使用FreeMarker导出word文档(支持循环导出实时多张图片)
续上一期的更新内容 ,导出的是单张图片,直接在路径的src 里面填写对应的占位符,就可以了,随着需求的变化,那么今天我们继续往下写一个循环导出多张图片到word里面。

使用FreeMarker导出word文档(支持导出单张图片)
首先我们需要进行在word 里面把对应的模版设置好。

设置好点击另存为,目前我用的html 格式的,网上也有很多xml 形式的,每种写法还不一样

接着我们用记事本进行打开,第一步一定要先修改编码格式为utf-8的

然后我们将html 中head中的标签全部,如果编码不修改,head标签不删除,将来导出的时候就是乱码,这个坑是很深的,排查了好长时间才解决。

这些都修改好后,我们点击另存为将这个模版改成后缀为ftl形式的

接下来我们就开始编写代码
@Overridepublic void exporttdYsdWord(HttpServletRequest request,HttpServletResponse response, String objId, String gllx) {List<Map<String, String>> list = null;List<Map<String, String>> list3 = null;List<Map<String, String>> list5 = null;String ysdName = "";String ysdSql = "";String zpSql = "";String sdsgfa = "";String ysgjjd = "";String sdsgfaEname = "";if ("0".equals(gllx)) {sdsgfa = "sdsgfa";ysgjjd = "ysgjjd";sdsgfaEname = "sczbjys_sczbjys_sdsgfa";ysdName = "中间环节验收报告";ysdSql = "select t.gcmc,t.jgdw,t.jgdwfzr,t.jgdwfzrdh,"+ "t.tdsgdw,t.tdsgdwlxr,t.tdsgdwlxrdh,to_char(t.sqyssj,'yyyy-MM-dd') sqyssj,"+ "t.czwt, (select a.username from gw_yhgl_user a where a.id = t.yxbzrm) yxbzrm, (select h.value from gw_limit_enums h where h.enumName like '%sczbjys_sczbjys_yxbz%' and h.key = t.yxbz) yxbz,(select t.value from gw_limit_enums t where t.enumName like '%sczbjys_sczbjys_ysgjjd%' and t.key=ysgjjd) ysgjjd from GW_SCZBJYS_ZLC t where t.OBJ_ID = ?";}list = this.hibernateDao.queryForListWithSql(ysdSql,new String[]{objId});Map<String, String> map0 = new HashMap<String, String>();Map<String, Object> map = new HashMap<String, Object>();StringBuilder sb = new StringBuilder();String aa="";zpSql="select t.ipath ,t.dpt from gw_pig_address_rw t where t.taskid=? and t.ipath is not null and t.dpt='问题照片' and t.dpt is not null and t.ipath not like '%dat%'" ;list3 = this.hibernateDao.queryForListWithSql(zpSql,new String[]{objId});String zpSqla="select t.ipath ,t.dpt from gw_pig_address_rw t where t.taskid=? and t.ipath is not null and t.dpt is not null and t.ipath not like '%dat%'" ;list5 = this.hibernateDao.queryForListWithSql(zpSqla,new String[]{objId});if(list3.size()>0){for (Map<String, String> stringObjectMap : list3) {if (stringObjectMap.get("DPT").equals("问题照片")) {
// map.put("PSZP", "" + PlatformConfigUtil.getString("TASK_PIC_ADDRESS") + stringObjectMap.get("IPATH"));
// aa= String.valueOf(sb.append(PlatformConfigUtil.getString("TASK_PIC_ADDRESS")+ stringObjectMap.get("IPATH")).append(","));
// aa= String.valueOf(sb.append(" <img width=249 height=273\" src=\""+PlatformConfigUtil.getString("TASK_PIC_ADDRESS") + stringObjectMap.get("IPATH")).append(">").append(","));aa= String.valueOf(sb.append("<img width=\"249\" height=\"273\" src=\""+PlatformConfigUtil.getString("TASK_PIC_ADDRESS") + stringObjectMap.get("IPATH")+"\">").append(","));}}}else{for (Map<String, String> stringObjectMap : list5) {if (!stringObjectMap.get("DPT").equals("问题照片")) {
// map.put("PSZP", "" + PlatformConfigUtil.getString("TASK_PIC_ADDRESS") + stringObjectMap.get("IPATH"));
// aa= String.valueOf(sb.append(PlatformConfigUtil.getString("TASK_PIC_ADDRESS")+ stringObjectMap.get("IPATH")).append(","));String hh="<img width=\"249\" height=\"273\" src=\"http://192.168.200.86:18080/XSGL/2023-07-27/20230802155008.jpg\",<img width=\"249\" height=\"273\" src=\"http://192.168.200.86:18080/XSGL/2023-07-27/20230802154952.jpg\"";aa= String.valueOf(sb.append("<img width=\"249\" height=\"273\" src=\""+PlatformConfigUtil.getString("TASK_PIC_ADDRESS") + stringObjectMap.get("IPATH")+"\">").append(","));}}}if(aa.length()>0){String a1 = aa.substring(0, aa.length() - 1);map.put("PSZP", a1);}else{if(aa.length()>0){String a1 = aa.substring(0, aa.length() - 1);map.put("PSZP", a1);}else{map.put("PSZP", "");}}if (!Tool.isEmptyList(list)) {map0 = list.get(0);if (Tool.isEmptyStr(map0.get("gcmc"))) {map.put("GCMC", "");} else {map.put("GCMC", map0.get("gcmc"));}if (Tool.isEmptyStr(map0.get("jgdw"))) {map.put("JGDW", "");} else {map.put("JGDW",getEnumsValueFromEnumDB("sczbjys_sczbjys_jgdw",map0.get("jgdw")));}if (Tool.isEmptyStr(map0.get("tdsgdw"))) {map.put("TDSGDW", "");} else {map.put("TDSGDW", map0.get("tdsgdw"));}if (Tool.isEmptyStr(map0.get("tdsgdwlxr"))) {map.put("TDSGDWLXR", "");} else {map.put("TDSGDWLXR", map0.get("tdsgdwlxr"));}if (Tool.isEmptyStr(map0.get("tdsgdwlxrdh"))) {map.put("TDSGDWLXRDH", "");} else {map.put("TDSGDWLXRDH", map0.get("tdsgdwlxrdh"));}if (Tool.isEmptyStr(map0.get("yxbz"))) {map.put("YXBZ", "");} else {map.put("YXBZ", map0.get("yxbz"));}if (Tool.isEmptyStr(map0.get("yxbzrm"))) {map.put("YXBZRM", "");} else {map.put("YXBZRM", map0.get("yxbzrm"));}if (Tool.isEmptyStr(map0.get("ysgjjd"))) {map.put("YSGJJD", "");} else {map.put("YSGJJD", map0.get("ysgjjd"));}if (Tool.isEmptyStr(map0.get("sqyssj"))) {map.put("SQYSSJ", "");} else {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");String string = map0.get("sqyssj"); Date parse = null;try {parse = simpleDateFormat.parse(string);} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}String format = simpleDateFormat.format(parse);StringBuilder myName = new StringBuilder(format);myName.setCharAt(4, '年');myName.setCharAt(7, '月');myName.append("日");System.out.println(myName);
// 时间变成 年月日形式map.put("SQYSSJ", myName.toString());}if (Tool.isEmptyStr(map0.get("czwt"))) {map.put("CZWT", "");} else {map.put("CZWT", map0.get("czwt"));}map.put("SJDW", "设计单位");map.put("JLDW", "监理");map.put("BD", "121");map.put("SDJG", "结构好");map.put("CD", "长度1");map.put("JCJ", "井口1");String hh="<img width=\"249\" height=\"273\" src=\"http://192.168.200.86:18080/XSGL/2023-07-27/20230802155008.jpg\",<img width=\"249\" height=\"273\" src=\"http://192.168.200.86:18080/XSGL/2023-07-27/20230802154952.jpg\"";map.put("TFT", "");
// map.put("PSZP", hh);
// map.put("YSGJJD", "飒飒");} else {map.put("SJDW", "");map.put("JLDW", "");map.put("BD", "");map.put("SDJG", "");map.put("CD", "");map.put("JCJ", "");map.put("TFT", "");}try {WordUtils.exportWorde(request, response, map, "scbzjystd.ftl",ysdName);} catch (IOException e) {// TODO Auto-generated catch block
// e.printStackTrace();}}
}

图片的格式高宽度提前在代码里面设置好,然后我们在模版里面用一个占位符来进行替代就可以了。
设置下载格式
public static void exportWorde(HttpServletRequest request,HttpServletResponse response, Map<String, Object> map,String templateName, String fileName) throws IOException {String pathString = request.getSession().getServletContext().getRealPath("/WEB-INF/templete/");logger.info("获取到的模板路径是:templetePath------->" + pathString);configuration.setDirectoryForTemplateLoading(new File(pathString));Template freemarkerTemplate = configuration.getTemplate(templateName);File file = null;InputStream fin = null;ServletOutputStream out = null;try {// 调用工具类的createDoc方法生成Word文档file = createDoce(map,freemarkerTemplate);fin = new FileInputStream(file);response.setCharacterEncoding("utf-8");response.setContentType("application/msword");// 设置浏览器以下载的方式处理该文件名fileName = fileName + DateUtil.currentDateToString() + ".doc";response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));out = response.getOutputStream();byte[] buffer = new byte[512]; // 缓冲区int bytesToRead = -1;// 通过循环将读入的Word文件的内容输出到浏览器中while((bytesToRead = fin.read(buffer)) != -1) {out.write(buffer, 0, bytesToRead);}} finally {if(fin != null) fin.close();if(out != null) out.close();if(file != null) file.delete(); // 删除临时文件}}
设置编码:
private static File createDoce(Map<String, Object> dataMap, Template template) {String name = ".doc";File f = new File(name);Template t = template;try {// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");t.process(dataMap, w);w.close();} catch (Exception ex) {ex.printStackTrace();throw new RuntimeException(ex);}return f;}
导出效果

若本文对你有所帮助,请一键三连,说不定后期工作中就用到了。
相关文章:
使用FreeMarker导出word文档(支持循环导出实时多张图片)
续上一期的更新内容 ,导出的是单张图片,直接在路径的src 里面填写对应的占位符,就可以了,随着需求的变化,那么今天我们继续往下写一个循环导出多张图片到word里面。 使用FreeMarker导出word文档(支持导出单张图片) …...
Evaluating Open-Domain Question Answering in the Era of Large Language Models
本文是LLM系列文章,针对《Evaluating Open-Domain Question Answering in the Era of Large Language Models》的翻译。 大语言模型时代的开放域问答评价 摘要1 引言2 相关工作3 开放域QA评估4 评估开放域QA模型的策略5 正确答案的语言分析6 CuratedTREC上的正则表…...
基于安卓Android的掌上酒店预订APP
项目介绍 网络的广泛应用给生活带来了十分的便利。所以把掌上酒店预订与现在网络相结合,利用java技术建设掌上酒店预订APP,实现掌上酒店预订的信息化。则对于进一步提高掌上酒店预订发展,丰富掌上酒店预订经验能起到不少的促进作用。 掌上酒…...
搭建CNFS文件系统
1.概念: CNFS (Cluster Network File System)是 GPFS 中的一种模式,用于配置和管理多台服务器(节点)之间的文件共享和数据访问 它允许多个节点同时访问和共享文件系统的数据,以实现高性能、高可…...
网络工程师知识点7
111、IS-IS路由器的三种类型? Level-1路由器(只能创建level-1的LSDB) Level-2路由器(只能创建level-2的LSDB) Level-1-2路由器(路由器默认的类型,能同时创建level-1和level-2的LSDB)…...
C++ 八股文:类析构
继承层次中,为什么基类析构函数是虚函数? 在继承层次中,将基类的析构函数声明为虚函数的主要原因是为了支持多态和安全的资源释放。以下是为什么基类的析构函数通常应该是虚函数的原因: 多态析构: 当使用基类指针&a…...
第三章 内存管理 八、两级页表
目录 一、定义 二、如何实现地址变换 三、注意 四、总结 一、定义 二级页表是一种分层的虚拟内存管理机制。在二级页表中,虚拟地址被分成两个层次,第一层是页目录,第二层是页表。通过这种方式,二级页表可以管理更大的虚拟内存…...
新时代高效记账:自动化智能如何进行财务管理
随着科技的不断发展,自动化智能已经逐渐渗透到我们生活的各个领域。在财务管理中,自动化智能的应用显得尤为重要。它不仅可以提高财务管理的效率和精度,还能帮助我们更好地规划和掌控公司的财务状况 晨曦记账本提供了多种高效财务管理工具。…...
Linux小程序---进度条
一:\r 和 \n \r --- 回车 --- 使光标回到这一行的开头 \n --- 换行 --- 会来到下一行与之平行的位置 缓冲区的问题: <1>: \n 的示例 正常输出 hehehehe 。 <2>: \r 的示例 为了方便观察,加入一个 sleep (休眠函数…...
【Java笔试强训】Day1(100449-组队竞赛 、OR63 删除公共字符)
100449-组队竞赛 链接:组队竞赛 题目: 牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。 例如: 一个队伍三个…...
C语言进行实验:通过程序实现线算图取值【支持VC++ 6.0编辑器环境运行】
背景: 一、实验目的和要求 1、能描述数据基本类型及其常量的表示方法; 2、会对变量进行定义及初始化; 3、能使用运算符与表达式对变量赋值; 4、会描述C语句的概念及种类、C语言常用的输入/出方式; 5、会设计顺序…...
信息检索与数据挖掘|(四)索引构建
目录 📚硬件基础 📚基于块的排序索引方法 🐇BSBI算法(blocked sort-based indexing) 📚内存式单遍扫描索引构建方法 🐇SPIMI算法(single-pass in-memory indexing) 📚分布式索引构建方法 Ὅ…...
Ruby使用类组织对象
使用Object.new创建新对象,但是一次只使用一种方法,这是感受以对象为中心的Ruby编程的最佳方式之一。不过这种方式并不能很好地扩展,假如有一个正在运行地在线售票网站,然后其数据库必须处理数以百计地售票记录,那么可…...
Spring Boot 中常用的注解@RequestParam
Spring Boot 中常用的注解RequestParam RequestParam 是 Spring Framework 和 Spring Boot 中常用的注解之一,用于从请求中获取参数值。它通常用于处理 HTTP 请求中的查询参数(query parameters)或表单数据。下面详细解释 RequestParam 的用…...
Spark工作流程
Spark 的整个工作流程可以概括为以下步骤: 创建 SparkSession: 应用程序首先需要创建一个 SparkSession 对象,它是与 Spark 的交互入口。SparkSession 提供了对核心功能和各个模块的访问。 加载数据: 使用 SparkSession 提供的 AP…...
IDEA如何设置项目包名分级
按上面的勾选即可!...
消防应急疏散指示系统在某生物制药工厂项目的应用
安科瑞 华楠 摘要 消防应急照明和疏散指示系统由控制器、集中电源和灯具(疏散指示灯具、应急照明灯具)等几部分组成。系统采用17寸工业平板电脑、Windonws7系统,可支持联动报警、系统监控、故障报警、自检、备电、记录存储与查询、导光流、…...
C语言文件操作(上)
文章目录 一、为什么使用文件二、什么是文件1.程序文件2.数据文件3.文件名 三、文件的打开与关闭1.文件指针2.文件的打开和关闭fopen 与 fclose 四、文件的顺序读写01 字符输出函数:fputs02 字符输入函数:fgetc03 文本行输出函数:fputs04 文本…...
二叉树的前 中 后序的非递归实现(图文详解)
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻强烈推荐优质专栏: 🍔🍟🌯C的世界(持续更新中) 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔…...
.NET验收
验收通用模板: 1.该资料计划看几天? 实际看了几天? 计划7天,实际看了9天 2.多少天一篇总结?将总结列出来。 一周总结一篇。 博客地址:3.这个资料相较于之前资料共同的内容是什么? 不同的(需要强化学习)…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
