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目录同级).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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())方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
2
3
4
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

posted @   橙木鱼  阅读(17313)  评论(4编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示