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

通过Freemark渲染数据到Word里并生成压缩包

通过Freemark渲染数据到Word里并生成压缩包

功能描述:现有一功能,需要把数据值渲染到Word里,并把生成的Word文件放到压缩包里,最后把压缩包下载下来,完成功能。

  1. 效果图:(带图片)
    在这里插入图片描述
  2. 模板制作图:(图片需要base64位,先在Word模板里放一张图片占位,制作好模板另存为XML格式,不要打开,再把.xml格式的后缀改为.ftl格式,放到tempates下,最后把模板中的图片base64位编码改为${image},模板就制作完成了。)
    在这里插入图片描述
    .ftl文件中图片占位符要修改的地方,原本是base64编码,删掉改为自己在map里定义一的字段。
    在这里插入图片描述

代码实现

  1. 接口
	@PostMapping("/genTestReport")@ApiOperation(value = "生成测试报告")public void genTestReport(TestReport testReport, HttpServletResponse response) {//查询验证数据列表List<TestReportVO> testReportVOList = testService.selectTestReportList(testReport);if (CollectionUtil.isEmpty(testReportVOList)) {throw new BaseException("查询数据为空!");}//response设置response.reset();response.setCharacterEncoding(Constants.UTF8);response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);try {FileUtils.setAttachmentResponseHeader(response, "测试报告附件.zip");// 获取输出流ServletOutputStream servletOutputStream = response.getOutputStream();ZipOutputStream zos = new ZipOutputStream(servletOutputStream);//循环处理,把每条需求生成一个申请单,最后打包成压缩包下载for (TestReportVO testReportVO: testReportVOList) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try {//处理截图String screenshot = getImgBySignature(testReportVO.getFileUrl());//生成wordWordUtil wordUtil = new WordUtil();Map<String, Object> dataMap = new HashMap<>();buildReqReviewMeetData(testReportVO, dataMap, screenshot);outputStream.reset();wordUtil.generateFromTemplates(dataMap, "testReport-template.ftl", outputStream);//文件名要唯一,所以拼接了一个testIdString entryName =  "测试报告(" + testReportVO.testId() + ").docx";writeZip(zos, entryName, new ByteArrayInputStream(outputStream.toByteArray()));} catch (Exception e) {logger.error("处理压缩包信息错误:", e);}}// 完成 ZIP 文件的写入zos.finish();servletOutputStream.flush();} catch (IOException e) {logger.error("批量导出测试报告单错误:", e);}}//替换占位符里的数据private void buildReqReviewMeetData(TestReportVO testReportVO, Map<String, Object> dataMap, String screenshot) {dataMap.put("testContent", testReportVO.getTestContent() == null ? "" : testReportVO.getTestContent());//测试内容dataMap.put("testResult", testReportVO.getTestResult() == null ? "" : testReportVO.getTestResult());//测试结果dataMap.put("image", screenshot);//图片}/*** zip 写入一条数据** @param zos       压缩包流* @param entryName 文件名(唯一)* @param bais      文件流* @throws IOException*/private void writeZip(ZipOutputStream zos, String entryName, InputStream bais) throws IOException {try {zos.putNextEntry(new ZipEntry(entryName));byte[] buffer = new byte[1024]; // 1KB 缓冲区int bytesRead;// 逐块读取和写入数据while ((bytesRead = bais.read(buffer)) != -1) {zos.write(buffer, 0, bytesRead);}zos.closeEntry();} catch (Exception e) {logger.error("写入压缩包数据错误:", e);} finally {if (bais != null) {IOUtils.close(bais);}}}//处理图片为base64位private String getImgBySignature(String screenshot) {//获取内容//TODO:换成自己的根据地址获取文件流的方法,转为base64位即可try (InputStream inputStream = minio.download(screenshot)) {byte[] bytes = IOUtils.toByteArray(inputStream);String base64 = Base64.getEncoder().encodeToString(bytes);return base64;} catch (Exception e) {logger.error("处理 URL {} 时出错: {}", path, e.getMessage(), e);}return "";}

2、FileUtils类

public class FileUtils {public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {String percentEncodedFileName = percentEncode(realFileName);StringBuilder contentDispositionValue = new StringBuilder();contentDispositionValue.append("attachment; filename=").append(percentEncodedFileName).append(";").append("filename*=").append("utf-8''").append(percentEncodedFileName);response.setHeader("Content-disposition", contentDispositionValue.toString());response.setHeader("download-filename", percentEncodedFileName);}/*** 百分号编码工具方法** @param s 需要百分号编码的字符串* @return 百分号编码后的字符串*/public static String percentEncode(String s) throws UnsupportedEncodingException {String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());return encode.replaceAll("\\+", "%20");}
}

3、WordUtil 类

public class WordUtil {/*** 模板方式*/private final Configuration configuration;/*** 根据模板生成文件流* @param date 模板数据* @param templateName 模板名称* @param outputStream 输出流* @throws Exception*/public void generateFromTemplates(Map date, String templateName, OutputStream outputStream) throws Exception {Template template = configuration.getTemplate(templateName);Writer w = new OutputStreamWriter(outputStream, "utf-8");template.process(date, w);w.close();}
}
http://www.dtcms.com/a/389843.html

相关文章:

  • Vue 项目中使用 AbortController:解决请求取消、超时与内存泄漏问题
  • 设置管家婆服务器开机自动启动
  • ubuntu20 安装 ros2 foxy
  • 二分查找(二分查找算法)
  • 贪心算法应用:超图匹配问题详解
  • Hadoop3.3.5搭建指南(双NN版本)
  • 如何正确写Controller?参数校验、异常处理
  • 线性代数:LU与Cholesky分解
  • 饮用水在线监测设备:实时、精准地捕捉水体中的关键参数,为供水安全提供全方位保障
  • 【环境搭建】Conda安装教程
  • Java与机器学习的结合:库与应用!
  • DHCP基本原理及实验(ENSP配置)
  • 高系分十一:软件需求工程
  • MCP Server Chart AntV 项目解析
  • 2025药物市场调研分析案例(模板资源分享)
  • 飞网出口网关:安全便捷地访问受限资源
  • 大模型训练的三大显存优化策略
  • 动态加载js链接、异步传参加载组件、有趣打印
  • 【Python】Python异常、模块与包
  • 第三方网站系统测试:【基于Pytest的自动化测试框架的测试】
  • 每个 SIwave 求解器的正确激励
  • 给 C++ Protobuf“装上 Abseil”版本确认、Bazel/CMake 实战与避坑
  • Java 大视界 -- Java 大数据在智能物流运输车辆智能调度与路径优化中的技术实现
  • 电脑中的32位和64位
  • 如何免费使用AWS服务器?AWS Free Tier免费套餐申请与避坑指南
  • QML界面调用C++层阻塞函数,如何不卡界面
  • JVM GC 调优:GC 问题发现工具,五大 GC 异常模式,四大调优方案与案例实战
  • Excel处理控件Aspose.Cells教程:如何使用Python在Excel中创建下拉列表
  • React 18.2中使用Redux 5.0.1
  • 程序开发的基本规律