itext7 html轉pdf實現


公司最近做一個交易所項目,里面涉及一個需求就是將html模板,在填充數據后轉換為pdf,這樣防止數據更改,下面是具體實現

1 pom文件

     <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>font-asian</artifactId>
            <version>7.1.2</version>
        </dependency>             

2 html轉pdf

itext7進行html轉換使用類:com.itextpdf.html2pdf.HtmlConverter
  它主要有三類操作:convertToPdf直接轉換為pdf文件
           convertToDocument轉為document文檔,這樣有利於進行pdf頁面調整
           convertToElements拆解pdf標簽
我這里因為html轉換后會有多頁,這里通過convertToDocument調整頁面大小,在一頁上顯示所有內容;
同時我使用ByteArrayOutputStream類,這個的好處是不在本地生成文件,減少磁盤操作,但是這種方式也有人說效率不高,使用者可以斟酌后使用.
因為spring boot存在打包后resources目錄文件獲取不到的問題,所以我將pdf依賴的字體文件放到項目的根路徑下(跟src目錄同級).
package com.ssth.exchanage.excenter.common.uitls;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.draw.ILineDrawer;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.LineSeparator;

public class PDFUtil {
	private static final String FONT = "./pdf/font/NotoSansCJKsc-Regular.otf";

	/**
	 * @Description 將html轉換為pdf文件
	 * @param html html頁面字符串
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public ByteArrayOutputStream html2Pdf(String html) throws FileNotFoundException, IOException {
		ConverterProperties props = new ConverterProperties();
		DefaultFontProvider defaultFontProvider = new DefaultFontProvider(false, false, false);
		defaultFontProvider.addFont(font);
		props.setFontProvider(defaultFontProvider);
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		PdfWriter writer = new PdfWriter(bao);
		PdfDocument pdf = new PdfDocument(writer);
		pdf.setDefaultPageSize(new PageSize(595, 14400));
		Document document = HtmlConverter.convertToDocument(html, pdf, props);
		EndPosition endPosition = new EndPosition();
		LineSeparator separator = new LineSeparator(endPosition);
		document.add(separator);
		document.getRenderer().close();
		PdfPage page = pdf.getPage(1);
		float y = endPosition.getY() - 36;
		page.setMediaBox(new Rectangle(0, y, 595, 14400 - y));
		document.close();
		return bao;
	}

	/**
	 * 定義操作區域
	 */
	class EndPosition implements ILineDrawer {
		// y坐標
		protected float y;

		/**
		 * @Description: 獲取y坐標
		 * @return
		 */
		public float getY() {
			return y;
		}

		/**
		 * @Description: 操作畫布特定區域
		 * @param pdfCanvas:操作畫布
		 * @param rect:操作區域
		 */
		@Override
		public void draw(PdfCanvas pdfCanvas, Rectangle rect) {
			this.y = rect.getY();
		}

		/**
		 * @Description: 獲取行顏色
		 * @return
		 */
		@Override
		public Color getColor() {
			return null;
		}

		/**
		 * @Description: 獲取行寬
		 * @return
		 */
		@Override
		public float getLineWidth() {
			return 0;
		}

		/**
		 * @Description: 設置行顏色
		 * @param color
		 */
		@Override
		public void setColor(Color color) {
		}

		/**
		 * @Description: 設置行寬
		 * @param lineWidth:寬度
		 */
		@Override
		public void setLineWidth(float lineWidth) {
		}
	}
}

3 流響應

核心是通過ByteArrayOutputStream.writeTo(HttpServletResponse.getOutputStream())方法

package com.huishi;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import com.ssth.exchanage.excenter.common.exception.ResException;
import com.ssth.exchanage.excenter.common.uitls.DateUtil;
import com.ssth.exchanage.excenter.common.uitls.PDFUtil;
import com.ssth.exchanage.excenter.controller.response.RecordApplyParamRep;
import com.ssth.exchanage.excenter.service.ProductRecordService;

@Service
public class ProductRecordServiceImp implements ProductRecordService {

	/**
	 * @Description 打印備案申請書
	 * @param res http響應
	 */
	@Override
	public void printRecord(HttpServletResponse res){
		try {
		  String htmlStr = FileUtil.readFile(null);
		  PDFUtil pdfUtil = new PDFUtil();
		  ByteArrayOutputStream stream = pdfUtil.html2Pdf(htmlStr);
		  res.setHeader("Expires", "0"); 
		  res.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
	          res.setHeader("Pragma", "public");
		  res.setContentType("application/pdf");
		  OutputStream os = res.getOutputStream();
		  stream.writeTo(os);
	          os.flush();
	          os.close();
		} catch (IOException e) {
		  log.error("printRecord {}",e.getMessage());
		  throw new ResException("-1","服務內部錯誤,請稍后再試!");
		}
	}
}

備注:

itext7解決中文顯示問題有兩種解決方式:

1 引入對應的語言包,火狐瀏覽器預覽生成的pdf可能存在部分中文亂碼問題,同時因為加載了語言包,生成的pdf更大
使用NotoSansCJKsc-Regular.otf,同時在pom中引入com.itextpdf.font-asian包.
2 設置字體:通過默認字體生成,pdf文件和html大小幾乎相同,不存在瀏覽器預覽亂碼問題 
PdfFont font = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);

 

使用示例鏈接: https://github.com/liulei3/html2pdf 

參考文件:

html轉pdf: https://developers.itextpdf.com/content/itext-7-examples/itext-7-converting-html-pdf

流響應:https://developers.itextpdf.com/content/best-itext-questions-stackoverview/general-questions-about-itext/itext7-how-can-i-serve-pdf-browser-without-storing-file-server-side


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM