SpringBoot Thymeleaf iText7 生成 PDF(2023/08/29)
1. 前言
近期在項目種遇到了實時生成復雜 PDF 的需求,經過一番調研和測試,最終選擇了采用 Thymeleaf 和 iText7 來實現需求,本文將詳細介紹實現過程。
2. 技術思路
- 通過 Thymeleaf 渲染生成需要的頁面內容;
- 通過 iText7 html2pdf 庫將 Thymeleaf 渲染的結果轉換成 PDF;
- 將 PDF 內容寫入到接口輸出流中返回給前端瀏覽器展示;
3. 實現過程
-
Maven 引入依賴;
<!-- Thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- iText html2pdf --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>html2pdf</artifactId> <version>5.0.0</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- 獲取資源文件 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.21</version> </dependency>
-
編寫 Thymeleaf 模板
resources/templates/demo.html
;<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>PDF Demo</title> <style> body { padding-top: 50px; padding-left: 60px; padding-right: 60px; font-family: 'KaiTi', serif; } .title { color: red; text-align: center; margin-bottom: 50px; } table { width: 100%; border: 1px solid black; border-spacing: 0; } th { border: 1px solid black; background-color: rgb(128, 128, 128); } td { border: 1px solid black; } </style> </head> <body> <h1 class="title" th:text="${title}"></h1> <table> <thead> <tr> <th>序號</th> <th>姓名</th> <th>年齡</th> <th>性別</th> </tr> </thead> <tbody th:each="student, studentStat : ${students}"> <tr> <td th:text="${studentStat.count}"></td> <td th:text="${student.name}"></td> <td th:text="${student.age}"></td> <td th:text="${student.sex}"></td> </tr> </tbody> </table> </body> </html>
-
添加中文字體資源
resources/fonts/simkai.ttf
; -
編寫 PDF 頁碼事件處理
handler/PageEventHandler
;package com.xiaoqqya.itextpdf.handler; import com.itextpdf.kernel.events.Event; import com.itextpdf.kernel.events.IEventHandler; import com.itextpdf.kernel.events.PdfDocumentEvent; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfPage; import com.itextpdf.kernel.pdf.canvas.PdfCanvas; import com.itextpdf.layout.Canvas; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.properties.TextAlignment; /** * 頁碼事件處理. * * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> * @since 2023/08/29 */ public class PageEventHandler implements IEventHandler { @Override public void handleEvent(Event event) { PdfDocumentEvent documentEvent = (PdfDocumentEvent) event; PdfDocument document = documentEvent.getDocument(); PdfPage page = documentEvent.getPage(); Rectangle pageSize = page.getPageSize(); PdfCanvas pdfCanvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), document); Canvas canvas = new Canvas(pdfCanvas, pageSize); float x = (pageSize.getLeft() + pageSize.getRight()) / 2; float y = pageSize.getBottom() + 15; Paragraph paragraph = new Paragraph("-- " + document.getPageNumber(page) + " --") .setFontSize(10); canvas.showTextAligned(paragraph, x, y, TextAlignment.CENTER); canvas.close(); } }
-
編寫 Student 實體類
model/domain/Student
;package com.xiaoqqya.itextpdf.model.domain; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * 學生. * * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> * @since 2023/08/29 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Student { /** * 姓名 */ private String name; /** * 、 * 年齡 */ private Integer age; /** * 性別 */ private String sex; }
-
編寫 Service
service/PdfService
生成 PDF;package com.xiaoqqya.itextpdf.service.impl; import cn.hutool.core.io.resource.ResourceUtil; import com.itextpdf.html2pdf.ConverterProperties; import com.itextpdf.html2pdf.HtmlConverter; import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider; import com.itextpdf.io.font.FontProgramFactory; import com.itextpdf.kernel.events.PdfDocumentEvent; import com.itextpdf.kernel.geom.PageSize; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.layout.font.FontProvider; import com.xiaoqqya.itextpdf.exception.CustomException; import com.xiaoqqya.itextpdf.handler.PageEventHandler; import com.xiaoqqya.itextpdf.model.domain.Student; import com.xiaoqqya.itextpdf.service.PdfService; import org.springframework.stereotype.Service; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; import javax.annotation.Resource; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; /** * PDF Service. * * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> * @since 2023/08/29 */ @Service public class PdfServiceImpl implements PdfService { @Resource private TemplateEngine templateEngine; /** * 生成 PDF. * * @param outputStream 輸出流 */ @Override public void generatePdf(OutputStream outputStream) { // 模擬數據 List<Student> students = new ArrayList<>(); students.add(Student.builder().name("小紅").age(18).sex("女").build()); students.add(Student.builder().name("小強").age(21).sex("男").build()); students.add(Student.builder().name("熊大").age(19).sex("男").build()); // 生成 Thymeleaf 上下文 Context context = new Context(); context.setVariable("title", "PDF Demo"); context.setVariable("students", students); String demo = templateEngine.process("demo", context); // 生成 PDF, 并添加頁碼 try (PdfWriter pdfWriter = new PdfWriter(outputStream); PdfDocument pdfDocument = new PdfDocument(pdfWriter)) { pdfDocument.setDefaultPageSize(PageSize.A4); pdfDocument.addEventHandler(PdfDocumentEvent.INSERT_PAGE, new PageEventHandler()); ConverterProperties converterProperties = new ConverterProperties(); FontProvider fontProvider = new DefaultFontProvider(true, true, false); fontProvider.addFont(FontProgramFactory.createFont(ResourceUtil.readBytes("fonts/simkai.ttf"))); converterProperties.setFontProvider(fontProvider); HtmlConverter.convertToPdf(demo, pdfDocument, converterProperties); } catch (IOException e) { throw new CustomException(e.getMessage()); } } }
-
編寫 Controller
controller/PdfController
返回給前端瀏覽器展示;package com.xiaoqqya.itextpdf.controller; import com.xiaoqqya.itextpdf.service.PdfService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * PDF Controller. * * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> * @since 2023/08/29 */ @RestController @RequestMapping(value = "/pdf") public class PdfController { @Resource private PdfService pdfService; /** * 生成 PDF. */ @GetMapping public void generatePdf(HttpServletResponse response) throws IOException { pdfService.generatePdf(response.getOutputStream()); } }
4. 測試
瀏覽器訪問 http://localhost:8080/pdf
查看效果。文章來源:http://www.zghlxwxcb.cn/news/detail-688510.html
參考文章:文章來源地址http://www.zghlxwxcb.cn/news/detail-688510.html
- 使用itext7將HTML轉為pdf · Issue #12 · ydq/blog (github.com);
到了這里,關于SpringBoot Thymeleaf iText7 生成 PDF(2023/08/29)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!