首页 / 历史 / 近代史 / 正文

javascript教程pdf(Spring Boot + iTextPdf:3步实现HTML模板生成pdf)

放大字体  缩小字体 来源:安徽工程技术学院 2026-04-17 17:25  浏览次数:10

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>    html, body {      font-family: "Microsoft YaHei", sans-serif;;    }    .wrapper {      width: 440px;      height: 1024px;    }    .bolded {      font-weight: bolder;    }    .content {      width: 45vh;      padding: 20px 40px;    }    .section {      border-bottom: 2px dashed black;      padding: 20px 0px;    }    .section-item {      margin-bottom: 20px;      overflow-wrap: break-word;    }    .section-item:last-child {      margin-bottom: 0px;    }    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如下:

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

打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心