访问个人博客java
最近遇到项目需求须要将数据库中的部分数据导出到 word 中,具体是在一个新闻列表中将选中的新闻导出到一个 word 中。参考了网上一些教程,实现了该功能,在此记录下来。ajax
导出结果以下:spring
图中为导出的其中两条新闻。数据库
搜索网上导出 word 的方式有不少种,可是不少都是一笔带过,有示例代码的只找到了 POI 导出,和经过 FreeMarker 方式导出,可是只是具备参考意义。本文采起使用 FreeMark 方式。apache
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.26-incubating</version> </dependency>
新建 word 替换内容为占位符
springboot
另存模板为 XML 文件
多线程
使用 NotePad++ 打开 xml 文件app
选中所有内容,到这里进行格式化工具
将原内容替换为格式化后的内容.net
由于个人 word 的内容是一个列表,因此须要添加一个 freemarer 标签标识
找到<w:document>
元素下面的 <w:body>
元素,添加<#list newsList news>
, 并在</w:body>
结束标签以前闭合 </#list>
, 此处的 newsList 为后台读取模板时须要须要渲染数据map集合的key, 其所对应的是一个list集合。
保存为 FreeMarker 的模板文件,后缀为 ftl 格式,拷贝到项目中
Map<String, Object> root = new HashMap<String, Object>(); root.put("newsList", newsList);//newsList为新闻对象集合 String template = "/temp.ftl"; //模板文件的地址 ByteArrayOutputStream outputStream = WordUtil.process(root, template); return outputStream;
DownloadUtil.download(byteArrayOutputStream, response, returnname);注:在实现功能的时候,因为采起的是 ajax 请求方式,致使只是将流写入 Response 时, Response 为 xml 格式的数据。可是想要实现的效果是弹出下载框,下载 word 文档。最后查询资料,修改ajax请求为form表单提交方式(ajax form),才弹出下载框实现了功能。
//WordUtil.java import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Map; import freemarker.template.Configuration; import freemarker.template.Template; public final class WordUtil { private static Configuration configuration = null; private WordUtil() { throw new AssertionError(); } /** * 根据模板生成相应的文件 * @param root 保存数据的map * @param template 模板文件的地址 * @param path 生成的word文档输出地址 * @return */ public static synchronized ByteArrayOutputStream process(Map<?, ?> root, String template) { if (null == root ) { throw new RuntimeException("数据不能为空"); } if (null == template) { throw new RuntimeException("模板文件不能为空"); } ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); String templatePath = template.substring(0, template.lastIndexOf("/")); String templateName = template.substring(template.lastIndexOf("/") + 1, template.length()); if (null == configuration) { configuration = new Configuration(Configuration.VERSION_2_3_23); // 这里Configurantion对象不能有两个,不然多线程访问会报错 configuration.setDefaultEncoding("utf-8"); configuration.setClassicCompatible(true); } configuration.setClassForTemplateLoading(WordUtil.class, templatePath); Template t = null; try { t = configuration.getTemplate(templateName); Writer w = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8")); t.process(root, w); // 这里w是一个输出地址,能够输出到任何位置,如控制台,网页等 w.close(); } catch (Exception e) { throw new RuntimeException(e); } return outputStream; } }
//DownloadUtil.java import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; public class DownloadUtil { /** * @param byteArrayOutputStream 将文件内容写入ByteArrayOutputStream * @param response HttpServletResponse 写入response * @param returnName 返回的文件名 */ public static void download(ByteArrayOutputStream byteArrayOutputStream, HttpServletResponse response, String returnName) throws IOException{ response.setContentType("application/msword"); response.setHeader("Content-Disposition", "attachment; filename=" + returnName); response.setContentLength(byteArrayOutputStream.size()); OutputStream outputstream = response.getOutputStream(); //取得输出流 byteArrayOutputStream.writeTo(outputstream); //写到输出流 byteArrayOutputStream.close(); //关闭 outputstream.flush(); //刷数据 } }