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

java实现根据Velocity批量生成pdf并合成zip压缩包

Velocity 模版操作

用的之前写好的: 传送门

其中需要新加一个转成输入流的方法

    public static InputStream convertToPdf(StringWriter stringWriter) throws IOException {//将 HTML 转为字节流byte[] htmlBytes = stringWriter.toString().getBytes(StandardCharsets.UTF_8);//创建 PDF 输出流ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream();try (PdfWriter writer = new PdfWriter(pdfOutputStream);PdfDocument pdfDocument = new PdfDocument(writer)) {// 设置 A4 纸张和边距pdfDocument.setDefaultPageSize(PageSize.A4);pdfDocument.setTagged(); // 支持无障碍阅读//配置中文字体ConverterProperties properties = new ConverterProperties();FontProvider fontProvider = new FontProvider();fontProvider.addFont("STSongStd-Light", "UniGB-UCS2-H"); // 添加中文字体properties.setFontProvider(fontProvider);//转换 HTML 到 PDFtry (InputStream htmlStream = new ByteArrayInputStream(htmlBytes)) {HtmlConverter.convertToPdf(htmlStream, pdfDocument, properties);}}// 返回 PDF 的输入流return new ByteArrayInputStream(pdfOutputStream.toByteArray());}

具体使用

public void reportBatchDownload(ReportBatchDownload params, HttpServletResponse response) {List<SpeExamineInfo> infos = speExamineInfoMapper.selectListByReportBatchDownload(params);if (infos.isEmpty()) {throw new ServiceException("当前没有已完成的预约记录");}String filName = "体检报告.zip";// 设置请求流try {FileUtils.setAttachmentResponseHeader(response, filName);response.setContentType("application/zip");try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {for (SpeExamineInfo info : infos) {VelocityContext velocityContext = getVelocityContext(info.getId(), info, null);StringWriter stringWriter = VelocityUtils.genHtml(velocityContext, "vm/report.vm");try (InputStream inputStream = VelocityUtils.convertToPdf(stringWriter)) {// 添加ZIP条目zipOut.putNextEntry(new ZipEntry(buildFilePath(info)));// 写入文件内容byte[] cache = new byte[8192];int nRead;while ((nRead = inputStream.read(cache)) != -1) {zipOut.write(cache, 0, nRead);}zipOut.closeEntry();}zipOut.flush();}// 最后刷新缓冲区zipOut.finish();}} catch (IOException e) {throw new RuntimeException("生成压缩包失败", e);}}private String buildFilePath(SpeExamineInfo info){return "/" + info.getSchName() + "/" + info.getGradeName() + "/" + info.getClassName() + "/" + info.getStuName() + "_体检报告.pdf";}// 处理vm模版变量
private VelocityContext getVelocityContext(String infoId, SpeExamineInfo speExamineInfo, String imgPrefix) {SpeExamineResQuery speExamineResQuery = new SpeExamineResQuery();speExamineResQuery.setInfoId(infoId);List<SpeExamineResDto> speExamineResDtos = speExamineResMapper.selectList(speExamineResQuery);SpeExamineType speExamineType = new SpeExamineType();speExamineType.setInfoId(infoId);List<SpeExamineType> speExamineTypes = speExamineTypeMapper.selectList(speExamineType);Map<String, Object> res = new HashMap<>();speExamineResDtos.forEach(item -> {if (StringUtils.isNotBlank(item.getItemResLabel())) {res.put(item.getItemCode() + "_label", item.getItemResLabel());}res.put(item.getItemCode(), item.getItemRes());res.put(item.getItemCode() + "_conclusion", item.getConclusion());res.put(item.getItemCode() + "_hasException", item.getHasException());});Map<String, Object> type = new HashMap<>();speExamineTypes.forEach(item -> {type.put(item.getItemType() + "_advice", item.getDocAdvice());type.put(item.getItemType() + "_signature", (StringUtils.isNotBlank(imgPrefix) ? imgPrefix : "" ) + item.getDocSign());});Map<String, Object> param = new HashMap<>(3);param.put("info", speExamineInfo);param.put("res", res);param.put("type", type);VelocityContext velocityContext = new VelocityContext();velocityContext.put("pdf", param);return velocityContext;}

效果图

在这里插入图片描述
在这里插入图片描述

http://www.xdnf.cn/news/6329.html

相关文章:

  • 023-C语言预处理详解
  • 使用GoLang版MySQLDiff对比表结构
  • 大模型之Dify之踩坑集锦
  • undefined reference to `typeinfo for DeviceAllocator‘
  • 深入理解浏览器渲染引擎:底层机制与性能优化实战
  • BFD与VRRP联动
  • 高云FPGA-新增输出管脚约束
  • STM32 SD卡拔插后FatFs挂载失败可能原因
  • ACI Fabric 中的各种地址
  • L - Strange Mirroring (思维)
  • Datawhale 5月llm-universe 第2次笔记
  • ⭐️⭐️⭐️【课时 7:如何创建智能体编排应用】学习总结 ⭐️⭐️⭐️ for《大模型Clouder认证:基于百炼平台构建智能体应用》认证
  • Excel在每行下面插入数量不等的空行
  • PyTorch LSTM练习案例:股票成交量趋势预测
  • web第四次课后作业--页面操作实现数据库的增删查改
  • 高精度降压稳压技术在现代工业自动化中的应用
  • 鸿蒙OSUniApp开发的商品详情展示页面(鸿蒙系统适配版)#三方框架 #Uniapp
  • 校园网规划与设计方案
  • 西门子 Teamcenter13 Eclipse RCP 开发 1 工具栏
  • 双目立体视觉
  • MCP本地高效与云端实时:stdio 与 HTTP+SSE 传输机制深度对比
  • 工业场景轮式巡检机器人纯视觉识别导航的优势剖析与前景展望
  • 医院网络安全托管服务(MSS)深度解读与实践路径
  • Vue 3 实现后端 Excel 文件流导出功能(Blob 下载详解)
  • Day 21 训练
  • [Harmony]获取资源文件中.txt文件中的字符串
  • U-Mail邮件系统的安全性和可扩展性
  • 【python】字典:: a list of dictionaries
  • 硬盘坏了电脑会出现哪些明显现象?机械和固态可不一样
  • 【C/C++】深度解析C++ Allocator:优化内存管理的关键