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;}
效果图