当前位置: 首页 > news >正文

别再手动填表了!用Java和iTextPDF 5.5.1自动生成带中文的结算单PDF(附完整源码)

电商订单结算单自动化:基于Java与iTextPDF的PDF动态生成实战

财务人员每天重复填写数十份结算单的时代该终结了。在电商订单量激增的背景下,我们为Java工程师准备了一套开箱即用的PDF动态生成方案。不同于网上零散的代码片段,本文将系统解决中文字体渲染、动态表格构建、数据绑定等核心痛点,并提供可直接集成到Spring Boot项目的模块化代码。

1. 环境准备与依赖配置

工欲善其事,必先利其器。我们选择iTextPDF 5.5.1版本作为核心库,这是经过大量生产验证的稳定版本。新建Maven项目时,需在pom.xml中添加以下关键依赖:

<dependencies> <!-- 核心PDF生成库 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.1</version> </dependency> <!-- 亚洲字体支持 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <!-- 可选JSON处理 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> </dependencies>

注意:实际项目中建议使用dependencyManagement统一管理版本号

开发环境建议配置:

  • JDK 8+(推荐JDK 11 LTS版本)
  • IntelliJ IDEA或Eclipse最新稳定版
  • 测试用中文模板文件(用于验证字体显示)

2. 中文字体解决方案深度剖析

中文乱码是PDF生成的经典难题。我们采用STSong-Light字体配合UniGB-UCS2-H编码方案,这是目前最稳定的中文显示方案之一。核心字体初始化代码如下:

// 创建中文字体基础对象 BaseFont chineseFont = BaseFont.createFont( "STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED ); // 派生不同样式字体 Font titleFont = new Font(chineseFont, 18, Font.BOLD); Font contentFont = new Font(chineseFont, 12, Font.NORMAL); Font highlightFont = new Font(chineseFont, 12, Font.BOLD, BaseColor.RED);

常见字体问题排查表:

现象可能原因解决方案
方块字字体未正确加载检查itext-asian依赖和字体名称
部分字符缺失编码不匹配确认使用UniGB-UCS2-H编码
文件体积过大字体全嵌入设置BaseFont.NOT_EMBEDDED

生产环境建议:将字体文件放入resources/fonts目录,使用createFont加载物理文件而非系统字体

3. 动态表格生成引擎设计

电商结算单通常包含表头、商品明细和汇总三部分。我们设计了一个灵活的表格构建器:

public class DynamicTableBuilder { private PdfPTable table; private Font defaultFont; public DynamicTableBuilder(int columns, Font font) { this.table = new PdfPTable(columns); this.defaultFont = font; table.setWidthPercentage(100); } public void addHeaderRow(List<String> headers) { headers.forEach(header -> { PdfPCell cell = new PdfPCell(new Phrase(header, defaultFont)); cell.setBackgroundColor(new BaseColor(240, 240, 240)); table.addCell(cell); }); } public void addDataRow(List<Object> rowData) { rowData.forEach(data -> { String content = data != null ? data.toString() : ""; table.addCell(new Phrase(content, defaultFont)); }); } public void addToDocument(Document document) throws DocumentException { document.add(table); } }

典型电商订单表格结构示例:

  1. 表头区域

    • 订单编号
    • 创建时间
    • 客户信息
  2. 商品明细

    • SKU编码
    • 商品名称
    • 单价
    • 数量
    • 小计
  3. 汇总区域

    • 商品总数
    • 总金额
    • 优惠金额
    • 实付金额

4. Spring Boot集成实战

将PDF生成能力封装为微服务是更优雅的方案。创建PdfExportService核心类:

@Service public class PdfExportService { @Value("${pdf.export.path:/tmp/pdf}") private String exportPath; public File generateOrderStatement(OrderDTO order) { String filename = exportPath + "/order_" + order.getId() + ".pdf"; try { Document document = new Document(PageSize.A4, 50, 50, 30, 30); PdfWriter.getInstance(document, new FileOutputStream(filename)); document.open(); addTitle(document, "订单结算单"); addOrderInfo(document, order); addItemsTable(document, order.getItems()); addSummary(document, order.getSummary()); document.close(); return new File(filename); } catch (Exception e) { throw new PdfGenerationException("PDF生成失败", e); } } private void addTitle(Document doc, String title) throws DocumentException { Font font = ChineseFontUtil.getTitleFont(); Paragraph p = new Paragraph(title, font); p.setAlignment(Element.ALIGN_CENTER); doc.add(p); doc.add(Chunk.NEWLINE); } // 其他私有方法省略... }

控制器层提供REST接口:

@RestController @RequestMapping("/api/pdf") public class PdfController { @Autowired private PdfExportService pdfService; @PostMapping("/order") public ResponseEntity<Resource> generateOrderPdf(@RequestBody OrderDTO order) throws IOException { File pdfFile = pdfService.generateOrderStatement(order); Path path = Paths.get(pdfFile.getAbsolutePath()); ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path)); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=order_" + order.getId() + ".pdf") .contentType(MediaType.APPLICATION_PDF) .contentLength(pdfFile.length()) .body(resource); } }

5. 高级优化技巧

性能优化方案:

  • 对象池复用Document和PdfWriter实例
  • 异步生成结合缓存机制
  • 批量操作时使用PdfCopy合并文档

样式增强技巧:

// 创建渐变背景色 PdfContentByte canvas = writer.getDirectContent(); canvas.setColorFill(new BaseColor(230, 230, 250)); canvas.rectangle(0, 0, PageSize.A4.getWidth(), 80); canvas.fill(); // 添加水印 PdfGState gs = new PdfGState(); gs.setFillOpacity(0.3f); canvas.setGState(gs); canvas.beginText(); canvas.setFontAndSize(bfChinese, 48); canvas.showTextAligned(Element.ALIGN_CENTER, "CONFIDENTIAL", 300, 400, 45); canvas.endText();

异常处理建议:

  • 对IO操作添加重试机制
  • 大文件生成时添加超时控制
  • 使用临时文件+原子移动保证操作原子性

6. 完整项目结构参考

标准化的项目布局能提升团队协作效率:

src/main/java └── com └── example └── pdf ├── config │ └── PdfConfig.java ├── controller │ └── PdfController.java ├── service │ ├── PdfExportService.java │ └── impl │ └── PdfExportServiceImpl.java ├── util │ ├── ChineseFontUtil.java │ └── DynamicTableBuilder.java └── exception └── PdfGenerationException.java src/main/resources ├── fonts │ └── simsun.ttc └── templates └── invoice_template.pdf

在电商项目实际落地时,我们发现将结算单生成时机放在"订单已完成"事件触发时最合理,配合消息队列实现异步生成,系统吞吐量提升了3倍。对于高并发场景,建议采用PDF预生成策略,将结算单模板与动态数据分离处理。

http://www.rkmt.cn/news/1507069.html

相关文章:

  • 3分钟搞定微信QQ消息防撤回:免费开源补丁终极指南
  • 致远CAP4表单进阶玩法:不写Groovy脚本,如何优雅引用外部数据库实现‘类业务关系’效果?
  • GitHub Desktop中文汉化终极指南:3分钟解锁全中文Git操作体验
  • 1.2 | 中大型团队升级:世动云智慧管理系统与企千虾AI智能体深度评测
  • 英文文本阅读难度速算工具:按SMOG公式自动换算对应美国年级水平
  • ACE-D5.3 Snoop transactions
  • 同调代数与无环模型定理:原理与应用解析
  • YOLOv5/v8训练时,到底该选哪个IoU损失函数?从IoU到CIoU的保姆级选择指南
  • AG Grid Vue单元格合并踩坑实录:suppressRowTransform=true到底该不该开?
  • VTK 9.2.0 在 Windows 10 上编译全记录:从 CMake 配置到 VS2019 项目生成(附 Qt 环境变量避坑点)
  • 从仿真到真机:手把手教你用MoveIt控制真实机械臂(以ROS Melodic + Dynamixel舵机为例)
  • 3分钟搭建Windows C/C++开发环境:w64devkit终极指南
  • FixMatch里的‘强增强’与‘弱增强’到底怎么选?一份基于CIFAR-10/SVHN的RandAugment调优指南
  • 避坑指南:AWS DeepRacer奖励函数调参实战——从60%到100%完赛率的航点与速度线配置
  • GESP C++一级2023.03–2024.12全部真题可运行AC代码(含测试样例与环境说明)
  • 从8位移位寄存器到进位选择加法器:在HDLBits里拆解Verilog层次化设计的进阶玩法
  • 【四旋翼】扰动补偿的四旋翼无人机自适应模型预测控制研究【含Matlab源码 15591期】
  • 告别手动切换:IAR编译后自动同时输出Bin和Hex文件的配置秘诀
  • Windows 64位一键运行版Eclipse 4.17 Java开发环境(含JDT、SWT及完整离线帮助)
  • asc-devkit(Ascend C算子编程开发语言工具链):CANN生态中的定位、多层API设计与完整算子开发实践
  • 免费PDF全能转换攻略:3款微信工具,Word/Excel/PPT/图片一键搞定 - 时时资讯
  • 云厂商竞速千行百业智能化蓝海:从比规模到比落地,谁能笑到最后?
  • 从用户态到AI Core硬件执行:一次昇腾NPU算子调用在CANN驱动层的完整穿越路径与硬件交互深度追踪
  • LangChain框架在高炉炼铁智能化领域的应用~系列文章01:当高炉遇上LangChain
  • 第04篇|Stage模型启动链路:EntryAbility到首页加载解析
  • Redis Stack 初探:为什么它是 AI 检索的“新基建”?
  • 深度实战:Python爬虫爬取古诗文网指定作者全部诗文——从编码陷阱到正则清洗的全流程解析
  • 深圳钣金外壳定制
  • 如何在5分钟内免费激活Unity全版本:UniHacker一站式解决方案
  • 实战复盘:我们如何用SageMaker Canvas将货物延迟预测准确率提升了30%