手把手教大家word文档的动态生成

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:juejin.cn/post/

7135253150532894728


1.写在前面

很多时候,我们可能需要根据一个word模板,动态生成,我们所需要得一个word文档。比如,前面我们的电子签章系统《SpringBoot实现电子文件签字+合同系统!》。

很多人可能不知道怎么做?刚好这两天群里一位网友,假期放假中还在埋头苦干写 bug,不知如何动态生成 word 文档?

借这个机会,今天我们一起来手把手教大家如何动态生成 word 文档。

我们来看一下这个word模板,格式如下:

89a1da908822b7aedde708e845644395.jpeg
word模板

这样得一个word模板,我之前得做法是替换段落文本,那会有啥问题?

  1. 文本的格式可能会丢失。

  2. 替换内容标识,可能会读取不到(单词别隔开)。

  3. 无法动态循环输出一个list集合。

  4. table表格无法做到动态输出。

当然啦,因为我们之前的业务功能比较简单,使用之前的替换段落文本方式,也是能实现到,所以就一直没有去研究,有无更好的方式。

嘿,随着业务功能的不断深入,动态list集合,动态table,这些功能也要求要实现了。

那我们作为一个程序员,这不得深入研究嘛?

巧了,哥们这几天,也研究了一个方式,可以实现动态list集合,动态table的渲染,那就是「freemarker模板引擎」

好了,废话不多说,直接进入主题了!!!

d0d766842bf3b4ddb4dbc86ce3d5f456.jpeg
进入主题

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

2.freemarker实现

首先说一下实现步骤:通过将word模板,另存为.xml格式,然后将.xml文件后缀改成 .ftl,然后再使用freemarker模板引擎,将数据填充到.ftl,然后再输出成一个word文档。

实现步骤,还是挺清晰的。那接下来,我们来实现一下:

2.1 word模板

acdb7c90e8155b7f11d28238ac923723.jpeg
word模板

例如:我们有一个这样的api接口文档,然后我们的系统后台会配置管理了很多api接口,然后导出到一个word文件。

1.输出的word文件,要带上文档目录结构(左边)

2.api的内容,要有table表格

3.api接口是一个list集合

由此可见,如果还是用我以前的方式,估计实现起来就相当麻烦了。

那这里用freemarker,如何实现呢?freemarker的语法是:${xxxx},那我们来改造模板,格式如下

2de4df2b4b22f8a7dbbed52e98599fe5.jpeg
freemarker

这里为什么要用:${api.xxx}呢?我们来看一下freemarker是如何渲染一个list的?

<#list apiList as api>    
  ${api.apiName}   
</#list>

看到这,估计大家都懂了把?

就是说我们有一个apiList集合对象,apiList as api,别名为api,进行遍历。${api.apiName} 就输出了apiName对应的属性的值。

看到这,我们的上面的模板,就很好理解了把?那我们来另存为xml。

6470e1c6a5395d8057ddce20e559318a.jpeg
另存为xml

2.2 .xml改.ftl

使用idea打开.ftl,然后格式化一下,搜索一下${api.apiName}

0049a90dadd13c0edc3937575dc4efd3.jpeg
ftl格式化

这里要注意一下,可能会有些地方报错,例如下面:

7e6bd1d9b72c3c14b6ff8db775bfea6c.jpeg
报错

对于这些内容,我们改一下即可。

2f9c05d8a9b95a1fb131c55887bf914a.jpeg
占位符渲染

参考${api.apiName}的格式即可。

好了,这里会有个问题,我们并没有看到有渲染一个list集合的?那这里,我们只能自己去构造了。

找到所有需要动态list渲染的内容,然后再加上 <#list > 标签

050da09e1e9acc9d71cdac69f0c094ad.jpeg
动态list渲染

看到这里,估计大家都知道怎么改.ftl模板了吧?这里就不在一一列举了。

2.3 freemarker渲染

  • 如果是使用springboot,那我们的pom.xml文件,可以添加下面的依赖:

<!-- freemarker-starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
    <version>2.3.12.RELEASE</version>
</dependency>

当然,直接引入fremarker依赖也是可以的,例如下面:

<dependency>
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>2.3.31</version>
</dependency>
  • 代码实现

@Autowired
private Configuration configuration;

@GetMapping("/doExportApiDoc2Word")
public void doExportApiDoc2Word(HttpServletResponse response,
                                @ApiParam @RequestParam(value = "projectId") String projectId){
    try {
        //返回word文档
        String fileName = URLEncoder.encode("接口文档" + DateUtil.format(new Date(), "yyyyMMddHHmmss"), "UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Disposition", "attachment; filename="" + fileName + ".docx"");
        
        //获取apiDoc所需要的数据
        Map<String, Object> dataModel = llsydnService.getApiDocData(projectId);
        
        //加载模板
        Template template = configuration.getTemplate("apiDoc.ftl", "utf-8");
        //渲染模板
        template.process(dataModel, response.getWriter());
        //response的Writer不需要我们手动关,tomcat会帮我们关的
    } catch (Exception e) {
        log.error("导出word异常:", e);
    }
}

由上可见,基本上都不需要我们操作,我们只需要构造出对象的数据,传给freemarker引擎即可。

我们要做的,就是定义好.ftl模板,构造好所需的参数。

这里说明一下,这个apiDoc.ftl模板,我们默认是放在templates目录下面即可,例如下面:

167486ebb39a73c8eab6e154d5fd3a4b.jpeg
ftl模板

2.4 导出word

好了,我们测试一下,浏览器直接访问:http://localhost:8080/doExportApiDoc2Word?projectId=1

c2e5f8d5915f27d94c2eef0d74f8c56c.jpeg
导出word

由此可见,导出的效果,还是蛮好的。

嘿,功能也实现了,我真是个聪明的小伙!!!^_^

a15c395a0ec13eb4865d0c230b1cc9a2.jpeg
聪明的小伙

2.5 office问题处理

好了,功能都正常了,接着就部署到正式环境了,测试了一下,导出的word也能打开。

然后通知业主方的人员测试下,嘿,问题来了:他们说,word文档打不开。

woc,什么情况?我这边都正常的喔?然后找他们要了截图,如下:

78aba0121e97cba1a561ff3bfd76a1fc.jpeg
office打不开

看到这,Microsoft Word?这个是office?哎呀,我本地用的是wps,功能都挺正常的。

然后我就叫业主方人员,用wps试试,嘿,果然是这个问题,wps可以打开,office打不开。

这就奇怪了,难道这是个正常的问题?然后百度了一下,确实,很多人都遇到了这个问题。

基本上都是过了,结果发现,解决的问题也是很简单,就是导出的格式,要从dcox改成doc

@Autowired
private Configuration configuration;

@GetMapping("/doExportApiDoc2Word")
public void doExportApiDoc2Word(HttpServletResponse response,
                                @ApiParam @RequestParam(value = "projectId") String projectId){
    try {
        //返回word文档
        String fileName = URLEncoder.encode("接口文档" + DateUtil.format(new Date(), "yyyyMMddHHmmss"), "UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Disposition", "attachment; filename="" + fileName + ".doc"");
        
        //获取apiDoc所需要的数据
        Map<String, Object> dataModel = llsydnService.getApiDocData(projectId);
        
        //加载模板
        Template template = configuration.getTemplate("apiDoc.ftl", "utf-8");
        //渲染模板
        template.process(dataModel, response.getWriter());
        //response的Writer不需要我们手动关,tomcat会帮我们关的
    } catch (Exception e) {
        log.error("导出word异常:", e);
    }
}

注意,上面的docx改成doc,即可。

我这边还遇到一个问题,就是当我改成doc得时候,office还是打不开,错误信息如下:

9b6ce15cbcc0452c9811718252f324cb.jpeg
office打不开

上面说,xml字符非法,出现的位置:行6984,列43

这个问题,我们要怎么样快速定位到6984行呢?这里我们可以借助一个工具:Notepad++,会帮我们格式化。

可以发现,这里确实是有些特殊字符,回想一下我的功能,这里,好像是使用了换行符号。

f74a20e54b92f5b9a185e1a183e4fc9d.jpeg
office打不开

换行符号如下:

private static String LINESEPARATOR = "" + (char) 11 + "";

不要问我为啥用这个?这个是在网上找到的,当时试了一下,wps下面确实可以换行,觉得就挺神奇。

结果,最后还是栽在了这个换行符号上面!!!

行,那我们就换一种方式:改成下面这个:

private static String LINESEPARATOR = "<w:p></w:p>";

好了,测试一下,功能正常了。office能打开了!!!


今天,又是充实的一天!!!

哎呀,一股风吹过,头顶不禁有点凉意。

啥情况?我的头发呢?(卑微)

4e9b555fdeb76e1628b1e7e94bc89498.jpeg
卑微

好了,以上就是 「freemarker实现word文档模板动态生成」 的分享了。

个人实操可能也不够全面,班门弄斧了。

如果觉得有收获的,帮忙点赞、评论、收藏一下呗!!!

006b8adb46e33eaefe1285e45ad28751.jpeg
点赞


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

73427e9acbfb4484530284861dfc67b0.png

已在知识星球更新源码解析如下:

11e3f8e811f11a14a7143de9725b5865.jpeg

bfd14c9b6de2d25352a59af48fe46d84.jpeg

53898a78db6a4cf463d7ef01afd995a1.jpeg

0fe48ff43b883177066d5543a97da92e.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值