使用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.这个资料相较于之前资料共同的内容是什么? 不同的(需要强化学习)…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
【QT控件】显示类控件
目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏:QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...
2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】
1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...
