最近公司有导出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文件编写完成就可以测试一下啦!

 

 

更多推荐