最近公司有导出word的需求,由于word的样式有的很复杂所以记录一下Java中利用freemarker模板动态生成word含表格,以防以后忘记。
1、word表格的模板
删掉无用的数据留下基础的样式
(如果有需要循环的list表格的位置只留表头和第一行数据)
把调整完的word另存为xml格式:
将保存的xml文件后缀改成.ftl
格式化一下xml,可以去百度一下在线格式化xml那里格式化,格式化完看着清晰一些,要不然容易误删标签导致文件打不开
2、Java代码
配置
项目的gradle文件,xxx.gradle文件里配置好拷贝ftl文件的代码
(绿色部分是需要添加的代码,gradle版本不一样文件路径也不同,下图是4.0版本路径)
2.4版本into "${buildDir}/classes/main"
4.0版本into "${buildDir}/classes/java/main"
1、需要导入freemarker的包
<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.20</version></dependency>
2、代码编写
service层
假装这里有代码,就是查出你要展示到word里面的数据
controller层
@ResponseBody@RequestMapping("/getWord.ajax")public Map<String, Object> getWord(HttpServletResponse response, Long roundId) {response.setContentType("application/x-www-form-urlencoded");response.setHeader("Content-disposition", "attachment; filename=vote1.doc");Map<String, Object> resultMap = new HashMap<>();ResultDO<TurnVoteResult> turnVoteResultDO = electionService.getVoteResultList(roundId);if (turnVoteResultDO.success()) {TurnVoteResult turnVoteResult = turnVoteResultDO.getObj();File file = new FreemarkerUtil().createVoteElected(turnVoteResult);try (ServletOutputStream outputStream = response.getOutputStream();InputStream input = new FileInputStream(file);) {byte[] bytes = new byte[input.available()];int read = input.read(bytes);if (read > 0) {outputStream.write(bytes);outputStream.flush();}} catch (IOException e) {VoteLogger.error(e);}super.setSuccess(resultMap);} else {super.setServiceFailure(resultMap, turnVoteResultDO);}return resultMap;}
createVoteElected方法的代码(voteElected.ftl是文件名字 放在跟这个方法同一文件夹下就行)
public File createVoteElected(TurnVoteResult turnVoteResult) {Map<String, Object> dataMap = new HashMap<>();//File outFile = new File("E:\\voteElected.doc"); // 生成文件路径,测试的时候可以用这句话把文件下载到本地File outFile = new File("voteElected.doc"); // 生成文件的路径dataMap.put("turnVoteResult", turnVoteResult);try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), StandardCharsets.UTF_8))) {configuration.setClassForTemplateLoading(this.getClass(), "");Template t = configuration.getTemplate("voteElected.ftl", "UTF-8"); // 文件名,并且设置编码if (t != null) {t.process(dataMap, out);}out.flush();} catch (IOException | TemplateException e1) {VoteLogger.error(e1);}return outFile;}
3.循环导出
现在替换ftl文件里的值,换成变量 格式是下面这样turnVoteResult是传入的实体名字,meetingPrintName是实体里字段的名字
${(turnVoteResult.meetingPrintName!'')?html}
如果word里有需要循环的地方,在ftl文件里要循环的列上加上
<#list turnVoteResult.turnCandidateVoList as candidate>
注意别忘记结束标签
如果循环里面还需要if判断的话看下图
1、判断对象不为空
如果name为null,freemarker就会报错。
如果需要判断对象不为空:
<#if name??>……</#if>
当对象有属性时,对象及对象属性都有可能为空,可写成:
<#if (user.name)??>//判断对象属性不为空……</#if>
判断String等值
<#if (qrCodeInfo.noteCountFlag)! =='Y'>XXXX<#else>XXXX</#if>
2、判断List是不为空
<#if userList?? && (userList?size > 0) > <h1>List不为空</h1><#list userList as uInfo>……<#else> <h1>显示</h1></#if>
ftl文件编写完成就可以测试一下啦!