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

使用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文档(支持循环导出实时多张图片)

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

Evaluating Open-Domain Question Answering in the Era of Large Language Models

本文是LLM系列文章&#xff0c;针对《Evaluating Open-Domain Question Answering in the Era of Large Language Models》的翻译。 大语言模型时代的开放域问答评价 摘要1 引言2 相关工作3 开放域QA评估4 评估开放域QA模型的策略5 正确答案的语言分析6 CuratedTREC上的正则表…...

基于安卓Android的掌上酒店预订APP

项目介绍 网络的广泛应用给生活带来了十分的便利。所以把掌上酒店预订与现在网络相结合&#xff0c;利用java技术建设掌上酒店预订APP&#xff0c;实现掌上酒店预订的信息化。则对于进一步提高掌上酒店预订发展&#xff0c;丰富掌上酒店预订经验能起到不少的促进作用。 掌上酒…...

搭建CNFS文件系统

1.概念&#xff1a; CNFS &#xff08;Cluster Network File System&#xff09;是 GPFS 中的一种模式&#xff0c;用于配置和管理多台服务器&#xff08;节点&#xff09;之间的文件共享和数据访问 它允许多个节点同时访问和共享文件系统的数据&#xff0c;以实现高性能、高可…...

网络工程师知识点7

111、IS-IS路由器的三种类型&#xff1f; Level-1路由器&#xff08;只能创建level-1的LSDB&#xff09; Level-2路由器&#xff08;只能创建level-2的LSDB&#xff09; Level-1-2路由器&#xff08;路由器默认的类型&#xff0c;能同时创建level-1和level-2的LSDB&#xff09;…...

C++ 八股文:类析构

继承层次中&#xff0c;为什么基类析构函数是虚函数&#xff1f; 在继承层次中&#xff0c;将基类的析构函数声明为虚函数的主要原因是为了支持多态和安全的资源释放。以下是为什么基类的析构函数通常应该是虚函数的原因&#xff1a; 多态析构&#xff1a; 当使用基类指针&a…...

第三章 内存管理 八、两级页表

目录 一、定义 二、如何实现地址变换 三、注意 四、总结 一、定义 二级页表是一种分层的虚拟内存管理机制。在二级页表中&#xff0c;虚拟地址被分成两个层次&#xff0c;第一层是页目录&#xff0c;第二层是页表。通过这种方式&#xff0c;二级页表可以管理更大的虚拟内存…...

新时代高效记账:自动化智能如何进行财务管理

随着科技的不断发展&#xff0c;自动化智能已经逐渐渗透到我们生活的各个领域。在财务管理中&#xff0c;自动化智能的应用显得尤为重要。它不仅可以提高财务管理的效率和精度&#xff0c;还能帮助我们更好地规划和掌控公司的财务状况 晨曦记账本提供了多种高效财务管理工具。…...

Linux小程序---进度条

一&#xff1a;\r 和 \n \r --- 回车 --- 使光标回到这一行的开头 \n --- 换行 --- 会来到下一行与之平行的位置 缓冲区的问题&#xff1a; <1>: \n 的示例 正常输出 hehehehe 。 <2>: \r 的示例 为了方便观察&#xff0c;加入一个 sleep &#xff08;休眠函数…...

【Java笔试强训】Day1(100449-组队竞赛 、OR63 删除公共字符)

100449-组队竞赛 链接&#xff1a;组队竞赛 题目&#xff1a; 牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。 例如: 一个队伍三个…...

C语言进行实验:通过程序实现线算图取值【支持VC++ 6.0编辑器环境运行】

背景&#xff1a; 一、实验目的和要求 1、能描述数据基本类型及其常量的表示方法&#xff1b; 2、会对变量进行定义及初始化&#xff1b; 3、能使用运算符与表达式对变量赋值&#xff1b; 4、会描述C语句的概念及种类、C语言常用的输入/出方式&#xff1b; 5、会设计顺序…...

信息检索与数据挖掘|(四)索引构建

目录 &#x1f4da;硬件基础 &#x1f4da;基于块的排序索引方法 &#x1f407;BSBI算法(blocked sort-based indexing) &#x1f4da;内存式单遍扫描索引构建方法 &#x1f407;SPIMI算法(single-pass in-memory indexing) &#x1f4da;分布式索引构建方法 &#x1f4d…...

Ruby使用类组织对象

使用Object.new创建新对象&#xff0c;但是一次只使用一种方法&#xff0c;这是感受以对象为中心的Ruby编程的最佳方式之一。不过这种方式并不能很好地扩展&#xff0c;假如有一个正在运行地在线售票网站&#xff0c;然后其数据库必须处理数以百计地售票记录&#xff0c;那么可…...

Spring Boot 中常用的注解@RequestParam

Spring Boot 中常用的注解RequestParam RequestParam 是 Spring Framework 和 Spring Boot 中常用的注解之一&#xff0c;用于从请求中获取参数值。它通常用于处理 HTTP 请求中的查询参数&#xff08;query parameters&#xff09;或表单数据。下面详细解释 RequestParam 的用…...

Spark工作流程

Spark 的整个工作流程可以概括为以下步骤&#xff1a; 创建 SparkSession&#xff1a; 应用程序首先需要创建一个 SparkSession 对象&#xff0c;它是与 Spark 的交互入口。SparkSession 提供了对核心功能和各个模块的访问。 加载数据&#xff1a; 使用 SparkSession 提供的 AP…...

IDEA如何设置项目包名分级

按上面的勾选即可&#xff01;...

消防应急疏散指示系统在某生物制药工厂项目的应用

安科瑞 华楠 摘要 消防应急照明和疏散指示系统由控制器、集中电源和灯具&#xff08;疏散指示灯具、应急照明灯具&#xff09;等几部分组成。系统采用17寸工业平板电脑、Windonws7系统&#xff0c;可支持联动报警、系统监控、故障报警、自检、备电、记录存储与查询、导光流、…...

C语言文件操作(上)

文章目录 一、为什么使用文件二、什么是文件1.程序文件2.数据文件3.文件名 三、文件的打开与关闭1.文件指针2.文件的打开和关闭fopen 与 fclose 四、文件的顺序读写01 字符输出函数&#xff1a;fputs02 字符输入函数&#xff1a;fgetc03 文本行输出函数&#xff1a;fputs04 文本…...

二叉树的前 中 后序的非递归实现(图文详解)

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…...

.NET验收

验收通用模板&#xff1a; 1.该资料计划看几天&#xff1f; 实际看了几天&#xff1f; 计划7天&#xff0c;实际看了9天 2.多少天一篇总结&#xff1f;将总结列出来。 一周总结一篇。 博客地址:3.这个资料相较于之前资料共同的内容是什么&#xff1f; 不同的(需要强化学习)…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...