Java根据模版导出PDF文件

问题

工作中经常有这样的需求,将一些数据,导出为下图的PDF文件,那Java怎么做呢?今天手把手教你
在这里插入图片描述

准备模版

模版地址:https://download.csdn.net/download/ZHUSHANGLIN/91923381
修改模版使用AcrobatProPortable工具,在"编辑PDF"按钮修改模版样式,在“准备表单”按钮中修改模版中填充内容,需要工具的留言私发你
在这里插入图片描述
在这里插入图片描述

Java代码

首先添加依赖

 <!--PDF打印-->
<dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency><dependency><groupId>com.itextpdf.tool</groupId><artifactId>xmlworker</artifactId><version>5.5.13</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version><scope>compile</scope></dependency>
public R CreatePDF(Tbmmu301Entity tbmmu301Entity,List<Tbmmu301aEntity> list,String user){String separator  = File.separator;//Windows :“\” Linux : “/”FileSystemView fsv = FileSystemView.getFileSystemView();// 模板路径String templatePath = "PDF/MMU791.pdf";//第一次生成的新文件路径,文件名String newPDFPath = fsv.getDefaultDirectory().toString()+separator+tbmmu301Entity.getIssueNo()+"_temp.pdf";// 最终生成的新文件路径,文件名String finalPDFPath = fsv.getDefaultDirectory().toString()+separator+"Proof of going out_"+tbmmu301Entity.getIssueNo()+".pdf";logger.info("MMU791物资出门证明打印PDF路径",finalPDFPath);//com.itextpdf.text.pdfPdfReader reader;FileOutputStream out;ByteArrayOutputStream bos;PdfStamper stamper;R<String> result = new R<>();try{logger.info("开始", DateUtil.formatDateTime(new Date()));out = new FileOutputStream(newPDFPath);// 输出流reader = new PdfReader(templatePath);// 读取pdf模板bos = new ByteArrayOutputStream();stamper = new PdfStamper(reader, bos);AcroFields form = stamper.getAcroFields();Map<String, String> PDFData = new HashMap<>();//存放需要填充的模板数据String isBack = "";String issueType = iDictValue.getDictValue("leaveDoorType",tbmmu301Entity.getIssueType());if(tbmmu301Entity.getIsBack().equals("Y")){isBack = "是";}else if(tbmmu301Entity.getIsBack().equals("N")){isBack = "否";}Map tbmmi001Map=iDictValue.getTbmma001ByCodeAndKey("compid_sort",tbmmu301Entity.getCompanyId());//VALUE_B存公司简称if(Func.isEmpty(tbmmi001Map)){return R.fail("打印失败,获取TBMMA001表-compid_sort当前公司信息失败");}String compShort=tbmmi001Map.get("VALUE_B")==null?"":tbmmi001Map.get("VALUE_B").toString();if(compShort.equals("")){return R.fail("打印失败,获取当前公司:"+tbmmu301Entity.getCompanyId()+"简称失败,请联系系统管理员至采购业务字典compid_sort,设定当前公司参数2");}String approveNode = "";approveNode=iGetApproveNodeClient.getApproveNode(tbmmu301Entity.getIssueNo());//45751 获取OA审批流程打印PDFData.put("companyName",compShort+"出门证明");PDFData.put("issueNo",tbmmu301Entity.getIssueNo());//申请单号PDFData.put("issueType",issueType);//出门类型PDFData.put("issueUser",tbmmu301Entity.getIssueUserId());//申请人PDFData.put("issueDept",tbmmu301Entity.getIssueDeptName());//申请部门PDFData.put("driverName",tbmmu301Entity.getDriverName());//司机姓名PDFData.put("issueTel",tbmmu301Entity.getIssueTel());//司机电话PDFData.put("carNo",tbmmu301Entity.getCarNo());//车牌PDFData.put("isBack",isBack);//是否返厂PDFData.put("memo",tbmmu301Entity.getMemo());//备注PDFData.put("approveNode",approveNode);//审批流程logger.info("PDFData",PDFData.toString());// 设置字体,不设置很可能,中文无法显示。//BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);// 检查文件是否存在String fontPath = "/fonts/simsunb.ttf";InputStream fontStream = getClass().getResourceAsStream(fontPath);if (fontStream == null) {throw new RuntimeException("字体文件未找到: " + fontPath);}ByteArrayOutputStream buffer = new ByteArrayOutputStream();byte[] data = new byte[1024];int nRead;while ((nRead = fontStream.read(data, 0, data.length)) != -1) {buffer.write(data, 0, nRead);}byte[] fontBytes = buffer.toByteArray();BaseFont bf = BaseFont.createFont("simsunb.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, false, fontBytes, null);form.addSubstitutionFont(bf);// 数据查询后,值的植入 强烈推荐键值方式,其他方式很容易混Set<String> keySet = PDFData.keySet();for (String key : keySet) {//填充固定表单值form.setField(key, PDFData.get(key)==null?" ":PDFData.get(key));}logger.info("模板填充完成",DateUtil.formatDateTime(new Date()));stamper.setFormFlattening(true);// 如果为false那么生成的PDF文件还能编辑,一定要设为truestamper.close();Document doc = new Document();PdfCopy copy = new PdfCopy(doc, out);doc.open();PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);copy.addPage(importPage);doc.close();//第一次生成的pdf,生成模板数据logger.info("模板PDF生成完成",DateUtil.formatDateTime(new Date()));// 填充子档数据generateFinalPdf(newPDFPath, finalPDFPath, list ,user);logger.info("上传开始",DateUtil.formatDateTime(new Date()));File pdfFile = new File(finalPDFPath);MultipartFile MultipartFile = getMultipartFile(pdfFile);Map<String,String> result1 = obsUtil.saveFile(MultipartFile.getOriginalFilename(),MultipartFile);if("200".equals(result1.get("code"))){String key = result1.get("key");;String fileName = "";fileName = MultipartFile.getOriginalFilename();System.err.println(fileName);if (fileName.contains("\\")) {//去掉反斜杠fileName = fileName.split("\\\\")[1];}String url = obsUtil.generatePresignedUrl(key);logger.info("PDF文件key",key);logger.info("修改后PDF文件name",fileName);result.setSuccess(true);result.setData(url);if (pdfFile.exists()) {boolean isDelete2 = pdfFile.delete();logger.info("第二个PDF是否删除:", String.valueOf(isDelete2));}logger.info("出门证明打印:",result.toString());}copy.close();reader.close();bos.close();}catch (Exception e){e.printStackTrace();logger.info("MMU791物资出门证明打印PDF异常",e.getMessage());}finally {//删除本地文件File pdfFile1 = new File(newPDFPath);if (pdfFile1.exists()) {boolean isDelete1 = pdfFile1.delete();logger.info("第一个PDF是否删除:", String.valueOf(isDelete1));}}return result;}private void generateFinalPdf(String newPath, String finalPath, List<Tbmmu301aEntity> list, String user) throws Exception{FileOutputStream outputStream = new FileOutputStream(finalPath);PdfReader reader = new PdfReader(newPath);// 读取pdf模板Rectangle pageSize = reader.getPageSize(1);Document document = new Document(pageSize);PdfWriter writer = PdfWriter.getInstance(document, outputStream);document.open();PdfContentByte cbUnder = writer.getDirectContentUnder();PdfImportedPage pageTemplate = writer.getImportedPage(reader, 1);cbUnder.addTemplate(pageTemplate, 1, 1); //第一次生成的PDF填充到第二次生成的 位置//document.newPage();//新创建一页来存放后面生成的表格//package com.itextpdf.text;Paragraph paragraph2 = new Paragraph(new Phrase(" ")); //创建一个空的段,用于调整第二个段的位置Paragraph paragraph = generatePdfATATable(list,user);//此处为生成的表格及内容方法paragraph.setSpacingBefore(115);//不同模板设置不同距离//paragraph.setKeepTogether(false);//表示该段落必须放在一个页面上//新建一行//document.add(Chunk.NEWLINE);document.add(paragraph2);//增加块到文档document.add(paragraph);//增加块到文档// document.setPageSize(new Rectangle(100, 100));document.close();reader.close();writer.close();}public Paragraph generatePdfATATable(List<Tbmmu301aEntity> list,String user) throws Exception{//BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);// 检查文件是否存在String fontPath = "/fonts/simsunb.ttf";InputStream fontStream = getClass().getResourceAsStream(fontPath);if (fontStream == null) {throw new RuntimeException("字体文件未找到: " + fontPath);}ByteArrayOutputStream buffer = new ByteArrayOutputStream();byte[] data = new byte[1024];int nRead;while ((nRead = fontStream.read(data, 0, data.length)) != -1) {buffer.write(data, 0, nRead);}byte[] fontBytes = buffer.toByteArray();BaseFont bfChinese = BaseFont.createFont("/fonts/STSong-Light.ttf",BaseFont.IDENTITY_H , BaseFont.NOT_EMBEDDED);Font fontChinese = new Font(bfChinese, 15F, Font.NORMAL);// 设置PDF字体 五号//Paragraph ret = new Paragraph("附表1: 基线按ATA章节分类情况统计表", fontChinese); //表titleParagraph ret = new Paragraph("",fontChinese); //表titlePdfPTable tableBox = new PdfPTable(11); //列数tableBox.setWidths(new int[] {10,17,17,17,17,17,17,17,17,17,17   //每个单元格占多宽});tableBox.setWidthPercentage(105f); //占PDF整个宽度的百分比tableBox.setPaddingTop(500);tableBox.setSplitRows(false);//tableBox.addCell(getTableCell(new Phrase("标题", fontChinese), false, 3, 1));//colspan:跨横着的格数 rowspan:跨竖着的格数tableBox.addCell(getTableCell(new Phrase("Serial Number", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Types", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Supplier Code", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Supplier Name", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Material Code", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Material Name", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Model", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Procurement Unit", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Stock Unit", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Ex-factory quantity", fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase("Date of Departure", fontChinese), false, 1, 1));String tbmmu301Id="";for(int i=0;i<list.size();i++){Tbmmu301aEntity s = list.get(i);tableBox.addCell(getTableCell(new Phrase(String.valueOf(i+1), fontChinese), false, 1, 1));String inventoryType = "";if(Func.isNotEmpty(s.getInventoryType())){inventoryType = iDictValue.getDictValue("ItemGrade",s.getInventoryType());}tableBox.addCell(getTableCell(new Phrase(inventoryType, fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getSupplierId(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getSupplierName(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getItemId(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getItemName(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getTypeSpec(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getItemUnit(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getInvUnit(), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(ZoaCommonUtil.parseNumber(s.getPlanQty(),ZoaCommonUtil.Decimal.THREE), fontChinese), false, 1, 1));tableBox.addCell(getTableCell(new Phrase(s.getBroutDate(), fontChinese), false, 1, 1));tbmmu301Id=s.getTbmmu301Id()==null?"":s.getTbmmu301Id();}Tbmmu301Entity tbmmu301Entity=baseMapper.selectOne(new QueryWrapper<Tbmmu301Entity>().lambda().eq(Tbmmu301Entity::getTbmmu301Id,tbmmu301Id).eq(Tbmmu301Entity::getIsDeleted,0));//tableBox.addCell(getTableCell(new Phrase("testtest", fontChinese), false, 1, 1));tableBox.addCell(getCell(new Phrase("Printed by:", fontChinese), true, 2, 1));tableBox.addCell(getCell(new Phrase(user, fontChinese), false, 3, 1));tableBox.addCell(getCell(new Phrase(iPrintNumFeign.printNum(tbmmu301Entity.getCompanyId(),tbmmu301Entity.getIssueNo(),"MMU791"), fontChinese), false, 2, 1));tableBox.addCell(getCell(new Phrase("Printing time:", fontChinese), true, 2, 1));tableBox.addCell(getCell(new Phrase(DateUtil.formatDateTime(new Date()), fontChinese), false, 3, 1));ret.add(tableBox);ret.setLeading(90f);// 主档和子档的上下距离//ret.setPaddingTop(1000);return ret;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96444.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96444.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣hot100:环形链表(快慢指针法)(141)

一、题目描述二、思路分析这是链表题目中的经典问题&#xff0c;核心就是 如何判断链表是否有环。 常见的两种方法有&#xff1a;哈希表法&#xff1a;用一个集合存储访问过的节点&#xff0c;如果再次遇到相同节点说明有环。缺点&#xff1a;需要额外的空间&#xff0c;空间复…

AI 智能编码工具:重塑开发效率的革命,从 GitHub Copilot 到国产新秀的全面解析

目录 引言 一、主流智能编码工具深度测评&#xff1a;从功能到实战 1. GitHub Copilot&#xff1a;AI 编码的 “开山鼻祖” 核心特性与实战代码 优缺点总结 2. Baidu Comate&#xff1a;文心大模型加持的 “国产之光” 核心特性与实战代码 优缺点总结 3. 通义灵码&…

Server 13 ,CentOS 上使用 Nginx 部署多个前端项目完整指南( 支持多端口与脚本自动化 )

目录 前言 一、实际背景 1.1 并行部署 1.2 接口代理 1.3 刷新问题 二、安装脚本 2.1 创建脚本 2.2 不同系统 2.3 执行完成 三、配置文件 3.1 配置文件 3.2 目录结构 3.3 重新启动 四、验证访问 五、问题排查 5.1 访问 404 5.2 接口 502 六、本文总结 6.1 清理…

2025最新:彻底解决Docker拉取镜像超时问题

文章目录&#x1f433; 解决 Docker 拉取镜像超时&#xff1a;context deadline exceeded 完整指南&#xff08;2025 亲测有效&#xff09;&#x1f525; 问题描述&#x1f9e9; 根本原因分析✅ 解决方案汇总✅ 方案 1&#xff1a;配置多源镜像加速器&#xff08;推荐&#xff…

小鹏汽车 vla 算法最新进展和模型结构细节

小鹏汽车在 VLA&#xff08;视觉 - 语言 - 动作&#xff09;算法领域的最新进展和模型结构细节&#xff0c;体现了其在端到端智驾系统和车端大模型部署上的技术突破。以下是基于 2025 年 9 月最新公开信息的深度解析&#xff1a; 一、最新进展&#xff1a;全场景 VLA 系统量产落…

斐波那契数列推广

目录 问题&#xff1a; 法一&#xff1a; 法二&#xff1a; 例题: 问题&#xff1a; 已知斐波那契数列的第一个和最后一个数字&#xff0c;如何求整个数列&#xff08;即第二个数字&#xff09; 法一&#xff1a; 主要是将数列拆分成两个数列的思想 法二&#xff1a; 暴力…

基于STM32设计的智慧路灯(华为云IOT)_281

文章目录 一、前言 1.1 项目介绍 【1】项目开发背景 【2】设计实现的功能 【3】项目硬件模块组成 【4】设计意义 【5】国内外研究现状 【6】摘要 1.2 设计思路 1.3 系统功能总结 1.4 开发工具的选择 【1】设备端开发 【2】上位机开发 1.5 参考文献 1.6 系统框架图 1.7 系统原理…

实验十 合理定义分布列实现性能优化-分布式表关联

实验介绍本实验通过分析普通查询过程中存在的性能瓶颈点&#xff0c;通过执行计划的分析找到可能的性能优化点并加以实施&#xff0c;最终达到优化的效果&#xff0c;重点关注分布式关联相关查询语句的优化。实验目的了解通过合理定义分布列实现分布式关联的性能优化。实验步骤…

C#,RabbitMQ从入门到精通,.NET8.0(路由/分布式/主题/消费重复问题 /延迟队列和死信队列/消息持久化 )/RabbitMQ集群模式

为什么使用消息队列 消息队列&#xff08;MQ&#xff09;在分布式系统中用于解耦生产者和消费者&#xff0c;提高系统的异步处理能力、削峰填谷、增强可扩展性和可靠性。通过消息队列&#xff0c;任务可以异步执行&#xff0c;避免系统因瞬时高并发而崩溃。 消息队列场景 异…

OpenHarmony之SELinux安全组件底层原理设计架构精讲

1. 组件介绍 1.1 核心功能 **SELinux(安全增强式Linux)**是Linux历史上杰出的安全组件,包含一组内核修改和用户空间工具,并提供了基于安全策略的强制访问控制机制(Mandatory Access Control,MAC)。本部件负责对文件、属性、服务等系统资源提供强制访问控制保护,提供n…

IIS 部署 asp.net core 项目时,出现500.19、500.31问题的解决方案

目录 &#xff08;一&#xff09;500.19 问题 1. 问题说明 2. 原因 3. 解决 &#xff08;二&#xff09;500.31 问题 1. 问题说明 2. 原因 打开事件检视器的3种方式&#xff1a; 3. 解决 &#xff08;一&#xff09;500.19 问题 1. 问题说明 2. 原因 Web项目发布时&am…

中大型水闸安全监测的重要性及实施方法

水闸作为水利工程体系中的关键性构筑物&#xff0c;其结构安全性和运行可靠性直接影响到整个水利系统的稳定运行&#xff0c;更与下游地区人民群众的生命财产安全息息相关。作为水利枢纽工程的重要控制节点&#xff0c;水闸承担着防洪排涝、灌溉供水、航运发电等多重功能&#…

【芯片设计-信号完整性 SI 学习 1.1.1 -- Unit Interval,比特周期】

文章目录1. Unit Interval (UI) / 比特周期 的定义2. 举例说明3. 在眼图 (Eye Diagram) 中的体现4. 示意图(a) 单比特周期(b) 不同速率下的 UI(c) 眼图中的 UI5. 总结1. Unit Interval (UI) / 比特周期 的定义 在高速信号传输与 信号完整性 (SI) 测试中&#xff0c;Unit Inter…

Go语言开发工具全解析

Go 语言的开发工具生态对于提高开发效率、保证代码质量和团队协作至关重要。一套完善的工具链可以帮助开发者&#xff1a;1. 加速编码过程代码模板快速生成常见模式例如使用代码片段(Snippet)快速生成HTTP服务框架自动生成测试用例模板实时语法检查减少错误即时显示类型不匹配错…

[邮件服务器core] 安全通信(SSL/TLS) | OpenSSL库管理 | 服务端安全SECURITY.md

第5章&#xff1a;安全通信&#xff08;SSL/TLS&#xff09; 欢迎回来 在第4章&#xff1a;服务运行中&#xff0c;我们学习了如何启动Dovecot邮件服务器并使其运行。 现在&#xff0c;我们的服务器已经启动并准备好处理电子邮件&#xff0c;但有一个关键问题&#xff1a;我…

Lodash方法总结

目录 1. _.defaults()为对象填充默认值 基本语法 功能说明 示例代码 注意事项 与其他类似方法的区别 2. _.pickBy()删除对象中值为空串或 null 的属性 实现方法 代码说明 扩展&#xff1a;深层过滤 3._.omitBy()移除满足条件的属性 基本语法 核心功能 示例代码 1…

C#---Expression(表达式)

前言&#xff1a;Expression 是C# 高级编程&#xff0c;表达式的应用场景有 ORM框架&#xff1a;Entity Framework&#xff0c;Dapper等&#xff0c;规则引擎&#xff1a;动态业务规则评估&#xff0c; 依赖注入&#xff1a;高级DI容器实现&#xff0c;测试框架&#xff1a;模拟…

Lodash-es 完整开发指南:ES模块化JavaScript工具库实战教程

简介 Lodash-es 是 Lodash 库的 ES 模块版本&#xff0c;提供了大量实用的 JavaScript 工具函数。它支持按需导入&#xff0c;可以显著减少打包体积&#xff0c;是现代 JavaScript 项目中的首选工具库。 主要特性 ES 模块支持: 完全支持 ES6 模块语法按需导入: 只导入需要的…

26. AI-Agent-Dify

文章目录前言一、Dify入门为什么使用 Dify&#xff1f;Dify 能做什么&#xff1f;二、Dify私有化部署Docker Compose 部署前提条件克隆 Dify 代码启动 Dify更新 Dify访问 Dify自定义配置三、Dify构建企业级Agent应用定义如何使用智能助手添加助手需要的工具配置 Agent配置对话开…

云原生:微服务与Serverless指南

Copilot时代的开发者效能提升 代码生成与补全&#xff1a;减少重复性编码工作&#xff0c;加快开发速度错误检测与修复&#xff1a;实时提示潜在问题&#xff0c;降低调试时间知识获取与学习&#xff1a;帮助开发者快速掌握新语言或框架协作效率&#xff1a;通过AI辅助减少团队…