大数跨境
0
0

Spring Boot + iTextPdf:3步实现HTML模板生成pdf

Spring Boot +  iTextPdf:3步实现HTML模板生成pdf Spring全家桶实战案例
2025-09-12
2
导读:Spring Boot + iTextPdf:3步实现HTML模板生成pdf
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!
图片

🎉🎉《Spring Boot实战案例合集》目前已更新170个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

在企业级应用中,PDF生成是常见的文档处理需求。无论是订单确认、发票开具、合同签署,还是报表导出,用户普遍期望获得格式规范、内容完整且可打印的PDF文件作为正式凭证或存档依据。相比HTML或Excel,PDF具有跨平台一致性、防篡改性强、布局固定等优势,尤其适用于金融、电商、政务等对文档合规性要求较高的场景。

本篇文章将通过通过itextpdf + html模板生成pdf文档(支持外部资源)。

2.实战案例

2.1 环境准备

<dependency>  <groupId>com.itextpdf</groupId>  <artifactId>kernel</artifactId>  <version>9.3.0</version></dependency><dependency>  <groupId>com.itextpdf</groupId>  <artifactId>html2pdf</artifactId>  <version>6.2.1</version></dependency><dependency>  <groupId>ognl</groupId>  <artifactId>ognl</artifactId>  <version>3.4.7</version></dependency><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

我们将通过thymeleaf模板技术生成PDF。thymeleaf支持各种强大的表达式,非常适合生成各种复杂的文档。

配置thymeleaf

spring:  thymeleaf:    mode: HTML    encoding: UTF-8    prefix: classpath:/templates/    suffix: .html    cache: false

2.2 准备数据 & 模板

public class Receipt {  // 收单机构信息  private String scope;  // 商户信息  private String merchantName;  private String merchantId;  private String terminalId;  private String merchantCity;  // 交易基本信息  private String stan; // 系统跟踪号  private String transactionDate; // 交易日期  private String transactionType; // 交易类型  private BigDecimal requestAmount; // 交易金额  // 交易详情  private String mcc; // 商户类别码  private String scheme; // 卡组织  private String maskedPan; // 掩码卡号  private String acquirer; // 收单机构BIN  // 系统信息  private String approvalNumber; // 授权号  private String processingCode; // 处理代码  private String responseCode; // 响应码  private String retrievalNumber; // 检索参考号  private String displayMessage; // 交易状态信息  // getters, setters}

模板定义

<!DOCTYPE html><html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"><head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>收据副本</title>  <link href="/google.css" rel='stylesheet' type='text/css' />  <style>    htmlbody {      font-family"Microsoft YaHei", sans-serif;;    }    .wrapper {      width440px;      height1024px;    }    .bolded {      font-weight: bolder;    }    .content {      width45vh;      padding20px 40px;    }    .section {      border-bottom2px dashed black;      padding20px 0px;    }    .section-item {      margin-bottom20px;      overflow-wrap: break-word;    }    .section-item:last-child {      margin-bottom0px;    }    small:last-child {      text-align: right;      float: right;    }  </style></head><body><div class="wrapper">  <div class="content">    <h1 style="text-align: center; border-bottom: 2px dashed black; padding-bottom: 20px;">** 收据副本 **<img src="/seo.png" width="32" height="32"/></h1>    <div class="section">      <div class="section-item">        <small>收单机构名称:</small>        <small style="word-wrap: anywhere" th:text="${receipt.scope}"></small>      </div>      <div class="section-item">        <small>商户名称:</small>        <small style="word-wrap: anywhere" th:text="${receipt.merchantName}"></small>      </div>      <div class="section-item">        <small>商户ID:</small>        <small th:text="${receipt.merchantId}"></small>      </div>      <div class="section-item">        <small>终端ID:</small>        <small th:text="${receipt.terminalId}"></small>      </div>      <div class="section-item">        <small>商户城市:</small>        <small th:text="${receipt.merchantCity}"></small>      </div>    </div>    <div class="section">      <div class="section-item">        <small>系统跟踪号(STAN):</small>        <small th:text="${receipt.stan}"></small>      </div>      <div class="section-item">        <small>交易日期:</small>        <small th:text="${receipt.transactionDate}"></small>      </div>    </div>    <div class="section">      <div class="section-item">        <small>交易类型:</small>        <small th:text="${receipt.transactionType}"></small>      </div>      <div class="section-item">        <small>交易金额:</small>        <small th:text="'NGN ' + ${receipt.requestAmount}"><b></b></small>      </div>    </div>    <div class="section">      <div class="section-item">        <small>商户类别码(MCC):</small>        <small th:text="${receipt.mcc}"></small>      </div>      <div class="section-item">        <small>卡组织:</small>        <small th:text="${receipt.scheme}"></small>      </div>      <div class="section-item">        <small>卡号:</small>        <small th:text="${receipt.maskedPan}"></small>      </div>      <div class="section-item">        <small>收单机构识别码(BIN)</small>        <small th:text="${receipt.acquirer}"></small>      </div>    </div>    <div class="section">      <div class="section-item">        <small>授权号:</small>        <small th:text="${receipt.approvalNumber}"></small>      </div>      <div class="section-item">        <small>处理代码:</small>        <small th:text="${receipt.processingCode}"></small>      </div>      <div class="section-item">        <small>响应码:</small>        <small th:text="${receipt.responseCode}"></small>      </div>      <div class="section-item">        <small>检索参考号(RRN):</small>        <small th:text="${receipt.retrievalNumber}"></small>      </div>      <div class="section-item">        <small>状态</small>        <small th:text="${receipt.displayMessage}"></small>      </div>    </div>    <h3 style="text-align: center; padding-bottom: 20px;">感谢您的光临!</h3>  </div></div></body></html>

在该模板中,我们使用了外部的css资源以及图片资源。

如下是我们需要准备的资源

2.3 Controller接口定义

@RestController@RequestMapping("/html2pdf")public class Html2PdfController {  private final ITemplateEngine templateEngine ;  public Html2PdfController(ITemplateEngine templateEngine) {    this.templateEngine = templateEngine;  }  @GetMapping("/download")  public ResponseEntity<byte[]> downloadEJournalFile( HttpServletRequest request,      HttpServletResponse response) throws Exception {    // 1.准备数据    Map<String, Object> variables = Map.of("receipt", getData()) ;    // 2.创建上下文并添加变量(模板需要的数据)    Context context = new Context();    context.setVariables(variables);    // 2.1.获取解析后的模板内容    String receiptTemplate = templateEngine.process("receipt", context);    // 3.配置模板中使用的基础资源信息    ConverterProperties converterProperties = new ConverterProperties();    // 如果你的模板中引用了样式,那么你需要设置    converterProperties.setBaseUri("http://localhost:8080") ;    // 3.1.设置字体    FontProvider fontProvider = new FontProvider();    // 加载系统所有字体(最简单方式)    fontProvider.addSystemFonts() ;    converterProperties.setFontProvider(fontProvider) ;    // 3.2.HTML到PDF转换    ByteArrayOutputStream target = new ByteArrayOutputStream();    HtmlConverter.convertToPdf(receiptTemplate, target, converterProperties);    // 4.设置下载信息    String fileName = URLEncoder.encode("收据明细.pdf""UTF-8");    HttpHeaders header = new HttpHeaders();    header.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);    header.add("Cache-Control""no-cache, no-store, must-revalidate") ;    header.add("Pragma""no-cache") ;    header.add("Expires""0") ;    return ResponseEntity.ok()        .headers(header)        .contentType(MediaType.APPLICATION_PDF)        .body(target.toByteArray()) ;  }  public Receipt getData() {    return ... ;  }}

该接口中已经详细的说明关键代码的作用。

2.4 测试

调用上面接口后,生成的pdf如下:

图片、样式都正确的加载。



以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

Spring Boot + JavaScript 实时数据流:2种完整实现

告别 JSON 烦恼!Spring Boot 中 12 个必知的 Jackson 强大注解

告别OOM!Spring Boot 流式导出百万数据:支持MyBatis/JPA/Jdbc

小心此Bug!Spring Boot 事务方法没有异常,为什么事务还是回滚了?

性能优化!Spring Boot + JPA 9 大逆天调优手段,让系统性能起飞

告别轮询!Spring Boot+Webhook 构建实时响应系统

优雅!Spring 基于 Plugin 插件开发(官方推荐)

万字长文!深入源码,彻底掌握Spring Cloud Gateway底层原理

惊呆了!Controller接口返回值支持17种逆天类型

太神了!Spring Boot官方推荐模板引擎Mustache,简直强到离谱!

再见 Feign!Spring Boot + JSON-RPC远程调用新选择

优雅!自定义注解轻松管理多版本Controller接口

图片
图片
图片
图片
图片
图片
图片
图片
图片

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读7
粉丝0
内容832