通过maven引入需要的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
创建导出模版
1、首先创建一个word模版文档,模版如下图
word模版地址:点击下载
注意word中的占位符的格式,就是freemaker的格式
详细解释如下:
- 文字处理:
直接用${} 中间为替换的字段名。
如果直接在word里面定义${title},在转换成xml的时候有可能会被一些编码隔开,这个时候只需要用word打开xml,将这些内容重新输入一遍。
强烈建议用IDE打开,然后格式化下,在进行检查处理,能用搜索尽量搜索,xml的格式里面有太多的代码,不要硬刚😂
- 图片处理:
需要在word文档模版中插入图片
将word转换成xml后,打开xml,会将我们的图片转换成长长的一段base64。
我们把base64换成我们的${pic}就可以了,pic为字段名,可任意替换
- 列表处理:
需要在word文档模版中插入表格
找到第二个<w:tr>
,第一行是我们的标题,在其前面添加 <#list peopleList as list> 其中 peopleList是传入list的集合名称 list 是别名。
参数取值为:${list.name}这样。
在与<w:tr>
配对的</w:tr>后面添加</#list>。 语法同freemaker的for循环语法
创建ftl模板
将上述word文档另存为test.xml格式,另存完之后可以用浏览器打开test.xml文件,查看我们的占位符是否标准
注意:占位符有时候会发生被隔开的情况,如下图:
图片的替换同上面的说明,图片为一串长长的base64,如下图所示:
然后将文件放置resources/templates目录下。
放置在resource目录下即可,剩下的目录根据自己需求定制。注意要与WordUtil.java中的目录对应。
编写程序
通用的导出工具类
在util包下创建WordUtil.java
工具类,👇
package com.maple.demo.util; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Map; import static freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS; /** * @author 笑小枫 * @date 2022/7/27 * @see <a href="https://www.xiaoxiaofeng.com">https://www.xiaoxiaofeng.com</a> */ public class WordUtil { private final Configuration configuration; public WordUtil() { configuration = new Configuration(DEFAULT_INCOMPATIBLE_IMPROVEMENTS); configuration.setDefaultEncoding("UTF-8"); } public void createWord(Map<String, Object> dataMap, String templateName, String fileName) { // 模板文件所在路径 configuration.setClassForTemplateLoading(this.getClass(), "/templates"); Template t = null; try { // 获取模板文件 t = configuration.getTemplate(templateName, "UTF-8"); } catch (IOException e) { e.printStackTrace(); } // 导出文件 File outFile = new File(fileName); try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), StandardCharsets.UTF_8))) { if (t != null) { // 将填充数据填入模板文件并输出到目标文件 t.process(dataMap, out); } } catch (IOException | TemplateException e1) { e1.printStackTrace(); } } }
请求接口
在controller
包下创建TestWordController.java
👇
其中用到了之前文章的文件转base64,参考文章15.Base64与File互转
package com.maple.demo.controller; import com.maple.demo.util.Base64Util; import com.maple.demo.util.WordUtil; import io.swagger.annotations.Api; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.util.*; /** * @author 笑小枫 * @date 2022/7/27 * @see <a href="https://www.xiaoxiaofeng.com">https://www.xiaoxiaofeng.com</a> */ @RestController @AllArgsConstructor @RequestMapping("/example") @Api(tags = "实例演示-根据模板生成word") public class TestWordController { /** * 文字处理: * 直接用${} 中间为替换的字段名。 * 如果直接在word里面定义${title},在转换成xml的时候有可能会被一些编码隔开,这个时候只需要用word打开xml,将这些内容重新输入一遍。 * 可以用浏览器打开xml,检出自己定义的${}的内容是否都在一起,是否有被编码隔开的情况。 * 图片处理: * 需要在word文档模版中插入图片 * 将word转换成xml后,打开xml,会将我们的图片转换成长长的一段base64。 * 我们把base64换成我们的${pic}就可以了,pic为字段名,可任意替换 * 列表处理: * 需要在word文档模版中插入表格 * 找到第二个<w:tr>,在其前面添加 <#list peopleList as list> 其中 peopleList是传入list的集合名称 list 是别名。 * 参数取值为:${list.name}这样。 * 在与<w:tr>配对的</w:tr>后面添加</#list>。 语法同freemaker的for循环语法 */ @GetMapping("/exportWord") public void exportWord(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1.创建临时文件夹 String rootPath = request.getSession().getServletContext().getRealPath("/"); String fileName = UUID.randomUUID().toString().replace("-", ""); // 处理图片信息,将图片转为base64字符串 File imageFile = new File("D:\\xiaoxiaofeng.jpg"); String base64 = Base64Util.fileToBase64(imageFile); // 处理表格的数据信息 List<Map<String, Object>> list = new ArrayList<>(); int size = 5; for (int i = 0; i < size; i++) { Map<String, Object> map = new HashMap<>(16); map.put("nickName", "笑小枫" + i); map.put("visitTime", "2022-07-27"); map.put("isLike", "是"); map.put("isAttention", "是"); list.add(map); } // 加载word中的数据信息 WordUtil word = new WordUtil(); Map<String, Object> dataMap = new HashMap<>(16); dataMap.put("title", "记得关注我哟"); dataMap.put("email", "1150640979@qq.com"); dataMap.put("name", "笑小枫"); dataMap.put("createDate", "2022-07-27"); dataMap.put("pic", base64); dataMap.put("peopleList", list); word.createWord(dataMap, "word.xml", rootPath + "/" + fileName + ".doc"); String exportName = "测试word"; response.setCharacterEncoding("utf-8"); response.setContentType("application/msword"); // 设置浏览器以下载的方式处理该文件名 response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode(exportName + ".doc", "UTF-8")))); File file = new File(rootPath + "/" + fileName + ".doc"); try (InputStream fin = new FileInputStream(file); ServletOutputStream out = response.getOutputStream()) { // 缓冲区 byte[] buffer = new byte[512]; int bytesToRead; // 通过循环将读入的Word文件的内容输出到浏览器中 while ((bytesToRead = fin.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } } catch (IOException e) { e.printStackTrace(); } finally { // 删除临时文件 file.delete(); } } }
测试
在浏览器输入http://localhost:6666/example/exportWord便可以看到你的word出来了呦。
导出效果图如下:
关于笑小枫💕
本章到这里结束了,喜欢的朋友关注一下我呦😘😘,大伙的支持,就是我坚持写下去的动力。
笑小枫个人博客:https://www.xiaoxiaofeng.com
本系列其它文章
本系列的源码已同步在Github:https://github.com/hack-feng/maple-demo
- SpringBoot项目创建
- SpringBoot配置基于swagger2的knife4j接口文档
- SpringBoot集成Mybatis Plus
- SpringBoot返回统一结果包装
- SpringBoot返回统一异常处理
- SpringBoot日志打印Logback详解
- SpringBoot控制台自定义banner
- SpringBoot集成Redis
- SpringBoot用户登录拦截器
- SpringBoot处理请求跨域问题
- SpringBoot接口日志信息统一记录
- SpringBoot导入Excel
- SpringBoot导出Excel
- SpringBoot发送邮件
- SpringBoot根据模板生成Word
- SpringBoot生成PDF
- SpringBoot文件上传下载
- SpringBoot中的Properties配置