前言
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
成果图:
从浏览器直接下载到本地
下载好的word文件 蓝色圈圈里的数据均为动态数据
注:这里可以自行写word模板
一、使用步骤
1.打开word模板,给需要赋值的位置先填上数据,方便查找编写freemarker代码,如下图
2.将word文件另存为xml文件 到桌面 ,然后修改jhj.xml修改后缀 改为 jhj.ftl 文件
1.刚打开的xml文件会比较长不太方便查看 可以把内容复制到菜鸟工具进行格式化 找到之前做好标记的位置 将数据替换
2.list循环数据 : 在<w:tr> 前加上 <#list taskstep as taskstep> ** </w:tr>在这之后加上结束标签 </#list>
二、后台代码
1.模板存放位置
2.依赖引入
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
3.后端代码
@RequestMapping(value = "/Testrecord", method = RequestMethod.POST) @ResponseBody public ResponseEntity<byte[]> Testrecord(@RequestBody Map<String, Object> paras, HttpServletRequest request) throws Exception { String path = request.getServletContext().getRealPath("/"); //设备信息 获取数据 BaseResult<Map<String, Object>> DeviceTask= deviceModuleService.getOneDeviceTask((Integer) paras.get("id")); //测试条件 获取数据 BaseResult<List<DeviceTaskStep>> deviceTaskStepByParas = deviceModuleService.getDeviceTaskStepByParas(paras); List<DeviceTaskStep> taskstep = deviceTaskStepByParas.getData(); // 循环方式 BaseResult<List<DeviceTaskLoop>> deviceTaskLoopByParas = deviceModuleService.getDeviceTaskLoopByParas(paras); System.out.println(deviceTaskLoopByParas.getData().toString()+"SAD"); List<DeviceTaskLoop> taskloop = deviceTaskLoopByParas.getData(); // 设备信息 Map<String, Object> datataskstep = DeviceTask.getData(); System.out.println(datataskstep); Object applyNo = datataskstep.get("reportNo"); Configuration configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); // 模板存放路径 configuration.setClassForTemplateLoading(this.getClass(), "/template"); // 获取模板文件 Template template = configuration.getTemplate("Testrecord.ftl"); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Map<String,Object> resultMap = new HashMap<>(); // 设备信息 resultMap.put("reportno",datataskstep.get("reportNo"));//word加入单数据 resultMap.put("devicename",datataskstep.get("deviceName")); resultMap.put("manufacturer",datataskstep.get("manufacturer")); resultMap.put("basictypename",datataskstep.get("basicTypeName")); resultMap.put("devicecode",datataskstep.get("deviceCode")); System.out.println(); if(datataskstep.get("startTime")==null){ resultMap.put("starttime"," "); }else { resultMap.put("starttime",datataskstep.get("startTime")); } if(datataskstep.get("endTime")==null){ resultMap.put("endtime"," "); }else { resultMap.put("endtime",datataskstep.get("endTime")); } // 测试条件 List<Map<String, Object>> tasksteps = new ArrayList<Map<String, Object>>(); if (taskstep.size()==0){ Map<String, Object> map=new HashMap<String, Object>(); map.put("stepNum"," "); map.put("temp", " "); map.put("humid", " "); map.put("timeHour", " "); map.put("timeMin", " "); tasksteps.add(map); }else { for (int i = 0; i < taskstep.size(); i++) { // Map<String, Object> map=new HashMap<String, Object>(); map.put("stepNum", taskstep.get(i).getStepNum()); map.put("temp", taskstep.get(i).getTemp()); map.put("humid", taskstep.get(i).getHumid()); map.put("timeHour", taskstep.get(i).getTimeHour()); map.put("timeMin", taskstep.get(i).getTimeMin()); tasksteps.add(map); } } // 循环方式 List<Map<String, Object>> taskloops = new ArrayList<Map<String, Object>>(); //这里做一个判断 如果加入了空数据会报错 if (taskloop.size()==0){ Map<String, Object> map=new HashMap<String, Object>(); map.put("loopNum", " "); map.put("stepStart", " "); map.put("stepStop", " "); map.put("loopCount", " "); taskloops.add(map); }else { for (int i = 0; i < taskloop.size(); i++) { // System.out.println(taskloop.get(i).getTaskId()+"AAA"); Map<String, Object> map=new HashMap<String, Object>(); map.put("loopNum", taskloop.get(i).getLoopNum()); map.put("stepStart", taskloop.get(i).getStepStart()); map.put("stepStop", taskloop.get(i).getStepStop()); map.put("loopCount", taskloop.get(i).getLoopCount()); taskloops.add(map); } } //word加入循环数据 resultMap.put("taskstep",tasksteps); resultMap.put("taskloop",taskloops); // 测试条件 File outFile = new File(String.format("%s%s.%s",path,applyNo,"doc")); Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8")); template.process(resultMap,out); out.flush(); out.close(); //这是是绝对路径 // String path = "C:\\Users\\zhangyf\\"; // String filename = "aaa.doc"; String filename = String.format("%s.%s",applyNo,"doc"); File file = new File(path+filename); HttpHeaders headers = new HttpHeaders(); //下载显示的文件名,解决中文名称乱码问题 String downloadFileName = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); //通知浏览器以attachment(下载方式)打开图片 headers.setContentDispositionFormData("attachment", downloadFileName); //application/octet-stream:二进制流数据(最常见的文件下载) headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); //201 HttpStatus.CREATED return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED); }
3.前端vue 浏览器下载代码
export function Testrecord(data) { return axios({ url: '/h/deviceModule/Testrecord', method: 'post', data: data, responseType: 'blob' //这里改一下 }) }
// 导出测试结果模板 hanldeExportTaskDoc(record) { const params = { id: record.id, taskId: record.id, } this.$api.Testrecord(params).then((res) => { if (res) { console.log(res); this.downloadWordFile(res,record.reportNo); } }) }, downloadWordFile (file,No) { console.log(No+'.docx'); const blob = new Blob([file], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) const url = URL.createObjectURL(blob) const a = document.createElement('A') a.download = No+'.docx' //下载的文件名 自行设置 a.href = url document.body.appendChild(a) a.click() document.body.removeChild(a) },