分享

java实现生成word文档_java生成word文档

 jacklopy 2023-11-06 发布于河北

简介

之前项目中有一个生成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>中

  1. <w:tcPr>
  2. <w:tcW w:w="2765" w:type="dxa"/>
  3. <#-- 表示居中-->
  4. <w:vAlign w:val="center"/>
  5. <#-- 将month 等于1 和 2的进行合并-->
  6. <#if book.month == 1>
  7. <w:vMerge w:val="restart"/>
  8. </#if>
  9. <#if book.month == 2>
  10. <w:vMerge/>
  11. </#if>
  12. </w:tcPr>

图片的插入

首先我们要在指定位置添加一个图片,我们保存为xml文件后,我们的图片信心会变为base64转码的字符串,将这部分进行删除,替换为${images},所以我们进行填充时也要是base64转码后的数据

 

修改xml文件为ftl文件

最后将我们的文件修改为 .ftl   格式的文件复制到我们 templates文件夹下

 代码实现

首先要导入我们的freemarker依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-freemarker</artifactId>
  4. </dependency>

定义我们要填充的数据

  1. public Map<String,Object> dataMap() throws IOException {
  2. //获取基础数据
  3. Map<String , Object> map = new HashMap<>();
  4. map.put("name","qtt");
  5. map.put("age","25");
  6. //获取表格数据
  7. List<Map<String,Object>> bookList = new ArrayList<>();
  8. for (int i = 0; i < 5; i++) {
  9. Map<String, Object> map1 = new HashMap<>();
  10. map1.put("month",i);
  11. map1.put("income", i);
  12. map1.put("expense", i +100);
  13. bookList.add(map1);
  14. }
  15. map.put("bookList",bookList);
  16. //获取图片流且进行base64转码
  17. File file = new File("C:\\Users\\Administrator\\Desktop\\teacher\\01.jpg");
  18. FileInputStream fileInputStream = new FileInputStream(file);
  19. byte[] bytes = new byte[fileInputStream.available()];
  20. fileInputStream.read(bytes);
  21. BASE64Encoder base64Encoder = new BASE64Encoder();
  22. String encode = base64Encoder.encode(bytes);
  23. map.put("images",encode);
  24. //关闭流
  25. fileInputStream.close();
  26. return map;
  27. }

定义我们我们的填充方法

  1. @Test
  2. public void insertWord() throws IOException, TemplateException {
  3. //定义我们的编码方式
  4. Configuration configuration = new Configuration();
  5. configuration.setDefaultEncoding("UTF-8");
  6. //指定我们word的目录
  7. configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));
  8. //指定我们要使用的word模板.ftl
  9. Template template = configuration.getTemplate("模板.ftl", "UTF-8");
  10. //指定输出流到的位置
  11. BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:/222/demo.doc"), "UTF-8"));
  12. //执行填充输出
  13. template.process(this.dataMap(),bufferedWriter);
  14. //关闭io流
  15. bufferedWriter.flush();
  16. bufferedWriter.close();
  17. }

我们还可以直接定义为下载,不用使用输出流指定下载地址,直接通过下载的方式指定地址

  1. @GetMapping("/upload")
  2. public void upload(HttpServletResponse response){
  3. try {
  4. //定义我们的编码方式
  5. Configuration configuration = new Configuration();
  6. configuration.setDefaultEncoding("UTF-8");
  7. //指定我们word的目录
  8. configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));
  9. //指定我们要使用的word模板.ftl
  10. Template template = configuration.getTemplate("模板.ftl", "UTF-8");
  11. //返回word文档
  12. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
  13. String format = simpleDateFormat.format(new Date());
  14. String fileName = URLEncoder.encode("接口文档" + format, "UTF-8");
  15. response.setCharacterEncoding("UTF-8");
  16. //请求头定义为下载
  17. response.setHeader("Content-Disposition","attachment;filename="+fileName+".doc");
  18. //获取apiDoc所需要的数据
  19. Map<String, Object> map = dataMap();
  20. //渲染模板
  21. template.process(map, response.getWriter());
  22. //response的Writer不需要我们手动关,tomcat会帮我们关的
  23. } catch (Exception e) {
  24. log.error("导出word异常:", e);
  25. }
  26. }

遇到的坑

1.优为注意:freemarker是不支持  null 的,所以我们的数据要么全部附上值,要么给为空的值设置为 " " ,否则会报错

2.我们在定义表格l遍历填充的时候,一定要注意传入的表格字段类型是list,不能是map,否则会报错

3.和并单元格的时候,查看的文章,它定义的标签是m是小写,实现不了合并,看其他文章都为大写M,修改实现了合并,有大小写区分

无法合并的情况

  1. <w:vmerge w:val="restart"/>
  2. <w:vmerge/>

修改后可以合并

  1. <w:vMerge w:val="restart"/>
  2. <w:vMerge/>

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多