SpringBoot导出Word文档的三种方式

打印 上一主题 下一主题

主题 928|帖子 928|积分 2784

SpringBoot导出Word文档的三种方式

一、导出方案

  1. .doc      application/msword
  2. .dot      application/msword
  3. .docx     application/vnd.openxmlformats-officedocument.wordprocessingml.document
  4. .dotx     application/vnd.openxmlformats-officedocument.wordprocessingml.template
  5. .docm     application/vnd.ms-word.document.macroEnabled.12
  6. .dotm     application/vnd.ms-word.template.macroEnabled.12
  7. .xls      application/vnd.ms-excel
  8. .xlt      application/vnd.ms-excel
  9. .xla      application/vnd.ms-excel
  10. .xlsx     application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  11. .xltx     application/vnd.openxmlformats-officedocument.spreadsheetml.template
  12. .xlsm     application/vnd.ms-excel.sheet.macroEnabled.12
  13. .xltm     application/vnd.ms-excel.template.macroEnabled.12
  14. .xlam     application/vnd.ms-excel.addin.macroEnabled.12
  15. .xlsb     application/vnd.ms-excel.sheet.binary.macroEnabled.12
  16. .ppt      application/vnd.ms-powerpoint
  17. .pot      application/vnd.ms-powerpoint
  18. .pps      application/vnd.ms-powerpoint
  19. .ppa      application/vnd.ms-powerpoint
  20. .pptx     application/vnd.openxmlformats-officedocument.presentationml.presentation
  21. .potx     application/vnd.openxmlformats-officedocument.presentationml.template
  22. .ppsx     application/vnd.openxmlformats-officedocument.presentationml.slideshow
  23. .ppam     application/vnd.ms-powerpoint.addin.macroEnabled.12
  24. .pptm     application/vnd.ms-powerpoint.presentation.macroEnabled.12
  25. .potm     application/vnd.ms-powerpoint.template.macroEnabled.12
  26. .ppsm     application/vnd.ms-powerpoint.slideshow.macroEnabled.12
  27. .mdb      application/vnd.ms-access
复制代码
二、富文本转换后的HTML下载为Word文档

1、准备


  • 业务需求

    • 前端使用富文本插件生成带HTML标签的word文档,然后需要下载这个word文档。
    • 每个word文档的格式是可变的

  • 扩展业务需求:

    • 甚至可以去替换HTML的Word中的内容,然后导出需要的文档;缺点:替换字符串麻烦、而且HTML的Word的标签还需要研究。
    • 基于上述的业务需求。建议使用模板技术导出(也就是“三”)

  • 参考:

  • 导出结果

2、实现

2.1、导包
  1. <dependency>
  2.     <groupId>org.apache.poi</groupId>
  3.     <artifactId>poi</artifactId>
  4.     <version>4.1.2</version>
  5. </dependency>
复制代码
2.2、HTML的word文档
  1. package com.cc.ewd.html;
  2. /**
  3. * @author CC
  4. * @since 2023/4/24 0024
  5. */
  6. public interface HtmlConstants {
  7.     /**
  8.      * 普通文档(富文本生成的)
  9.      */
  10.     String HTML1 = "<h1 style="text-align: center;"><strong>文章标题</strong></h1><h1><strong>一、标题1" +
  11.             "</strong></h1><p><strong>       我是数据:{NUM}</strong></p><h2><strong>" +
  12.             "1.1、吾问无为谓</strong></h2><table style="width: 100%;">" +
  13.             "<tbody><tr><th colSpan="1" rowSpan="1" width="auto">序号</th>" +
  14.             "<th colSpan="1" rowSpan="1" width="auto">第一列</th>" +
  15.             "<th colSpan="1" rowSpan="1" width="auto">第二列</th>" +
  16.             "<th colSpan="1" rowSpan="1" width="auto">第三列</th>" +
  17.             "<th colSpan="1" rowSpan="1" width="auto">第四列</th>" +
  18.             "</tr><tr><td colspan="1" rowspan="1" width="auto" style="text-align: center;">1</td>" +
  19.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">11</td>" +
  20.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">22</td>" +
  21.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">33</td>" +
  22.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">44</td>" +
  23.             "</tr><tr><td colspan="1" rowspan="1" width="auto" style="text-align: center;">2</td>" +
  24.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">11</td>" +
  25.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">22</td>" +
  26.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">33</td>" +
  27.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">44</td>" +
  28.             "</tr><tr><td colspan="1" rowspan="1" width="auto" style="text-align: center;">3</td>" +
  29.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">11</td>" +
  30.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">22</td>" +
  31.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">33</td>" +
  32.             "<td colspan="1" rowspan="1" width="auto" style="text-align: center;">44</td></tr>" +
  33.             "</tbody></table><p><br></p>";
  34.     /**
  35.      * 带表格文档(可以富文本生成,也可以使用word文档另存为HTML文件,然后拷出来)
  36.      */
  37.     String HTML2 = "<h1 align=center  style="text-align:center;" ><b style="mso-bidi-font-weight:normal" ><font face="宋体" >标题</font></b><b style="mso-bidi-font-weight:normal" ><o:p></o:p></b></h1><h2><b style="mso-bidi-font-weight:normal" ><font face="黑体" >一、段落</font><font face="Arial" >1</font></b><b style="mso-bidi-font-weight:normal" ><o:p></o:p></b></h2><p class=MsoNormal ><font face="宋体" >哒哒</font><b><font face="宋体" >哒哒哒</font></b><font face="宋体" >哒</font><o:p></o:p></p><h3><b style="mso-bidi-font-weight:normal" ><font face="Calibri" >1.1</font><font face="宋体" >、表格</font></b><b style="mso-bidi-font-weight:normal" ><o:p></o:p></b></h3><table class=MsoTableGrid  border=1  cellspacing=0  style="border-collapse:collapse;border:none;mso-border-left-alt:0.5000pt solid windowtext;\n" +
  38.             "mso-border-top-alt:0.5000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;mso-border-bottom-alt:0.5000pt solid windowtext;\n" +
  39.             "mso-border-insideh:0.5000pt solid windowtext;mso-border-insidev:0.5000pt solid windowtext;mso-padding-alt:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;" ><tr><td width=142  valign=center  style="width:106.5000pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  40.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  41.             "border-top:1.0000pt solid windowtext;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  42.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="宋体" >序号</font><o:p></o:p></p></td><td width=142  valign=center  style="width:106.5000pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  43.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  44.             "border-top:1.0000pt solid windowtext;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  45.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="宋体" >列</font><font face="Calibri" >1</font><o:p></o:p></p></td><td width=142  valign=center  style="width:106.5500pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  46.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  47.             "border-top:1.0000pt solid windowtext;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  48.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="宋体" >列</font><font face="Calibri" >2</font><o:p></o:p></p></td><td width=142  valign=center  style="width:106.5500pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  49.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  50.             "border-top:1.0000pt solid windowtext;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  51.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="宋体" >列</font><font face="Calibri" >3</font><o:p></o:p></p></td></tr><tr><td width=142  valign=center  style="width:106.5000pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  52.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  53.             "border-top:none;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  54.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="Calibri" >1</font><o:p></o:p></p></td><td width=142  valign=center  style="width:106.5000pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  55.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  56.             "border-top:none;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  57.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="Calibri" >11</font><o:p></o:p></p></td><td width=142  valign=center  style="width:106.5500pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  58.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  59.             "border-top:none;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  60.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="Calibri" >22</font><o:p></o:p></p></td><td width=142  valign=center  style="width:106.5500pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid windowtext;\n" +
  61.             "mso-border-left-alt:0.5000pt solid windowtext;border-right:1.0000pt solid windowtext;mso-border-right-alt:0.5000pt solid windowtext;\n" +
  62.             "border-top:none;mso-border-top-alt:0.5000pt solid windowtext;border-bottom:1.0000pt solid windowtext;\n" +
  63.             "mso-border-bottom-alt:0.5000pt solid windowtext;" ><p class=MsoNormal  align=center  style="text-align:center;" ><font face="Calibri" >33</font><o:p></o:p></p></td></tr></table><p class=MsoNormal ><o:p> </o:p></p><p class=MsoNormal ><o:p> </o:p></p><p class=MsoNormal ><o:p> </o:p></p><h2><b style="mso-bidi-font-weight:normal" ><font face="黑体" >二、段落</font><font face="Arial" >2</font></b><b style="mso-bidi-font-weight:normal" ><o:p></o:p></b></h2><p class=MsoNormal ><o:p> </o:p></p><p class=MsoNormal ><o:p> </o:p></p><p class=MsoNormal ><o:p> </o:p></p>";
  64. }
复制代码
2.3、导出


  • 逻辑、注意事项看注释
  • 代码:
  1. package com.cc.ewd.web.controller;
  2. import com.cc.ewd.html.HtmlConstants;
  3. import org.apache.poi.poifs.filesystem.DirectoryEntry;
  4. import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.*;
  10. import java.net.URLEncoder;
  11. import java.nio.charset.StandardCharsets;
  12. /** 业务需求:前端使用富文本插件生成带HTML标签的word文档,然后需要下载这个word文档。
  13. * @author CC
  14. * @since 2023/4/24 0024
  15. */
  16. @RestController
  17. @RequestMapping("/apachePoiExport")
  18. public class ApachePoiExport {
  19.   /** 将HTML内容(富文本生成的HTML)转换为Word文档并下载
  20.    * @param response HTTP响应
  21.    */
  22.   @GetMapping
  23.   public void getDoc(HttpServletResponse response) {
  24.     String fileName = "Word文件名";
  25.     String html = HtmlConstants.HTML2;
  26.     //导出word的方法
  27.     exportWord(fileName, html, response);
  28.   }
  29.   /** <p>将HTML内容(富文本生成的HTML)转换为Word文档并下载(word2007之后的_docx)</p>
  30.    *  <li>参考:https://my.oschina.net/u/1045509/blog/1924024</li>
  31.    *  <li>参考:https://blog.csdn.net/qq_42682745/article/details/120867432</li>
  32.    * @param fileName 文件名
  33.    * @param html 富文本生成的HTML
  34.    * @param response 响应
  35.    * @since 2023/4/25 0025
  36.    * @author CC
  37.    **/
  38.   public static void exportWord(String fileName, String html, HttpServletResponse response) {
  39.     //0、获取富文本的html:
  40.     // HTML内容必须被<html><body></body></html>包装;最好设置一下编码格式
  41.     // HTML在这里设置<head></head>是为了让输入的文档是以"页面视图"。而不是"Web版式"
  42.     String wrappedHtml =
  43.             "<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"\n" +
  44.                     "xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"\n" +
  45.                     "xmlns="http://www.w3.org/TR/REC-html40">" +
  46.                 "<head>" +
  47.                     "" +
  48.                 "</head>" +
  49.                 "<body>%s</body>" +
  50.             "</html>";
  51.     wrappedHtml = String.format(wrappedHtml, html);
  52.     //1、将HTML转换为Word文档byte数组
  53.     byte[] bytes = wrappedHtml.getBytes(StandardCharsets.UTF_8);
  54.     try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem();
  55.          InputStream byteInputStream = new ByteArrayInputStream(bytes);
  56. //             InputStream inputStream = new BufferedInputStream(byteInputStream);
  57.          ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  58.     ){
  59.       //2、使用ApachePoi转换word并设置到输出流outputStream
  60.       DirectoryEntry directory = poifsFileSystem.getRoot();
  61.       //WordDocument名称不允许修改
  62.       directory.createDocument("WordDocument", byteInputStream);
  63.       //将Word文档写入POIFSFileSystem对象
  64.       poifsFileSystem.writeFilesystem(outputStream);
  65.       //3、①将Word文档(输出流outputStream)写入HTTP响应并下载;②也可以上传到自己的文件服务器然后返回URL给前端下载。
  66.       response.setCharacterEncoding("utf-8");
  67.       //设置content-type就是告诉浏览器这是啥玩意儿
  68.       //"octet-stream" :通用二进制流;
  69.       //"msword" :Microsoft Word文档
  70.       //"vnd.openxmlformats-officedocument.wordprocessingml.document" :响应的内容类型设置为Microsoft Word 2007及更高版本的docx格式。对应的文件名后缀需要改成”docx“
  71.       response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8");
  72.       //解决跨域不显示在header里面的问题
  73.       response.setHeader("Access-Control-Expose-Headers","Content-disposition");
  74.       //"attachment":让浏览器把响应视为附件并下载
  75.       //"inline":    让浏览器打开Word文档而不是下载它
  76.       response.setHeader("Content-disposition","attachment; filename=" +
  77.               URLEncoder.encode(fileName.concat(".docx"), "UTF-8"));
  78.       //BufferedOutputStream缓冲流:可以将数据缓存在内存中,以减少对底层IO的调用次数,从而提高性能。
  79.       //ServletOutputStream:用于向客户端发送数据的
  80.       //因为需要将数据写入HTTP响应,所以使用ServletOutputStream是更好的选择。
  81.       OutputStream out = new BufferedOutputStream(response.getOutputStream());
  82.       out.write(outputStream.toByteArray());
  83.       out.flush();
  84.       out.close();
  85.     } catch (Exception e) {
  86.       e.printStackTrace();
  87.     }
  88.   }
  89. }
复制代码
三、使用模板技术导出


  • 使用Thymeleaf模板技术(推荐,也是我使用的)。也可以使用FreeMarker
  • Word文件的格式是固定
  • 可以根据需求写入不同的数据
1、准备工作

1.1、导包
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-thymeleaf</artifactId>
  4. </dependency>
复制代码
1.2、导出文件的预处理,Thymeleaf语法


  • 使用WPS(建议使用微软的Word)新建一个需要导出Word文件


  • 这个Word文件中,需要替换的值,最好使用单独的格式。因为单独的格式在HTML或者xml中才能区分


  • 弄好Word文件,最后另存为xml格式或者HTML(单个文件)格式。就得到我们需要的xml或者HTML格式的Word文件。


  • 使用Thymeleaf语法修改xml文件

    • 参考:Thymeleaf更多语法见下面:
      1. https://blog.csdn.net/weixin_45203607/article/details/120251923
      2. https://blog.csdn.net/guoqigengxin/article/details/108674177普通文本
      复制代码
    • 普通文本



  • 循环
  1. -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
复制代码


  • 条件判断:if-else

1.3、把处理好的xml文件放到resources下


1.4、使用HTML的注意事项


  • 见附件:thymeleaf_3_wps.html
  • 另存为后,修改HTML的编码格式:utf-8


  • 设置值,直接可以设置在:font 标签上


  • “页面视图“修改:

    • 参考导出页面视图见:一、导出方案



2、原理


  • 可以使用xml导出、也可以使用HTML导出。
  • 导出前需要预处理xml
  • 可以使用下面的进行测试、导出。
2.1、原理
  1. package com.cc.ewd.web.controller;
  2. import com.cc.ewd.vo.Msg4Vo;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import org.thymeleaf.context.Context;
  7. import org.thymeleaf.spring5.SpringTemplateEngine;
  8. import org.thymeleaf.templatemode.TemplateMode;
  9. import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
  10. import javax.annotation.Resource;
  11. import javax.servlet.ServletOutputStream;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.ByteArrayInputStream;
  14. import java.io.ByteArrayOutputStream;
  15. import java.io.IOException;
  16. import java.net.URLEncoder;
  17. import java.nio.charset.StandardCharsets;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. /** thymeleaf导出的原理
  23. * @author CC
  24. * @since 2023/4/25 0025
  25. */
  26. @RestController
  27. @RequestMapping("/thymeleafTheoryExport")
  28. public class ThymeleafTheoryExport {
  29.     @Resource
  30.     private SpringTemplateEngine springTemplateEngine;
  31.     /** <p>原理</p>
  32.      * <ol>
  33.      *     <li>相当于把word文件转为xml或者html,然后修改其中的值再以xml、html下载成word文件</li>
  34.      *     <li>这个方法只能运行一次,因为对ClassLoaderTemplateResolver的设置是一次性的</li>
  35.      *     <li>所以需要将ClassLoaderTemplateResolver设置成单例:配置Bean。</li>
  36.      *     <li>doc或docx的模板别使用WPS的文档,使用微软的office新建word文档,然后转为xml或html</li>
  37.      *     <li>可以导出xml、也可以导出html:建议使用xml</li>
  38.      * </ol>
  39.      */
  40.     @GetMapping
  41.     public void thymeleafExport(HttpServletResponse response){
  42.         String fileName = "第一个thy的文件";
  43.         //一、设置Thymeleaf模板
  44.         ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
  45.         //xml文件地址:自定义xml的文件夹:thymeleafcs/thymeleaf_1_wps.xml
  46.         //xml文件地址:默认放在thymeleaf下就可以读取到
  47.         templateResolver.setPrefix("thymeleafcs/");
  48.         //设置文件的后缀
  49.         templateResolver.setSuffix(".xml");
  50. //        templateResolver.setSuffix(".html");
  51.         templateResolver.setCharacterEncoding("utf-8");
  52.         //模板模式:默认是HTML。改为xml
  53. //        templateResolver.setTemplateMode(TemplateMode.XML);
  54.         templateResolver.setTemplateMode(TemplateMode.HTML);
  55.         //加载模板
  56.         springTemplateEngine.setTemplateResolver(templateResolver);
  57.         //启用Spring EL编译器
  58.         springTemplateEngine.setEnableSpringELCompiler(true);
  59.         //二、设置数据(可以用map,也可以用对象)
  60.         Map<String,Object> map = new HashMap<>();
  61.         //1普通文本参数
  62.         map.put("msg1","我是参数1111");
  63.         map.put("msg2","我是参数2222");
  64.         map.put("msg3","我是参数3333");
  65.         //2if-else参数
  66.         map.put("thIf1","1");
  67.         map.put("thIf2","2");
  68.         //3循环:构建集合参数,用于表格:可以是Map;可以是对象
  69. //        List<Map<String,Object>> msg4Vos = new ArrayList<>();
  70.         List<Msg4Vo> msg4Vos = new ArrayList<>();
  71.         for (int i = 0; i < 10; i++) {
  72.             //1map方式
  73. //            Map<String,Object> map4 = new HashMap<>();
  74. //            map4.put("l1","列1-" + i);
  75. //            map4.put("l2","列2-" + i);
  76. //            map4.put("l3","列3-" + i);
  77. //            map4.put("l4","列4-" + i);
  78. //            msg4Vos.add(map4);
  79.             //2对象方式
  80.             Msg4Vo vo = new Msg4Vo();
  81.             vo.setL1("列1-" + i);
  82.             vo.setL2("列2-" + i);
  83.             vo.setL3("列3-" + i);
  84.             vo.setL4("列4-" + i);
  85.             msg4Vos.add(vo);
  86.         }
  87.         map.put("msg4Vos",msg4Vos);
  88.         //4设置数据
  89.         Context context = new Context();
  90.         context.setVariables(map);
  91.         //写入输入(模板名称,数据)
  92.         String process = springTemplateEngine.process("thymeleaf_4_wps_final", context);
  93.         //三、下载
  94.         //建议下载成doc的。不然微软的office可能打不开
  95.         try {
  96.             byte[] bytes = process.getBytes(StandardCharsets.UTF_8);
  97. //            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
  98. //            ByteArrayOutputStream outputStream = getByteArrayOutputStream(inputStream);
  99.             response.setCharacterEncoding("utf-8");
  100.             response.setContentType("application/msword");
  101.             response.setHeader("Access-Control-Expose-Headers","Content-disposition");
  102.             response.setHeader("Content-disposition","attachment; filename=" +
  103.                     URLEncoder.encode(fileName.concat(".doc"), "UTF-8"));
  104.             ServletOutputStream out = response.getOutputStream();
  105.             //两种方式都可以:用bytes好些
  106. //            out.write(outputStream.toByteArray());
  107.             out.write(bytes);
  108.             out.flush();
  109.             out.close();
  110.         }catch(Exception e){
  111.             e.printStackTrace();
  112.         }
  113.     }
  114.     /** 将 ByteArrayInputStream 拷贝成 ByteArrayOutputStream
  115.      *  将 字节数组输入流 拷贝成 字节数组输出流
  116.      */
  117.     public static ByteArrayOutputStream getByteArrayOutputStream(ByteArrayInputStream inputStream) throws IOException {
  118.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  119.         byte[] buffer = new byte[1024];
  120.         int length;
  121.         while ((length = inputStream.read(buffer)) != -1) {
  122.             outputStream.write(buffer, 0, length);
  123.         }
  124.         return outputStream;
  125.     }
  126. }
复制代码
2.2、导出后预览


3、实现

3.1、yml配置
  1. server:
  2.   port: 5555
  3. spring:
  4.   #thymeleaf的配置
  5.   thymeleaf:
  6.     #关闭 Thymeleaf 的缓存开发过程中无需重启
  7.     #Thymeleaf默认会开启页面缓存,提高页面并发能力。但会导致我们修改页面不会立即被展现,因此我们关闭缓存
  8.     cache: false
  9.     #设置thymeleaf页面的编码
  10.     encoding: UTF-8
  11.     #模型:XML/HTML5:HTML是默认值, 为了清楚起见, 在此处添加。
  12.     mode: XML
  13.     #设置thymeleaf页面的后缀:.html是默认。
  14.     suffix: .xml
  15.     #设置thymeleaf页面的存储路径
  16.     prefix: classpath:/thymeleafcs/
  17.     #使用Spring 4.2.4或更高版本启用SpringEL编译器
  18.     #可以加快大多数情况下的执行速度, 但是当一个模板中
  19.     #的表达式在不同数据类型之间重用时,
  20.     #可能与特定情况不兼容, 因此该标志默认为“false”
  21.     #以实现更安全的向后兼容性。
  22.     enable-spring-el-compiler: true
复制代码
3.2、实现
  1. package com.cc.ewd.web.controller;
  2. import com.cc.ewd.vo.Msg4Vo;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import org.thymeleaf.context.Context;
  7. import org.thymeleaf.spring5.SpringTemplateEngine;
  8. import javax.annotation.Resource;
  9. import javax.servlet.ServletOutputStream;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.ByteArrayInputStream;
  12. import java.io.ByteArrayOutputStream;
  13. import java.io.IOException;
  14. import java.net.URLEncoder;
  15. import java.nio.charset.StandardCharsets;
  16. import java.util.ArrayList;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. /** thymeleaf导出的实现
  21. * @author CC
  22. * @since 2023/5/4 0025
  23. */
  24. @RestController
  25. @RequestMapping("/thymeleafExport")
  26. public class ThymeleafExport {
  27.     @Resource
  28.     private SpringTemplateEngine springTemplateEngine;
  29.     /** <p>原理</p>
  30.      * <ol>
  31.      *     <li>相当于把word文件转为xml或者html,然后修改其中的值再以xml、html下载成word文件</li>
  32.      *     <li>这个方法只能运行一次,因为对ClassLoaderTemplateResolver的设置是一次性的</li>
  33.      *     <li>所以需要将ClassLoaderTemplateResolver设置成单例:配置Bean。</li>
  34.      *     <li>doc或docx的模板别使用WPS的文档,使用微软的office新建word文档,然后转为xml或html</li>
  35.      *     <li>可以导出xml、也可以导出html:建议使用xml</li>
  36.      * </ol>
  37.      */
  38.     @GetMapping
  39.     public void thymeleafExport(HttpServletResponse response){
  40.         String fileName = "第二个thy的文件";
  41.         //一、设置数据(可以用map,也可以用对象)
  42.         Map<String,Object> map = new HashMap<>();
  43.         //1普通文本参数
  44.         map.put("msg1","我是参数1111");
  45.         map.put("msg2","我是参数2222");
  46.         map.put("msg3","我是参数3333");
  47.         //2if-else参数
  48.         map.put("thIf1","1");
  49.         map.put("thIf2","2");
  50.         //3循环:构建集合参数,用于表格:可以是Map;可以是对象
  51. //        List<Map<String,Object>> msg4Vos = new ArrayList<>();
  52.         List<Msg4Vo> msg4Vos = new ArrayList<>();
  53.         for (int i = 0; i < 10; i++) {
  54.             //1map方式
  55. //            Map<String,Object> map4 = new HashMap<>();
  56. //            map4.put("l1","列1-" + i);
  57. //            map4.put("l2","列2-" + i);
  58. //            map4.put("l3","列3-" + i);
  59. //            map4.put("l4","列4-" + i);
  60. //            msg4Vos.add(map4);
  61.             //2对象方式
  62.             Msg4Vo vo = new Msg4Vo();
  63.             vo.setL1("列1-" + i);
  64.             vo.setL2("列2-" + i);
  65.             vo.setL3("列3-" + i);
  66.             vo.setL4("列4-" + i);
  67.             msg4Vos.add(vo);
  68.         }
  69.         map.put("msg4Vos",msg4Vos);
  70.         //4设置数据
  71.         Context context = new Context();
  72.         context.setVariables(map);
  73.         //写入输入(模板名称,数据)
  74.         String process = springTemplateEngine.process("thymeleaf_4_wps_final", context);
  75.         //二、下载
  76.         //建议下载成doc的。不然微软的office可能打不开
  77.         try {
  78.             byte[] bytes = process.getBytes(StandardCharsets.UTF_8);
  79. //            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
  80. //            ByteArrayOutputStream outputStream = getByteArrayOutputStream(inputStream);
  81.             response.setCharacterEncoding("utf-8");
  82.             response.setContentType("application/msword");
  83.             response.setHeader("Access-Control-Expose-Headers","Content-disposition");
  84.             response.setHeader("Content-disposition","attachment; filename=" +
  85.                     URLEncoder.encode(fileName.concat(".doc"), "UTF-8"));
  86.             ServletOutputStream out = response.getOutputStream();
  87.             //两种方式都可以:用bytes好些
  88. //            out.write(outputStream.toByteArray());
  89.             out.write(bytes);
  90.             out.flush();
  91.             out.close();
  92.         }catch(Exception e){
  93.             e.printStackTrace();
  94.         }
  95.     }
  96.     /** 将 ByteArrayInputStream 拷贝成 ByteArrayOutputStream
  97.      *  将 字节数组输入流 拷贝成 字节数组输出流
  98.      */
  99.     public static ByteArrayOutputStream getByteArrayOutputStream(ByteArrayInputStream inputStream) throws IOException {
  100.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  101.         byte[] buffer = new byte[1024];
  102.         int length;
  103.         while ((length = inputStream.read(buffer)) != -1) {
  104.             outputStream.write(buffer, 0, length);
  105.         }
  106.         return outputStream;
  107.     }
  108. }
复制代码
3.3、不使用yml配置,使用配置bean方式


  • 可以配置不同的bean,注入使用的时候,使用我们需要的bean。实现动态使用不同类型的模板的功能。
  • 如果yml中配置了, 又配置了bean。yml中的配置会失效。
  • 其中一个bean一定要添加:@Primary。来设置默认的bean
  • config配置
  1. package com.cc.ewd.config;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.context.annotation.Primary;
  6. import org.thymeleaf.spring5.SpringTemplateEngine;
  7. import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
  8. import org.thymeleaf.templatemode.TemplateMode;
  9. import javax.annotation.Resource;
  10. /** ThymeLeaf单独的配置
  11. * @since 2023/5/4 0004
  12. * @author CC
  13. **/
  14. @Configuration
  15. public class MyThymeLeafConfig {
  16.     @Resource
  17.     private ApplicationContext applicationContext;
  18.     /** 自定义的bean
  19.      * @return SpringTemplateEngine
  20.      * @Primary :<li>作用:指定使用名为“myTemplateEngine”的bean作为默认bean。</li>
  21.      *          <li>这样,当您在需要使用SpringTemplateEngine的地方没有指定@Qualifier注释时,Spring将使用该默认bean。</li>
  22.      *          <li>使用@Resource时,可直接设置名字。不用使用@Qualifier注释</li>
  23.      */
  24.     @Bean(name = "myTemplateEngine")
  25.     @Primary
  26.     public SpringTemplateEngine myTemplateEngine(){
  27.         // SpringTemplateEngine自动应用SpringStandardDialect
  28.         // 并启用Spring自己的MessageSource消息解析机制。
  29.         SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  30.         SpringResourceTemplateResolver templateResolver = myTemplateResolver();
  31.         templateEngine.setTemplateResolver(templateResolver);
  32.         // 使用Spring 4.2.4或更高版本启用SpringEL编译器
  33.         // 可以加快大多数情况下的执行速度, 但是当一个模板中
  34.         // 的表达式在不同数据类型之间重用时,
  35.         // 可能与特定情况不兼容, 因此该标志默认为“false”
  36.         // 以实现更安全的向后兼容性。
  37.         templateEngine.setEnableSpringELCompiler(true);
  38.         return templateEngine;
  39.     }
  40.     /** 自定义配置
  41.      * @return SpringResourceTemplateResolver
  42.      */
  43.     @Bean("myTemplateResolver")
  44.     public SpringResourceTemplateResolver myTemplateResolver(){
  45.         // SpringResourceTemplateResolver自动与Spring自己集成
  46.         // 资源解决基础设施, 强烈推荐。
  47.         SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
  48.         templateResolver.setApplicationContext(this.applicationContext);
  49.         templateResolver.setPrefix("classpath:thymeleafcs/");
  50.         templateResolver.setSuffix(".html");
  51.         templateResolver.setCharacterEncoding("UTF-8");
  52.         // HTML是默认值, 为了清楚起见, 在此处添加。
  53.         templateResolver.setTemplateMode(TemplateMode.HTML);
  54.         return templateResolver;
  55.     }
  56. //----------------------------------------------
  57.     /** 自定义的bean2
  58.      * @return SpringTemplateEngine
  59.      */
  60.     @Bean(name = "myTemplateEngine2")
  61.     public SpringTemplateEngine myTemplateEngine2(){
  62.         // SpringTemplateEngine自动应用SpringStandardDialect
  63.         // 并启用Spring自己的MessageSource消息解析机制。
  64.         SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  65.         SpringResourceTemplateResolver templateResolver = myTemplateResolver2();
  66.         templateEngine.setTemplateResolver(templateResolver);
  67.         // 使用Spring 4.2.4或更高版本启用SpringEL编译器
  68.         // 可以加快大多数情况下的执行速度, 但是当一个模板中
  69.         // 的表达式在不同数据类型之间重用时,
  70.         // 可能与特定情况不兼容, 因此该标志默认为“false”
  71.         // 以实现更安全的向后兼容性。
  72.         templateEngine.setEnableSpringELCompiler(true);
  73.         return templateEngine;
  74.     }
  75.     /** 自定义配置2
  76.      * @return SpringResourceTemplateResolver
  77.      */
  78.     @Bean("myTemplateResolver2")
  79.     public SpringResourceTemplateResolver myTemplateResolver2(){
  80.         // SpringResourceTemplateResolver自动与Spring自己集成
  81.         // 资源解决基础设施, 强烈推荐。
  82.         SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
  83.         templateResolver.setApplicationContext(this.applicationContext);
  84.         templateResolver.setPrefix("classpath:thymeleafcs/");
  85.         templateResolver.setSuffix(".xml");
  86.         templateResolver.setCharacterEncoding("UTF-8");
  87.         // HTML是默认值, 为了清楚起见, 在此处添加。
  88.         templateResolver.setTemplateMode(TemplateMode.XML);
  89.         return templateResolver;
  90.     }
  91. }
复制代码

  • 使用

    • @Resource注入:
      1.     @Resource(name = "myTemplateEngine")
      2.     private SpringTemplateEngine springTemplateEngine;
      复制代码
    • @Autowired注入:
      1.     @Autowired
      2.     @Qualifier("myTemplateEngine")
      3.     private SpringTemplateEngine springTemplateEngine1Html;
      复制代码
    • 配置文件会失效——配置类优先
    • 使用:根据传入的type不同。使用的模板是不同的。

  1. package com.cc.ewd.web.controller;
  2. import com.cc.ewd.vo.Msg4Vo;
  3. import org.springframework.beans.factory.annotation.Qualifier;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RequestParam;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import org.thymeleaf.context.Context;
  9. import org.thymeleaf.spring5.SpringTemplateEngine;
  10. import javax.annotation.Resource;
  11. import javax.servlet.ServletOutputStream;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.ByteArrayInputStream;
  14. import java.io.ByteArrayOutputStream;
  15. import java.io.IOException;
  16. import java.net.URLEncoder;
  17. import java.nio.charset.StandardCharsets;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. /** thymeleaf导出的实现
  23. * @author CC
  24. * @since 2023/5/4 0025
  25. */
  26. @RestController
  27. @RequestMapping("/thymeleafExport")
  28. public class ThymeleafExport {
  29. //    @Resource
  30. //    private SpringTemplateEngine springTemplateEngine;
  31.     @Resource(name = "myTemplateEngine")
  32.     private SpringTemplateEngine springTemplateEngine1Html;
  33.     @Resource(name = "myTemplateEngine2")
  34.     private SpringTemplateEngine springTemplateEngine2Xml;
  35.     /** <p>原理</p>
  36.      * <ol>
  37.      *     <li>相当于把word文件转为xml或者html,然后修改其中的值再以xml、html下载成word文件</li>
  38.      *     <li>这个方法只能运行一次,因为对ClassLoaderTemplateResolver的设置是一次性的</li>
  39.      *     <li>所以需要将ClassLoaderTemplateResolver设置成单例:配置Bean。</li>
  40.      *     <li>doc或docx的模板别使用WPS的文档,使用微软的office新建word文档,然后转为xml或html</li>
  41.      *     <li>可以导出xml、也可以导出html:建议使用xml</li>
  42.      * </ol>
  43.      */
  44.     @GetMapping
  45.     public void thymeleafExport(@RequestParam String type, HttpServletResponse response){
  46.         String fileName = "第二个thy的文件";
  47.         //一、设置数据(可以用map,也可以用对象)
  48.         Map<String,Object> map = new HashMap<>();
  49.         //1普通文本参数
  50.         map.put("msg1","我是参数1111");
  51.         map.put("msg2","我是参数2222");
  52.         map.put("msg3","我是参数3333");
  53.         //2if-else参数
  54.         map.put("thIf1","1");
  55.         map.put("thIf2","2");
  56.         //3循环:构建集合参数,用于表格:可以是Map;可以是对象
  57. //        List<Map<String,Object>> msg4Vos = new ArrayList<>();
  58.         List<Msg4Vo> msg4Vos = new ArrayList<>();
  59.         for (int i = 0; i < 10; i++) {
  60.             //1map方式
  61. //            Map<String,Object> map4 = new HashMap<>();
  62. //            map4.put("l1","列1-" + i);
  63. //            map4.put("l2","列2-" + i);
  64. //            map4.put("l3","列3-" + i);
  65. //            map4.put("l4","列4-" + i);
  66. //            msg4Vos.add(map4);
  67.             //2对象方式
  68.             Msg4Vo vo = new Msg4Vo();
  69.             vo.setL1("列1-" + i);
  70.             vo.setL2("列2-" + i);
  71.             vo.setL3("列3-" + i);
  72.             vo.setL4("列4-" + i);
  73.             msg4Vos.add(vo);
  74.         }
  75.         map.put("msg4Vos",msg4Vos);
  76.         //4设置数据
  77.         Context context = new Context();
  78.         context.setVariables(map);
  79.         //写入输入(模板名称,数据):1:html;2:xml
  80.         String process = "";
  81.         if ("1".equals(type)){
  82.             process = springTemplateEngine1Html.process("thymeleaf_3_wps", context);
  83.         }else if ("2".equals(type)){
  84.             process = springTemplateEngine2Xml.process("thymeleaf_4_wps_final", context);
  85.         }
  86.         //二、下载
  87.         //建议下载成doc的。不然微软的office可能打不开
  88.         try {
  89.             byte[] bytes = process.getBytes(StandardCharsets.UTF_8);
  90. //            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
  91. //            ByteArrayOutputStream outputStream = getByteArrayOutputStream(inputStream);
  92.             response.setCharacterEncoding("utf-8");
  93.             response.setContentType("application/msword");
  94.             response.setHeader("Access-Control-Expose-Headers","Content-disposition");
  95.             response.setHeader("Content-disposition","attachment; filename=" +
  96.                     URLEncoder.encode(fileName.concat(".doc"), "UTF-8"));
  97.             ServletOutputStream out = response.getOutputStream();
  98.             //两种方式都可以:用bytes好些
  99. //            out.write(outputStream.toByteArray());
  100.             out.write(bytes);
  101.             out.flush();
  102.             out.close();
  103.         }catch(Exception e){
  104.             e.printStackTrace();
  105.         }
  106.     }
  107.     /** 将 ByteArrayInputStream 拷贝成 ByteArrayOutputStream
  108.      *  将 字节数组输入流 拷贝成 字节数组输出流
  109.      */
  110.     public static ByteArrayOutputStream getByteArrayOutputStream(ByteArrayInputStream inputStream) throws IOException {
  111.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  112.         byte[] buffer = new byte[1024];
  113.         int length;
  114.         while ((length = inputStream.read(buffer)) != -1) {
  115.             outputStream.write(buffer, 0, length);
  116.         }
  117.         return outputStream;
  118.     }
  119. }
复制代码
四、总结


  • 甚至可以结合Thymeleaf模板技术和ApachePoi技术。
  • 先使用Thymeleaf模板技术替换Word文档中的值。然后得到完整的HTML格式的Word文档
  • 然后使用ApachePoi导出HTML格式的Word文档
  • 文中使用到的文档:
https://files.cnblogs.com/files/blogs/787464/SpringBoot导出Word文档的三种方式-文档.rar?t=1683184411&download=true

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

干翻全岛蛙蛙

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表