JAVA按模版匯出PDF檔案,含條碼,二維碼,表格
阿新 • • 發佈:2019-01-04
示例模版:
示例匯出:
核心程式碼:
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:
[email protected] * @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; @Component public class PdfGeneratorDefaultImpl implements PdfGenerator { // 定義日誌介面 private static final Logger logger = LoggerFactory.getLogger(PdfGeneratorDefaultImpl.class); /** * 生成Pdf檔案到下載輸出流 * @param generator * @param request * @param response */ @Override public 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) {// IE11 enableFileName = new String(fileName.getBytes("GBK"), "ISO-8859-1"); }else if (agent != null && agent.indexOf("MSIE") == -1) {// FF enableFileName = "=?UTF-8?B?" + (new String(Base64.encodeBase64(fileName.getBytes("UTF-8")))) + "?="; } else { // IE enableFileName = 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:不能上傳附件是不是不太科學,模版檔案沒地放。。。