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

Velocity 模版操作

用的之前写好的: 传送门

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

java 复制代码
    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 到 PDF
            try (InputStream htmlStream = new ByteArrayInputStream(htmlBytes)) {
                HtmlConverter.convertToPdf(htmlStream, pdfDocument, properties);
            }
        }
        // 返回 PDF 的输入流
        return new ByteArrayInputStream(pdfOutputStream.toByteArray());
    }

具体使用

java 复制代码
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;
    }

效果图


相关推荐
bing_1584 分钟前
MQTT 在Spring Boot 中的使用
java·spring boot·后端·mqtt
purpleseashell_Lili16 分钟前
react 基本写法
java·服务器·前端
oneDay++37 分钟前
# IntelliJ IDEA企业版高效配置指南:从主题到快捷键的终极优化
java·经验分享·intellij-idea·学习方法
Jasmin Tin Wei44 分钟前
idea中的vcs不见了,如何解决
java·ide·intellij-idea
Java程序员-小白1 小时前
使用java -jar命令指定VM参数-D运行jar包报错问题
java·开发语言·jar
东风西巷2 小时前
MobiPDF:安卓设备上的专业PDF阅读与编辑工具
android·智能手机·pdf·软件需求
ClearViper32 小时前
Java的多线程笔记
java·开发语言·笔记
全栈凯哥3 小时前
Java详解LeetCode 热题 100(17):LeetCode 41. 缺失的第一个正数(First Missing Positive)详解
java·算法·leetcode
神经毒素3 小时前
WEB安全--Java安全--LazyMap_CC1利用链
java·开发语言·网络·安全·web安全
逸夕3 小时前
httpclient请求出现403
java