JAVA按模版导出PDF文件,含条码,二维码,表格

来源:互联网 发布:联通网络如何报修 编辑:程序博客网 时间:2024/06/08 00:38

示例模版:


示例导出:


核心代码:

package com.yonyou.dms.framework.service.pdf;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.OutputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.itextpdf.text.Element;import com.itextpdf.text.Font;import com.itextpdf.text.Image;import com.itextpdf.text.Phrase;import com.itextpdf.text.pdf.AcroFields;import com.itextpdf.text.pdf.AcroFields.FieldPosition;import com.itextpdf.text.pdf.Barcode39;import com.itextpdf.text.pdf.BarcodeQRCode;import com.itextpdf.text.pdf.BaseFont;import com.itextpdf.text.pdf.PdfContentByte;import com.itextpdf.text.pdf.PdfPCell;import com.itextpdf.text.pdf.PdfPTable;import com.itextpdf.text.pdf.PdfReader;import com.itextpdf.text.pdf.PdfStamper;import com.yonyou.dms.framework.service.pdf.domain.PDFTableDto;/** * @ClassName: PDFTemplateExport * @Description: TODO * @Author: xiongrx@vip.qq.com * @Date: 2017年8月26日 */public class PDFTemplateExport {private static final Logger logger = LoggerFactory.getLogger(PDFTemplateExport.class);private String templatePdfPath;private String fontName = "simsun.ttc,1";public PDFTemplateExport(String templatePdfPath) {this.templatePdfPath = templatePdfPath;}public PDFTemplateExport(String templatePdfPath, String fontName) {this.templatePdfPath = templatePdfPath;this.fontName = fontName;}/** * 根据模版导出PDF文档 * @param os 输出流 * @param textFields 文本字段 * @param barcodeFields 条码字段 * @param qrcodeFields 二维码字段 * @param tableFields 表格字段 * @throws Exception */public void export(OutputStream os, Map<String, Object> textFields, Map<String, Object> barcodeFields, Map<String, Object> qrcodeFields,Map<String, PDFTableDto> tableFields) throws Exception {//读取模版PdfReader reader = new PdfReader(templatePdfPath);ByteArrayOutputStream bos = new ByteArrayOutputStream();PdfStamper ps = new PdfStamper(reader, bos);//使用中文字体BaseFont bf = BaseFont.createFont(getFontPath(fontName), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();fontList.add(bf);AcroFields s = ps.getAcroFields();s.setSubstitutionFonts(fontList);//遍历表单字段for (Map.Entry<String, Object> entry : textFields.entrySet()) {String key = entry.getKey();Object value = entry.getValue();s.setFieldProperty(key, "textfont", bf, null);    s.setField(key, getBlank(value));}        //遍历条码字段for (Map.Entry<String, Object> entry : barcodeFields.entrySet()) {String key = entry.getKey();Object value = entry.getValue();// 获取属性的类型if(value != null && s.getField(key) != null){//获取位置(左上右下)FieldPosition fieldPosition = s.getFieldPositions(key).get(0);//绘制条码Barcode39 barcode39 = new Barcode39();//字号barcode39.setSize(12);//条码高度barcode39.setBarHeight(30);//条码与数字间距barcode39.setBaseline(10);//条码值barcode39.setCode(value.toString());barcode39.setStartStopText(false);barcode39.setExtended(true);//绘制在第一页PdfContentByte cb = ps.getOverContent(1);//生成条码图片Image image128 = barcode39.createImageWithBarcode(cb, null, null);//左边距(居中处理)float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;//条码位置image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, fieldPosition.position.getBottom());//加入条码cb.addImage(image128);}}//遍历二维码字段for (Map.Entry<String, Object> entry : qrcodeFields.entrySet()) {String key = entry.getKey();Object value = entry.getValue();// 获取属性的类型if(value != null && s.getField(key) != null){//获取位置(左上右下)FieldPosition fieldPosition = s.getFieldPositions(key).get(0);//绘制二维码float width = fieldPosition.position.getRight() - fieldPosition.position.getLeft();BarcodeQRCode pdf417 = new BarcodeQRCode(value.toString(), (int)width, (int)width, null);//生成二维码图像Image image128 = pdf417.getImage();//绘制在第一页PdfContentByte cb = ps.getOverContent(1);//左边距(居中处理)float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;//条码位置image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, fieldPosition.position.getBottom());//加入条码cb.addImage(image128);}}//遍历表格字段Font keyfont = new Font(bf, 8, Font.BOLD);// 设置字体大小 Font textfont = new Font(bf, 8, Font.NORMAL);// 设置字体大小 for (Map.Entry<String, PDFTableDto> entry : tableFields.entrySet()) {String key = entry.getKey();PDFTableDto tableDto = entry.getValue();// 获取属性的类型if(tableDto != null && tableDto.getColFields() != null && s.getField(key) != null){//获取位置(左上右下)FieldPosition fieldPosition = s.getFieldPositions(key).get(0);float width = fieldPosition.position.getRight() - fieldPosition.position.getLeft();//创建表格String[] thread = tableDto.getColNames() != null ? tableDto.getColNames().split(",") : tableDto.getColFields().split(",");PdfPTable table = new PdfPTable(thread.length);        try{             table.setTotalWidth(width);             table.setLockedWidth(true);             table.setHorizontalAlignment(Element.ALIGN_CENTER);                  table.getDefaultCell().setBorder(1);         }catch(Exception e){            e.printStackTrace();         }        //创建表头for (String col : thread) {table.addCell(createCell(col, keyfont, Element.ALIGN_CENTER));}//创建表体String[] fields = tableDto.getColFields().split(",");List<Map<String, Object>> dataList = tableDto.getDataList();if(dataList != null && dataList.size() > 0){for(int i=0;i<dataList.size();i++){Map<String, Object> row = dataList.get(i);for (String field : fields) {table.addCell(createCell(row.get(field), textfont));}}}        //插入文档        PdfContentByte cb = ps.getOverContent(1);        table.writeSelectedRows(0, -1, 0, -1, fieldPosition.position.getLeft(), fieldPosition.position.getTop(), cb);}}ps.setFormFlattening(true);ps.close();os.write(bos.toByteArray());os.flush();os.close();bos.close();reader.close();}/** * 创建单元格 * @param value 显示内容 * @param font 字体 * @param align 对齐方式 * @return */private static PdfPCell createCell(Object value, Font font, int align) {PdfPCell cell = new PdfPCell();cell.setVerticalAlignment(Element.ALIGN_MIDDLE);cell.setHorizontalAlignment(align);cell.setPhrase(new Phrase(getBlank(value), font));return cell;}/** * 创建单元格 * @param value 显示内容 * @param font 字体 * @return */private static PdfPCell createCell(Object value, Font font) {PdfPCell cell = new PdfPCell();cell.setVerticalAlignment(Element.ALIGN_MIDDLE);cell.setHorizontalAlignment(Element.ALIGN_LEFT);cell.setPhrase(new Phrase(getBlank(value), font));return cell;}/** * 非空处理 * @param value * @return */private static String getBlank(Object value) {if(value != null){return value.toString();}return "";}/** * 获取字体文件 * @param fontName * @return */private String getFontPath(String fontName) {String fontPath = "C:\\Windows\\Fonts\\" + fontName;// 判断系统类型,加载字体文件java.util.Properties prop = System.getProperties();String osName = prop.getProperty("os.name").toLowerCase();if (osName.indexOf("linux") > -1) {fontPath = "/usr/share/fonts/" + fontName;}return fontPath;}public static void main(String[] args) throws Exception {File outputFile = new File("C:\\Users\\XiongRx\\Desktop\\export.pdf");Map<String, Object> textFields = new HashMap<String, Object>();textFields.put("ifCode", "ZC-TXJ-01");textFields.put("ifName", "获取单台或多台车实时位置及油耗数据");textFields.put("ifSource", "天行健");textFields.put("ifFrequency", "实时");textFields.put("ifType", "WebService");textFields.put("ifDesc", "当整车系统需要获取某台或多台车的实时位置时,即可实时调用此接口获取所查询车辆的坐标数据、油耗数据等");Map<String, Object> barcodeFields = new HashMap<String, Object>();barcodeFields.put("ifLogic", "12312312312");Map<String, Object> qrcodeFields = new HashMap<String, Object>();qrcodeFields.put("qrCode", "http://blog.csdn.net/ruixue0117/article/details/77599808");PDFTableDto tableDto = new PDFTableDto();tableDto.setColNames("第1列,第2列,第3列,第4列,第5列");tableDto.setColFields("col1,col2,col3,col4,col5");List<Map<String, Object>> dataList = new ArrayList<Map<String,Object>>();for(int i=0;i<15;i++){Map<String, Object> row = new HashMap<String, Object>();for(int j=1;j<5;j++){row.put("col"+j, "col"+j);}dataList.add(row);}tableDto.setDataList(dataList);Map<String, PDFTableDto> tableFields = new HashMap<String, PDFTableDto>();tableFields.put("table", tableDto);outputFile.createNewFile();new PDFTemplateExport("C:\\Users\\XiongRx\\Desktop\\Simple1.pdf").export(new FileOutputStream(outputFile), textFields, barcodeFields, qrcodeFields, tableFields);}}

调用方法:

package com.yonyou.dms.framework.service.pdf.impl;import java.io.File;import java.io.OutputStream;import java.util.Map;import java.util.UUID;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.codec.binary.Base64;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.yonyou.dms.framework.service.pdf.PDFTemplateExport;import com.yonyou.dms.framework.service.pdf.PdfGenerator;import com.yonyou.dms.framework.service.pdf.domain.PDFGeneratorDto;import com.yonyou.dms.framework.service.pdf.domain.PDFTableDto;import com.yonyou.dms.function.exception.ServiceBizException;import com.yonyou.dms.function.exception.UtilException;import com.yonyou.dms.function.utils.common.CommonUtils;import com.yonyou.dms.function.utils.common.StringUtils;import com.yonyou.dms.function.utils.io.IOUtils;@Componentpublic class PdfGeneratorDefaultImpl implements PdfGenerator {// 定义日志接口private static final Logger logger = LoggerFactory.getLogger(PdfGeneratorDefaultImpl.class);/** * 生成Pdf文件到下载输出流 * @param generator * @param request * @param response */@Overridepublic void generatePdf(@SuppressWarnings("rawtypes") PDFGeneratorDto generator, HttpServletRequest request, HttpServletResponse response) {// 如果Data中没有数据,则返回错误if (generator == null || StringUtils.isNullOrEmpty(generator.getTempPath()) || CommonUtils.isNullOrEmpty(generator.getTextFields())) {throw new ServiceBizException("No Pdf Data !");}OutputStream outputStream = null;PDFTemplateExport pdfExport = null;try {// 初始化输出流String fileName = StringUtils.getString(generator.getFileName(), UUID.randomUUID());outputStream = initOutputStream(request, response, fileName, generator.isOnlineView());// 初始化模版String fontPath = StringUtils.getString(generator.getFontPath());String tempPath = StringUtils.getString(generator.getTempPath());String rootDir = request.getSession().getServletContext().getRealPath("/");tempPath = rootDir + "assets" + File.separator + "pdf" + File.separator + tempPath;if (StringUtils.isNullOrEmpty(fontPath)) {pdfExport = new PDFTemplateExport(tempPath);} else {pdfExport = new PDFTemplateExport(tempPath, fontPath);}// 写入数据Map<String, Object> textFields = generator.getTextFields();Map<String, Object> barcodeFields = generator.getBarcodeFields();Map<String, Object> qrcodeFields = generator.getQrcodeFields();Map<String, PDFTableDto> tableFields = generator.getTableFields();pdfExport.export(outputStream, textFields, barcodeFields, qrcodeFields, tableFields);} catch (Exception exception) {logger.warn(exception.getMessage(), exception);throw new ServiceBizException(exception.getMessage(), exception);} finally {IOUtils.closeStream(outputStream);}}/** * 初始化输出流 * @param request * @param response * @param fileName * @param isOnLine * @return * @throws UtilException */private OutputStream initOutputStream(HttpServletRequest request, HttpServletResponse response, String fileName, boolean isOnLine) throws UtilException {try {// 中文文件名兼容性调整String enableFileName = "";String agent = (String) request.getHeader("USER-AGENT");if (agent != null && agent.indexOf("like Gecko") != -1) {// IE11enableFileName = new String(fileName.getBytes("GBK"), "ISO-8859-1");}else if (agent != null && agent.indexOf("MSIE") == -1) {// FFenableFileName = "=?UTF-8?B?" + (new String(Base64.encodeBase64(fileName.getBytes("UTF-8")))) + "?=";} else { // IEenableFileName = new String(fileName.getBytes("GBK"), "ISO-8859-1");}// 输出文件流response.reset(); // 非常重要if (isOnLine) { // 在线打开方式response.setContentType("application/pdf");response.setHeader("Content-Disposition", "inline; filename=" + enableFileName);} else { // 纯下载方式response.setContentType("application/x-msdownload");response.setHeader("Content-Disposition", "attachment; filename=" + enableFileName);}return response.getOutputStream();} catch (Exception e) {throw new UtilException("pdf 流初始化失败", e);}}}
package com.yonyou.dms.framework.service.pdf.domain;import java.util.HashMap;import java.util.List;import java.util.Map;/** * PDF模版信息 * @author XiongRx * @date 2017年7月19日 */public class PDFGeneratorDto {    private String tempPath;    private String fontPath;    private Map<String, Object> textFields = new HashMap<String, Object>();    private Map<String, Object> barcodeFields = new HashMap<String, Object>();    private Map<String, Object> qrcodeFields = new HashMap<String, Object>();    private Map<String, PDFTableDto> tableFields = new HashMap<String, PDFTableDto>();        private String fileName;    private boolean onlineView = false;    public String getTempPath() {return tempPath;}public void setTempPath(String tempPath) {this.tempPath = tempPath;}public String getFontPath() {return fontPath;}public void setFontPath(String fontPath) {this.fontPath = fontPath;}public Map<String, Object> getTextFields() {return textFields;}public void setTextFields(Map<String, Object> textFields) {this.textFields = textFields;}public Map<String, Object> getBarcodeFields() {return barcodeFields;}public void setBarcodeFields(Map<String, Object> barcodeFields) {this.barcodeFields = barcodeFields;}public Map<String, Object> getQrcodeFields() {return qrcodeFields;}public void setQrcodeFields(Map<String, Object> qrcodeFields) {this.qrcodeFields = qrcodeFields;}public Map<String, PDFTableDto> getTableFields() {return tableFields;}public void setTableFields(Map<String, PDFTableDto> tableFields) {this.tableFields = tableFields;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}public boolean isOnlineView() {return onlineView;}public void setOnlineView(boolean onlineView) {this.onlineView = onlineView;}    }
package com.yonyou.dms.framework.service.pdf.domain;import java.util.List;import java.util.Map;/** * PDF表格信息 * @author XiongRx * @date 2017年7月19日 */public class PDFTableDto {    private String colNames;    private String colFields;    private List<Map<String, Object>> dataList;    public String getColNames() {return colNames;}public void setColNames(String colNames) {this.colNames = colNames;}public String getColFields() {return colFields;}public void setColFields(String colFields) {this.colFields = colFields;}public List<Map<String, Object>> getDataList() {return dataList;}public void setDataList(List<Map<String, Object>> dataList) {this.dataList = dataList;}        }

相关JAR包:

<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.10</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency>

还是写点备注吧:

这个代码重要的不是模版也不是条码(满大街都是),是在模版里设置条码和表格的位置。

实现按格式导出只需要核心代码就够了,写了个调用工具类是因为核心方法的参数较多,不方便调用,再者写了个实体类后续有新增需求也好维护,加新属性就好了,不会影响已有的调用。


http://rensanning.iteye.com/blog/1538689

附上很全的参考资料,并表示感谢。


PS:不能上传附件是不是不太科学,模版文件没地放。。。