1. 程式人生 > >JAVA按模版匯出PDF檔案,含條碼,二維碼,表格

JAVA按模版匯出PDF檔案,含條碼,二維碼,表格

示例模版:


示例匯出:


核心程式碼:

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:不能上傳附件是不是不太科學,模版檔案沒地放。。。