网络广告推广实施计划西安seo服务外包

张小明 2026/1/8 7:57:17
网络广告推广实施计划,西安seo服务外包,seo是什么品牌衣服,掌上大学微信管理系统#x1f449; 这是一个或许对你有用的社群#x1f431; 一对一交流/面试小册/简历优化/求职解惑#xff0c;欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料#xff1a; 《项目实战#xff08;视频#xff09;》#xff1a;从书中学#xff0c;往事上…这是一个或许对你有用的社群 一对一交流/面试小册/简历优化/求职解惑欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料《项目实战视频》从书中学往事上“练”《互联网高频面试题》面朝简历学习春暖花开《架构 x 系统设计》摧枯拉朽掌控面试高频场景题《精进 Java 学习指南》系统学习互联网主流技术栈《必读 Java 源码专栏》知其然知其所以然这是一个或许对你有用的开源项目国产Star破10w的开源项目前端包括管理后台、微信小程序后端支持单体、微服务架构RBAC权限、数据权限、SaaS多租户、商城、支付、工作流、大屏报表、ERP、CRM、AI大模型、IoT物联网等功能多模块https://gitee.com/zhijiantianya/ruoyi-vue-pro微服务https://gitee.com/zhijiantianya/yudao-cloud视频教程https://doc.iocoder.cn【国内首批】支持 JDK17/21SpringBoot3、JDK8/11Spring Boot2双版本来源PunkSerris背景解决方案具体实现1.引入iTextPdf库2.编辑对应模板3.编写java PDF生成程序总结背景之前有其他哥们写过类似功能通过解析数据动态生成pdf文件。但他用的那个技术jasper有点老了资料不太好找问过神奇的chatgpt后了解到iTextPdf这个库应该是比较好的选择。基于 Spring Boot MyBatis Plus Vue Element 实现的后台管理系统 用户小程序支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能项目地址https://github.com/YunaiV/ruoyi-vue-pro视频教程https://doc.iocoder.cn/video/解决方案我们先观察下真实的开票预览的模板。发票信息由两部分组成固定信息例如购买方信息、销售方信息。商品信息可能有多行需动态填充很明显的一个主子结构。了解了一下iTextPdf的相关api。要实现这个功能其实我们需要分别生成两部分的发票信息也就是两个pdf然后将两个pdf拼接成同一个。对于第一部分的固定信息我们可以用Acrobat之类的pdf设计工具设计出一个模板然后在java程序中读取并填充对应的模板值。对于第二部分的商品信息就需要获取商品数据动态生成表格当然iTextPdf是支持这一功能的。分别得到两部分的pdf之后再将其合并为同一个pdf就可以了。基于 Spring Cloud Alibaba Gateway Nacos RocketMQ Vue Element 实现的后台管理系统 用户小程序支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能项目地址https://github.com/YunaiV/yudao-cloud视频教程https://doc.iocoder.cn/video/具体实现1.引入iTextPdf库在pom文件中添加iTextPdf的对应依赖。其中 itext-asian 这个也是需要的不然生成的pdf中无法显示中文dependency groupIdcom.itextpdf/groupId artifactIditextpdf/artifactId version5.5.13.2/version /dependency dependency groupIdcom.itextpdf/groupId artifactIditext-asian/artifactId version5.2.0/version /dependency2.编辑对应模板下载Adobe Acrobat工具这部分就不细说了 点击文件-创建-表单。如果你有现成的pdf文件也可以在这步选择单一文件开始没有的话就从头新建通过放置文字和文字域来设计好表单模板。注意文字域“属性”里的名称就是最后使用iTextPdf填充时需要填充的对应字段。3.编写java PDF生成程序使用框架还是老一套的SpringBoot但为了方便测试不展示最终的成品接口而是写在一个可执行的主方法里main里。3.1 读取PDF模板文件iTextPdf负责读取文件的Class是PdfReader,支持多种解析方式可以读取文件路径也支持直接传入文件的字节流线上环境使用了字节流的读取方式。演示的主方法中使用了直接读取本地文件路径的方式。// 读取本地文件当然线上环境肯定不这么写 PdfReader reader new PdfReader(C:\\Users\\User\\Desktop\\开票预览模板.pdf); // 线上环境使用了s3服务器会提前得到字节流 byte[] bytes PdfReader reader new PdfReader(bytes);3.2 填写模板文件并生成固定信息的PDF文件iTextPdf负责填充表单字段的Class是PdfStamperStamper译文压模母盘模子印章用来形容把动态数据填充进已有的表单里还挺形象的注意 form.setField(purName,购买方对应公司); 这里设值的key就是我们在设计表单时文字域的名称。// 临时输出流-表单 ByteArrayOutputStream bos1 new ByteArrayOutputStream(); PdfStamper stamper new PdfStamper(reader, bos1); // 获取表单 AcroFields form stamper.getAcroFields(); form.setGenerateAppearances(true); // 表单填充 form.setField(purName,购买方对应公司); stamper.close();在实际的实现中这里使用了一个MapString,String map遍历所有entrySet将值通过setField(entrySet.key(),entrySet.value())方法填充至表单3.3 动态创建表格并生成商品信息的PDF文件搞定了第一部分的PDF文件我们再来处理第二部分的PDF文件生成商品列表。这里我们需要新建一个Document在这个Document中动态创建一个表格对象PdfPTable最后将Document关闭。调用Document.close()时会触发输出流ByteArrayOutputStream的更新。另外还有一个要点是如果表格要显示中文那么输出的内容格必须设置中文字体否则无法显示。我们来看一下填充一个最简单的Pdf表格是怎么做的// 最简单的示例 import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.PageSize; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; import java.io.FileOutputStream; public class AdjustTablePositionInPdf { public static void main(String[] args) { try { // 创建一个新的 PDF 文档 Document document new Document(PageSize.A4); PdfWriter.getInstance(document, new FileOutputStream(C:\\Users\\User\\Desktop\\adjusted_table_position.pdf)); document.open(); // 添加文本内容 document.add(new Paragraph(Test PDF with Table)); // 创建表格 PdfPTable table new PdfPTable(2); table.addCell(Name); table.addCell(Age); table.addCell(Alice); table.addCell(25); table.addCell(Bob); table.addCell(30); // 设置表格之前的间距 table.setSpacingBefore(20f); // 设置表格之后的间距 table.setSpacingAfter(20f); // 设置表格的总宽度 table.setTotalWidth(300f); // 将表格添加到 PDF document.add(table); document.close(); System.out.println(PDF 文件生成成功); } catch (Exception e) { e.printStackTrace(); } } }声明PdfPTable对象后需指定列的数目通过调用Table.addCell()方法添加行数据。Table.addCell()会自动切换行的。假如表有两列连续调用三个Table.addCell()方法第三个方法就会自动切换到第二行。知道了这一点后我们分析一下对于表格的某一列我们至少需要以下两个参数表头中文名称列的数据映射key/** * 表头信息 **/ Data AllArgsConstructor public class HeadRowMetaInfo { // 列中文名 private String colName; // 列key private String colKey; // 列宽度 private float width; } /** * 自定义头部信息 * return */ public static ListHeadRowMetaInfo headInfos(){ ListHeadRowMetaInfo infos new ArrayList(); infos.add(new HeadRowMetaInfo(货物或应税劳务、服务名称,commodityName,80)); infos.add(new HeadRowMetaInfo(规格型号,model,80)); infos.add(new HeadRowMetaInfo(单位,pushUnitName,80)); infos.add(new HeadRowMetaInfo(数量,orderNum,80)); infos.add(new HeadRowMetaInfo(单价,orderPriceNoTax,80)); infos.add(new HeadRowMetaInfo(不含税金额,orderAmount,80)); infos.add(new HeadRowMetaInfo(税额,taxAmt,80)); infos.add(new HeadRowMetaInfo(含税金额,orderAmountTax,80)); infos.add(new HeadRowMetaInfo(税率,taxRate,80)); return infos; }好了我们继续来看我们的主方法// 临时文件流-商品 ByteArrayOutputStream bos2 new ByteArrayOutputStream(); // 获取原页面的尺寸和样式 Document document new Document(reader.getPageSize(1)); PdfWriter writer PdfWriter.getInstance(document, bos2); document.open(); //新创建一页来存放后面生成的表格 document.newPage(); // 获取商品导出数据 ListMapString, Object mapData otherService.getData(); // 全局统一字体不设置无法显示中文 // 创建支持中文的字体 BaseFont bfChinese BaseFont.createFont(STSongStd-Light, UniGB-UCS2-H, false); Font font new Font(bfChinese, 12, Font.NORMAL, BaseColor.BLACK); PdfPTable table generatePdfPTable(720f,font,mapData,headInfos()); document.add(table); // 文档流关闭 // 关闭后才会触发ByteArrayOutputStream的流更新 document.close(); writer.close();主方法中声明的生成PDF表格的子方法为public static PdfPTable generatePdfPTable(float totalWidth, Font font, ListMapString, Object data, ListHeadRowMetaInfo headRowMetaInfos) throws DocumentException { // 多少列 PdfPTable table new PdfPTable(headRowMetaInfos.size()); // 表宽度 table.setTotalWidth(totalWidth); // 设置每列的宽度 ListFloat flist headRowMetaInfos.stream().map(HeadRowMetaInfo::getWidth).collect(Collectors.toList()); float[] farr new float[flist.size()]; for(int i 0;iflist.size();i){ farr[i] flist.get(i); } table.setWidths(farr); MapInteger,String indexToKeyMap new HashMap(); // 根据表头信息插入表头 for(int i 0 ;i headRowMetaInfos.size();i){ table.addCell(new Phrase(headRowMetaInfos.get(i).getColName(),font)); indexToKeyMap.put(i,headRowMetaInfos.get(i).getColKey()); } // 添加行数据 for(MapString,Object dataItem:data){ for(int i0;iheadRowMetaInfos.size();i){ if(dataItem.get(indexToKeyMap.get(i)) ! null){ table.addCell(new Phrase(dataItem.get(indexToKeyMap.get(i)).toString(),font)); }else{ table.addCell(-); } } } // 计算表格在页面上的位置并添加到页面 // 注意这里的坐标可能需要根据实际情况调整 table.setLockedWidth(true); return table; }3.4 拼接两个PDF文件public static byte[] copy(Listbyte[] files) throws DocumentException, IOException { // 创建文档对象 Document document new Document(); // 创建PdfCopy对象 ByteArrayOutputStream bos new ByteArrayOutputStream(); PdfCopy copy new PdfCopy(document, bos); // 设置只读 copy.setEncryption(null, null, PdfWriter.ALLOW_PRINTING, PdfWriter.STANDARD_ENCRYPTION_128); // 打开文档 document.open(); PdfReader reader; int n; // 循环遍历所有PDF文件 for (byte[] file : files) { reader new PdfReader(file); // 获取每个PDF文件的页数 n reader.getNumberOfPages(); for (int page 0; page n; ) { // 向PdfCopy添加每一页 copy.addPage(copy.getImportedPage(reader, page)); } // 关闭PdfReader reader.close(); } // 关闭文档否则输出流不会刷新 document.close(); byte[] bytes bos.toByteArray(); // 关闭流 bos.close(); return bytes; }3.5 输出用于线上环境的接口在此处得到了字节流之后就上传s3了 在演示用的主函数里将字节流保存为了本地文件log.info(returnPath pdf模板填充成功进行合并); Listbyte[] files new ArrayList(); files.add(bos1.toByteArray()); files.add(bos2.toByteArray()); // 合并两个pdf流 byte[] s3bytes copy(files); // 关闭流 bos1.close(); bos2.close(); reader.close(); // 有流之后 可以把流存储至本地文件也可以上传s3了 String outputPath C:\\Users\\User\\Desktop\\test3.pdf; FileOutputStream fileOutputStream new FileOutputStream(outputPath); fileOutputStream.write(s3bytes); fileOutputStream.close();总结通过这次的需求学习到了JAVA里生成操作pdf文件的方法。先制作PDF表格模板设置文字域可以处理掉导出数据中的固定部分数据 针对表格类的数据长度不固定需要通过生成PDF表格来进行处理。欢迎加入我的知识星球全面提升技术能力。 加入方式“长按”或“扫描”下方二维码噢星球的内容包括项目实战、面试招聘、源码解析、学习路线。文章有帮助的话在看转发吧。 谢谢支持哟 (*^__^*
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

买手表网站主机怎么装wordpress

你是否好奇人工智能如何"读懂"蛋白质的语言?AlphaFold作为DeepMind的革命性成果,正在重新定义生物信息学的边界。本文将深入解析其核心算法架构,揭示从基础原理到产业落地的完整路径。 【免费下载链接】alphafold 项目地址: htt…

张小明 2025/12/28 2:00:10 网站建设

学校门户网站建设工作汇报对外宣传及网站建设文件稿

FaceFusion在新闻播报机器人中的形象定制实践在媒体内容高速迭代的今天,观众对新闻播报形式的要求早已超越“准确”与“及时”,更追求真实感、亲和力与个性化体验。然而,传统虚拟主播系统依赖昂贵的3D建模和动作捕捉流程,难以快速…

张小明 2025/12/28 10:03:33 网站建设

品牌网站查询广州网站建设费用多少

个人收款系统终极部署指南:零基础搭建高效支付解决方案 【免费下载链接】xpay Exrick/xpay 是一个用于集成多种支付方式的 SDK。适合在移动应用和网站中实现支付功能。特点是提供了丰富的支付方式、简洁易用的 API 和良好的兼容性。 项目地址: https://gitcode.co…

张小明 2026/1/3 1:00:00 网站建设

深圳网站建设小江网站建设支付方式

第一章:MCP量子认证全流程概览MCP(Multi-Channel Protocol)量子认证是一种基于量子密钥分发(QKD)与多通道加密协议融合的身份验证机制,广泛应用于高安全等级的分布式系统中。该认证流程结合了量子物理特性与…

张小明 2026/1/4 3:21:02 网站建设

有哪些做文创产品的网站视觉设计专业就业前景

作为大模型落地的核心环节,微调的本质是让预训练模型在保留通用能力的基础上,精准适配特定场景需求——而数据集格式的规范性、算法选择的适配性、参数配置的合理性,共同构成了微调效果的“铁三角”。LLaMA-Factory 凭借多格式数据集支持、灵活的微调策略与全流程训练工具链…

张小明 2026/1/2 13:08:58 网站建设

天津网站建设定做网站开发属于哪个类目

基本特性 多主而非一主多从CAN过滤器是硬件级的实时过滤机制,类似于MQTT的主题匹配,不过CAN是硬件实现的,速度快。过滤是为了减少CPU压力,减少无效消息占用CPU。 总线仲裁 优先级仲裁规则 CAN控制器会对总线上的消息ID进行优先级仲…

张小明 2026/1/8 7:36:21 网站建设