目录

  • freemarker生成word文件并导出
  • 一、环境准备
  • 二、编写代码
    • 1.实体类
    • 2.mapper.xml文件
    • 3.mapper.java文件
    • 4.Service.java
    • 5.ServiceImpl.java
    • 6.wordUtil工具类(重点)
    • 7.controller文件(重点)
    • 8.前端文件
  • 三、处理模板文件
    • 1.填好最初的word文件
    • 2.word文件转xml文件
    • 3.利用xml文件生成ftl模板文件

freemarker生成word文件并导出

根据前端选择的表格数据生成word表格文档。要对若依字典数据进行处理,使导出的是字典标签(如:合格、不合格),而不是字典值(0,1)。同时实现下载好生成的word文件后,自动删除存储的生成文件,避免冗余。


一、环境准备

(1)JDK1.8
(2)SpringBoot2.3.7.RELEASE
(3)Freemarker 2.3.28

主要是导入freemarker

 <!-- freemarker--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.28</version></dependency>

二、编写代码

1.实体类

在下图位置创建一个实体类,内容是需要导出的数据和对应的get,set方法。同时在其中做好对字典数据的处理。
代码如下:

package com.ruoyi.system.domain.TempEntity;import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.system.domain.DataApparatus;
import com.ruoyi.system.domain.vo.DataApparatusCheckSchemeVo;import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;public class TempDataApparatusCheckScheme extends BaseEntity {/** 检/校参量 */@Excel(name = "检/校参量")private String checkParameter;/** 检/校范围 */@Excel(name = "检/校范围")private String checkRange;/** 检/校依据 */@Excel(name = "检/校依据")private String checkBasis;/** 检定单位 */@Excel(name = "检定单位")private String checkUnit;/** 备注 */@Excel(name = "备注")private String rmk;/** 检/校结果 */@Excel(name = "检/校结果")private String checkResult;/** 仪器设备名称 */@Excel(name = "仪器设备名称")private String apparatusName;/** 实验室编号(字典) */@Excel(name = "实验室编号(字典)")private String labId;/** 仪器设备型号 */@Excel(name = "仪器设备型号")private String apparatusModel;/** 出厂编号 */@Excel(name = "出厂编号")private String factoryNum;/** 使用部门(字典) */@Excel(name = "使用部门(字典)")private String userDepartment;/** 检/校周期 */@Excel(name = "检/校周期")private String checkCycle;public String getCheckParameter() {return checkParameter;}public void setCheckParameter(String checkParameter) {this.checkParameter = checkParameter;}public String getCheckRange() {return checkRange;}public void setCheckRange(String checkRange) {this.checkRange = checkRange;}public String getCheckBasis() {return checkBasis;}public void setCheckBasis(String checkBasis) {this.checkBasis = checkBasis;}public String getCheckUnit() {return checkUnit;}public void setCheckUnit(String checkUnit) {this.checkUnit = checkUnit;}public String getRmk() {return rmk;}public void setRmk(String rmk) {this.rmk = rmk;}public String getCheckResult() {return checkResult;}public void setCheckResult(String checkResult) {this.checkResult = checkResult;}public String getApparatusName() {return apparatusName;}public void setApparatusName(String apparatusName) {this.apparatusName = apparatusName;}public String getLabId() {return labId;}public void setLabId(String labId) {this.labId = labId;}public String getApparatusModel() {return apparatusModel;}public void setApparatusModel(String apparatusModel) {this.apparatusModel = apparatusModel;}public String getFactoryNum() {return factoryNum;}public void setFactoryNum(String factoryNum) {this.factoryNum = factoryNum;}public String getUserDepartment() {return userDepartment;}public void setUserDepartment(String userDepartment) {this.userDepartment = userDepartment;}public String getCheckCycle() {return checkCycle;}public void setCheckCycle(String checkCycle) {this.checkCycle = checkCycle;}public TempDataApparatusCheckScheme(DataApparatusCheckSchemeVo s, HashMap<String, ArrayList<SysDictData>> dictmap){this.labId = s.getLabId();this.apparatusName = s.getApparatusName();this.apparatusModel = s.getApparatusModel();this.factoryNum = s.getFactoryNum();this.userDepartment = s.getUserDepartment();this.checkCycle = s.getCheckCycle();this.checkParameter = s.getCheckParameter();this.checkRange = s.getCheckRange();this.checkBasis = s.getCheckBasis();this.checkUnit = s.getCheckUnit();this.rmk = s.getRmk();//check resultfor( SysDictData dictData:dictmap.get("check_result")){if(dictData.getDictValue().equals(s.getCheckResult())){this.checkResult =dictData.getDictLabel();break;}}}public String toString() {return "TempDataApparatusCheckScheme{" +"labId=" + labId +", apparatusName='" + apparatusName + '\'' +", apparatusModel='" + apparatusModel + '\'' +", factoryNum='" + factoryNum + '\'' +", userDepartment='" + userDepartment + '\'' +", checkCycle='" + checkCycle + '\'' +", checkParameter='" + checkParameter + '\'' +", checkRange='" + checkRange + '\'' +", checkBasis='" + checkBasis + '\'' +", checkUnit='" + checkUnit + '\'' +", checkResult='" + checkResult + '\'' +", rmk='" + rmk + '\'' +'}';}
}

2.mapper.xml文件

修改mapper.xml文件。增加根据前端传来的数组查询数据的方法。

 <!--    根据ID数组 查询所有的检校信息 --><select id="selectDataApparatusCheckSchemeByIds" parameterType="Long" resultMap="DataApparatusCheckSchemeVoResult"><include refid="selectDataApparatusCheckSchemeVo" />where data_apparatus_check_scheme.id in<foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach></select>

3.mapper.java文件

 /*** 根据ID数组查询仪器设备校准方案列表* @param ids 仪器设备校准方案主键集合* @return 仪器设备校准方案列表集合*/public List<DataApparatusCheckSchemeVo> selectDataApparatusCheckSchemeByIds(Long[] ids);

4.Service.java

  /*** 根据ID数组查询仪器校准方案列表* @param ids 仪器设备检校方案主键集合* @return 仪器设备校准方案集合*/public List<DataApparatusCheckSchemeVo> selectDataApparatusCheckSchemeByIds(Long[] ids);

5.ServiceImpl.java

 /*** 根据ID数组查询仪器设备校准方案列表* @param ids* @return*/@Overridepublic List<DataApparatusCheckSchemeVo> selectDataApparatusCheckSchemeByIds(Long[] ids) {return dataApparatusCheckSchemeMapper.selectDataApparatusCheckSchemeByIds(ids);}

6.wordUtil工具类(重点)

在下图所示位置建立wordUtil工具类,用于生成word文档以及其他相关操作

代码如下:

package com.ruoyi.common.utils.file;import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.DateUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Map;/*** @ClassName WordUtil* @Description 使用Freemarker生成Word文档工具类* @Author ruoyi* @Date 2022/6/15 10:06**/public class WordUtil {/*** 使用Freemarker自动生成Word文档* @param dataMap   保存Word文档中所需要的数据* @param templatePath  模板文件的绝对路径* @param templateFile  模板文件的名称* @param generateFile  生成文件的路径+名称* @throws Exception*//** 原版生成word方法 */public static void generateWord(Map<String, Object> dataMap, String templatePath,String templateFile, String generateFile) {// 设置FreeMarker的版本Configuration configuration = new Configuration(new Version("2.3.28"));// 设置Freemarker的编码格式configuration.setDefaultEncoding("UTF-8");Writer out = null;try{// 设置FreeMarker生成Word文档所需要的模板的路径configuration.setDirectoryForTemplateLoading(new File(templatePath));// 设置FreeMarker生成Word文档所需要的模板名称Template t = configuration.getTemplate(templateFile, "UTF-8");// 创建一个Word文档的输出流out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(generateFile)), "UTF-8"));//FreeMarker使用Word模板和数据生成Word文档t.process(dataMap, out);} catch (Exception e) {e.printStackTrace();}if (out != null) {try {out.flush();out.close();} catch (IOException e) {e.printStackTrace();}}}/** 新的生成word方法 */public static void CreateWord(HttpServletResponse resp, HttpServletRequest req,Map<String, Object> dataMap, String templatePath,String templateFile, String generateFile) {// 设置FreeMarker的版本Configuration configuration = new Configuration(new Version("2.3.28"));// 设置Freemarker的编码格式configuration.setDefaultEncoding("UTF-8");String str = DateUtils.dateTimeNow() + ".doc";Writer out = null;try{// 设置FreeMarker生成Word文档所需要的模板的路径configuration.setDirectoryForTemplateLoading(new File(templatePath));// 设置FreeMarker生成Word文档所需要的模板名称Template t = configuration.getTemplate(templateFile, "UTF-8");// 创建一个Word文档的输出流out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(generateFile)), "UTF-8"));//FreeMarker使用Word模板和数据生成Word文档t.process(dataMap, out);//下载生成好的Word文档downloadFile(generateFile,str,resp,req);} catch (Exception e) {e.printStackTrace();}if (out != null) {try {out.flush();out.close();} catch (IOException e) {e.printStackTrace();}}}/********************************************//*** 下载文件* @param path 文件的位置* @param fileName 自定义下载文件的名称* @param resp http响应* @param req http请求*/public static void downloadFile(String path, String fileName, HttpServletResponse resp, HttpServletRequest req){System.out.println("开始下载到本地");try {File file = new File(path);/*** 中文乱码解决*/String type = req.getHeader("User-Agent").toLowerCase();if(type.indexOf("firefox")>0 || type.indexOf("chrome")>0){/*** 谷歌或火狐*/fileName = new String(fileName.getBytes("utf-8"), "iso8859-1");}else{/*** IE*/fileName = URLEncoder.encode(fileName, "utf-8");}// 设置响应的头部信息resp.setHeader("content-disposition", "attachment;filename=" + fileName);// 设置响应内容的类型resp.setContentType(getFileContentType(fileName)+"; charset= utf-8");// 设置响应内容的长度resp.setContentLength((int) file.length());// 输出outStream(new FileInputStream(file), resp.getOutputStream());} catch (Exception e) {System.out.println("执行downloadFile发生了异常:" + e.getMessage());}}/*** 文件的内容类型*/private static String getFileContentType(String name){String result = "";String fileType = name.toLowerCase();if (fileType.endsWith(".png")) {result = "image/png";} else if (fileType.endsWith(".gif")) {result = "image/gif";} else if (fileType.endsWith(".jpg") || fileType.endsWith(".jpeg")) {result = "image/jpeg";} else if(fileType.endsWith(".svg")){result = "image/svg+xml";}else if (fileType.endsWith(".doc")) {result = "application/msword";} else if (fileType.endsWith(".xls")) {result = "application/x-excel";} else if (fileType.endsWith(".zip")) {result = "application/zip";} else if (fileType.endsWith(".pdf")) {result = "application/pdf";} else {result = "application/octet-stream";}return result;}/*** 基础字节数组输出*/private static void outStream(InputStream is, OutputStream os) {try {byte[] buffer = new byte[10240];int length = -1;while ((length = is.read(buffer)) != -1) {os.write(buffer, 0, length);os.flush();}} catch (Exception e) {System.out.println("执行 outStream 发生了异常:" + e.getMessage());} finally {try {os.close();} catch (IOException e) {}try {is.close();} catch (IOException e) {}}}/*** 检查存储生成文件的路径是否存在,如果不存在则新建路径.* @param directory the directory name, like '\dir-name'*/public static void CheckDownloadPath(String directory){File path=new File(RuoYiConfig.getDownloadPath()+directory);if(!path.exists()){path.mkdirs();}}}

7.controller文件(重点)

在controller中调用工具类生成word

/*** 导出仪器校准方案列表*/@PreAuthorize("@ss.hasPermi('system:scheme:export')")@Log(title = "仪器校准方案", businessType = BusinessType.EXPORT)@PostMapping("/export/{ids}")public void export(HttpServletResponse resp, HttpServletRequest req, @PathVariable Long[] ids){//获取仪器设备检校列表List<DataApparatusCheckSchemeVo> list = dataApparatusCheckSchemeService.selectDataApparatusCheckSchemeByIds(ids)//获取字典HashMap<String, ArrayList<SysDictData>> dictData = dictDataService.getAllDictDataMap();//生成结果集Map<String, Object> dataMap = new HashMap<String,Object>();ArrayList<TempDataApparatusCheckScheme> resultList=new ArrayList<TempDataApparatusCheckScheme>();for (DataApparatusCheckSchemeVo s:list){resultList.add(new TempDataApparatusCheckScheme(s,dictData));}dataMap.put("schemeList",resultList);//设置生成文件存储路径String directory="/schemeList";WordUtil.CheckDownloadPath(directory);//生成文件WordUtil.CreateWord(resp,req,dataMap,"ruoyi-system\\src\\main\\resources\\template\\dataApparatusCheckScheme","BKJC-CX-007-2.ftl", RuoYiConfig.getDownloadPath()+directory+"/BKJC-CX-007-2.doc");//下载后删除生成文件FileUtils.deleteFile(RuoYiConfig.getDownloadPath()+directory+"/BKJC-CX-007-2.doc");}

http://t.csdn.cn/iZpPv中描述了获取全部若依全部字典的方法

8.前端文件

js文件

// 导出仪器校准方案
export function exportScheme(ids){return request({url:'/system/scheme/export/' + ids,method: 'post'})
}

index.vue

 /** 导出按钮操作 */handleExport() {let schemeNum=this.ids.length;if(schemeNum<1){this.$message.error('未选择需要导出的设备仪器检校信息,请勾选需要导出的设备仪器检校信息!');}else{exportScheme(this.ids).then(response =>{let data = new Blob([response], { type: 'application/msword,charset=utf-8' });let fileDate = new Date();let fileYear = fileDate.getFullYear();let fileMonth = (fileDate.getMonth()+1).toString().padStart(2,'0');let fileDay = fileDate.getDate().toString().padStart(2,'0');var fileHour = fileDate.getHours().toString().padStart(2,'0')var fileMin = fileDate.getMinutes().toString().padStart(2,'0')if (typeof window.chrome !== 'undefined') {undefined// chromeconst link = document.createElement('a');link.href = window.URL.createObjectURL(data);link.download = fileYear+fileMonth+fileDay+fileHour+fileMin+"仪器设备检校表";link.click();} else if (typeof window.navigator.msSaveBlob !== 'undefined') {undefine// IEconst blob = new Blob([data], {type: 'application/force-download'});window.navigator.msSaveBlob(blob, "BKJC-CX-007-2");} else {undefined// Firefoxconst file = new File([data], "BKJC-CX-007-2", {type: 'application/force-download'});window.open(URL.createObjectURL(file));}})}

三、处理模板文件

1.填好最初的word文件

2.word文件转xml文件

3.利用xml文件生成ftl模板文件

将保存好的xml文件用vsCode打开,vsCode安装XML Tools插件用于格式化xml文件。
xml文件格式化后,找到如下图的表格数据
如果${}形式的占位符中的内容被分隔开了,我们需要手动删除掉中间内容。
将所有表格数据处理好后折叠,在外部包裹如下代码:

<#list schemeList as scheme>
</#list>

完成后如下所示:
注意
①schemeList要与controller代码中保持一致
②as是给schemeList起别名的作用
③scheme就是userList的别名,这样在xml中就可以用scheme.

全部完成后将文件另存为ftl格式即可。

最后将word、xml、ftl三个文件放入项目如图位置。其中ftl文件是真正的模板文件,其余两个文件是中间文件,没有实际作用。

若依 springboot 使用freemarker生成word文件,并导出下载相关推荐

  1. Java技术:SpringBoot集成FreeMarker生成word文件

                    今天给大家分享SpringBoot集成FreeMarker模板引擎生成word文件的用法,感兴趣的可以学一下,完整源码地址在文章末尾处,欢迎互相沟通交流! 一.什么是F ...

  2. Freemarker生成word文件,打开后页眉和页脚图片不显示

    Freemarker生成word文件,打开后页眉和页脚图片不显示 在我们开发过程中通常会把模板文件Ctrl+Alt+L格式化,方便处理.这样就造成word的标签格式产生多余的换行或者空白,但是word ...

  3. Java使用freemarker生成word文件

    首先声明我的项目是一个web项目,生成的word文件直接通过response响应发送给前端.如果不是web项目的话可以像网上的其他教程一样将生成的word保存在本地. 要利用freemarker生成w ...

  4. 火影推荐程序连载32-我是如何使用freemarker生成Word文件的?

    背景 一天,产品经理递给我了一份word报告,我定睛一看 这个文档有大大小小的标题层级,还有排版好的段落.各种一目了然的饼图.走势图,当然还少不了颜色循环交替的报表.精致程度不亚于小明同学的学习报告. ...

  5. SpringBoot根据模板生成Word文件,然后Word转PDF

    1.在pom文件中导入相关依赖 <!--根据模板生成Word 需要依赖 开始--><dependency><groupId>cn.afterturn</gro ...

  6. 使用FreeMarker生成word文件自定义每页页眉或页脚

    最新工作中遇到生成word中表格时,要求文档中每页头部和底部都是固定格式的表格,但是内容不一样,头部信息在word中画样式的时候就可以设置为"在各页顶端以标题形式重复出现",而底部 ...

  7. freemarker生成word文件,word文件打不开解决方法。

    原因 填充的数据中含有'<','>','&'等特殊字符,需要对这些字符进行处理后,Word文件就可以打开了. 报错 解决方案 configuration = new Configu ...

  8. Springboot实现Freemarker生成word文档

    导入Freemarker工具包 <!-- freemaker引擎 --> <dependency><groupId>org.springframework.boot ...

  9. java xsl生成word文件_导出生成xsl文件

    public String expData() throws Exception{ List list = subAreaService.findAll(); HSSFWorkbook hssf =  ...

最新文章

  1. ASP.NET MVC 表单提交教程
  2. Point-to Analysis指针分析(2)
  3. find_all 返回空 python_python小课堂23 - 正则表达式(一)
  4. CompletableFuture介绍
  5. UVA340 ​​​​​​​Master-Mind Hints【数组】
  6. [crypto][ipsec] 简述ESP协议的sequence number机制
  7. MongoDB教程——第2天
  8. 字段计算器中的功能_Flask实践:计算器
  9. 身份证号码(最后一位)计算。(使用 Excel 公式,计算 身份证最后一位)
  10. 计算机表格制作培训教材,电脑制作表格教案设计
  11. 2020ccf大学生计算机系统,云南大学学生获得2019CCF大学生计算机系统与程序设计竞赛西...
  12. 浅谈自然语言处理(NLP)学习路线(一)--- 概述
  13. GDB基本命令(整合)
  14. XML 是一种元语言, 可以用它来描述其他语言。
  15. 3D立方体图片切换动画
  16. 2021届前端面试知识点(其他)
  17. Ibatis.net + Npgsql +PostgreSql 多线程“Timeout while getting a connection from pool.”
  18. 【弄nèng - Activiti6】Activiti6入门篇(十九)—— 结束事件
  19. 秒杀系统的技术架构设计与实现
  20. 解决css使用align-items文字与数字对齐不了问题

热门文章

  1. 如何用手机在旧楼房里拍出文艺范?
  2. android 卡片播放,显示“正在播放”卡片
  3. vim出现 E325:Attention的解决办法
  4. 原创-含泪贡献:Revit二次开发,从零开始,利用socket实现Revit的远程调用,读取rvt文件信息
  5. PCB线宽与过流计算公式
  6. 【转】夫妻间的魔鬼定律
  7. Bzoj3730: 震波
  8. iphone 老是显示无服务器,我的iPhone有时一直显示正在搜索和无服务。但是调制解调器固件有数。是什么问题...
  9. windows 通过bat一键Android手机截图
  10. 6.初次见面的礼貌用语