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

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://g28W1HEB.nkkpp.cn
http://DEFfAU2X.nkkpp.cn
http://rFtZlAqp.nkkpp.cn
http://t91dto9M.nkkpp.cn
http://nkt7b9eC.nkkpp.cn
http://G93YkylC.nkkpp.cn
http://bvB6zh0t.nkkpp.cn
http://vpKziPvy.nkkpp.cn
http://iOdbM3Ni.nkkpp.cn
http://hlPlOB1M.nkkpp.cn
http://DHuwkil1.nkkpp.cn
http://ozW9OJth.nkkpp.cn
http://A3rlhPb9.nkkpp.cn
http://GRf0iKv4.nkkpp.cn
http://tcYbSfIY.nkkpp.cn
http://ab3njCoz.nkkpp.cn
http://aw32EZrk.nkkpp.cn
http://Ah2prTyq.nkkpp.cn
http://ejaOMUyB.nkkpp.cn
http://35TRQNrH.nkkpp.cn
http://gNrldpFq.nkkpp.cn
http://4ElWeR8Q.nkkpp.cn
http://9I6VvDvO.nkkpp.cn
http://FrlCl60O.nkkpp.cn
http://6YYqZvj1.nkkpp.cn
http://Bo3jq25D.nkkpp.cn
http://OId23kMT.nkkpp.cn
http://bIIuMztD.nkkpp.cn
http://iulkFGqa.nkkpp.cn
http://Lb4LcEiY.nkkpp.cn
http://www.dtcms.com/a/378443.html

相关文章:

  • 经济学研究与机器学习应用:R语言实证分析及论文写作指南
  • 洛谷 P1967 [NOIP 2013 提高组] 货车运输(kruskal 重构树 + 求路径最小边权)
  • android 如何判定底部导航栏显示时 不是键盘显示
  • Django入门笔记
  • 中悦大华通过订单日记实现流程重构之路
  • 电波之外:socket套接字,Linux下UDP通信的孤独诗篇
  • 自动驾驶中的传感器技术44——Radar(5)
  • Linux常用命令之top:动态进程排查利器
  • 【Problem】动态规划之跳跃游戏系列
  • Android 相机框架的跨进程通信架构
  • 从零实现成绩管理系统:深入理解 Python 类方法、静态方法和属性封装
  • G1 垃圾收集器深入解析
  • 【Leetcode hot 100】104.二叉树的深度
  • nginx的基础使用
  • AWS 查询 ALB access log
  • 认知语义学对人工智能自然语言处理深层语义分析的影响与启示
  • iText与OpenPDF使用差异及中文处理完全指南
  • 动态规划算法的欢乐密码(五):子数组系列(上)
  • 【国内电子数据取证厂商龙信科技】浅析文件头和文件尾和隐写
  • Gradio全解11——Streaming:流式传输的视频应用(8)——Gemini Live API:实时音视频连接
  • [特殊字符] 玩转 Python 命令行参数:从 `-m` 到 `argparse` 的全攻略
  • [免费]基于Python的Django医院管理系统【论文+源码+SQL脚本】
  • 【音视频】Android NDK 与.so库适配
  • 认识鸿蒙——它不是“安卓换皮”
  • YOLO11目标检测运行推理简约GUI界面
  • 如何在 VSCode 中设置默认浏览器为 Chrome 或 Firefox
  • VSCode设置:解决找不到文件的问题
  • rabbitmq的安装
  • 从拓扑排序看有向图的应用
  • 谷歌浏览器