简介
之前项目中有一个生成word文档的功能,根据数据库的数据进行word文档的生成,当时实现了该功能,但没有打笔记忘记了,特此打个笔记记录一下
我使用的freemarker的技术来实现word的生成,网上也都比较推荐该方式,他是通过根据一个模板,进行填充的方式实现word的生成
准备工作
定义word模板
我们要使用freemarker生成word,首先要自己去定义一个doc模板,模板中要填充的数据使用字符串模板的方式定义 ${ 字段名 }
定义完我们的模板之后,我们要将文档保存为xml的格式
修改保存的xml文件
保存完的xml文件是一行的不好查看,我们可以提前复制到idea中,使用ctrl + alt + l 进行格式化,就变成标准的xml格式了
保存为xml常见的问题就是${name}被拆开了,我们要进行修改
修改为下面这样(多余的wr直接删除即可)
基础信息的定义
基础信息的定义只要保证我们转化成的xml文件中的${name} , ${age}格式没错误即可
表格的定义
遍历实现,表格的数据填充
在xml文件中我们的 <w:tbl> 代表是我们的表格 ,<w:tr> 代表的是我们的行 ,<w:tc> 代表我们的列
我们要想使用表格的方式,肯定大部分是要使用我们的list集合进行数据填充的,我们可以通过下面的方式进行遍历填充数据
我们在表格的表头下的<w:tr>上添加
<#list bookList as book>
在我们</w:tr>下添加
</#list>
其中bookList代表我们要遍历的集合,book代表出来的结果,book.month代表book中的字段
实现单元格的合并
有两个标签
该标签表示,从这个开始进行合并
<w:vMerge w:val="restart"/>
该标签表示,只要带这个标签他就与上面的这个标签合并
<w:vMerge/>
我们将这两个标签定义到我们要合并的单元格的<w:tcPr>中
<w:tcW w:w="2765" w:type="dxa"/> <w:vAlign w:val="center"/> <#-- 将month 等于1 和 2的进行合并--> <w:vMerge w:val="restart"/>
图片的插入
首先我们要在指定位置添加一个图片,我们保存为xml文件后,我们的图片信心会变为base64转码的字符串,将这部分进行删除,替换为${images},所以我们进行填充时也要是base64转码后的数据
修改xml文件为ftl文件
最后将我们的文件修改为 .ftl 格式的文件复制到我们 templates文件夹下
代码实现
首先要导入我们的freemarker依赖
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId>
定义我们要填充的数据
public Map<String,Object> dataMap() throws IOException { Map<String , Object> map = new HashMap<>(); List<Map<String,Object>> bookList = new ArrayList<>(); for (int i = 0; i < 5; i++) { Map<String, Object> map1 = new HashMap<>(); map1.put("expense", i +100); map.put("bookList",bookList); File file = new File("C:\\Users\\Administrator\\Desktop\\teacher\\01.jpg"); FileInputStream fileInputStream = new FileInputStream(file); byte[] bytes = new byte[fileInputStream.available()]; fileInputStream.read(bytes); BASE64Encoder base64Encoder = new BASE64Encoder(); String encode = base64Encoder.encode(bytes); map.put("images",encode);
定义我们我们的填充方法
public void insertWord() throws IOException, TemplateException { Configuration configuration = new Configuration(); configuration.setDefaultEncoding("UTF-8"); configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates")); Template template = configuration.getTemplate("模板.ftl", "UTF-8"); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:/222/demo.doc"), "UTF-8")); template.process(this.dataMap(),bufferedWriter);
我们还可以直接定义为下载,不用使用输出流指定下载地址,直接通过下载的方式指定地址
public void upload(HttpServletResponse response){ Configuration configuration = new Configuration(); configuration.setDefaultEncoding("UTF-8"); configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates")); Template template = configuration.getTemplate("模板.ftl", "UTF-8"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String format = simpleDateFormat.format(new Date()); String fileName = URLEncoder.encode("接口文档" + format, "UTF-8"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition","attachment;filename="+fileName+".doc"); Map<String, Object> map = dataMap(); template.process(map, response.getWriter()); //response的Writer不需要我们手动关,tomcat会帮我们关的 log.error("导出word异常:", e);
遇到的坑
1.优为注意:freemarker是不支持 null 的,所以我们的数据要么全部附上值,要么给为空的值设置为 " " ,否则会报错
2.我们在定义表格l遍历填充的时候,一定要注意传入的表格字段类型是list,不能是map,否则会报错
3.和并单元格的时候,查看的文章,它定义的标签是m是小写,实现不了合并,看其他文章都为大写M,修改实现了合并,有大小写区分
无法合并的情况
<w:vmerge w:val="restart"/>
修改后可以合并
<w:vMerge w:val="restart"/>
|