java 使用freemarker 导出word文档
前言:今天有一个开发需求需要在页面上导出一个word文档,故用到了freemarker
一.什么是freemarker?
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
(百度答案) 也就是开发者可以先建立模板,然后通过freemarker 导出各种类型的文件,今天介绍的就是导出成word文档。
二.项目中如何使用freemarker?
(1)第一步,需要在项目中引用freemarker的jar包
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency>
(2)首先可以自己新建一个word文档,里面的格式自己定义。
(3)将当前这个world文档 保存为xml格式。
(4)转换后的xml文件
(5)接下来就是项目中的引用了,先写一个html页面。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h2>使用freemarker 导出文档</h2> </body> <form action="/exportPunishmentBook" method="get" > <input type="submit" value="导出文档" /> <br><br> </form> </html>
(6)接下来写后端接口,
@ApiOperation(value = "1.3 使用FreeMarker 导出文档") @GetMapping(value = "/exportPunishmentBook") public void exportPunishmentBook(HttpServletResponse response) { try { //获得一条行为管理的数据,填充到map中 Map<String, Object> dataMap = new LinkedHashMap<>(); getData(dataMap); //得到模板位置,模板分两套,一套是带图片 一套是不带图片 String templateFilePath = ResourceUtils.getFile("classpath:template").getPath() + "/report.ftl"; //在模板文件里插入数据后生成了一个临时文件,再把这个临时文件用流返回给前端 String exportFilePath = "C:\\ebo_system_file\\test\\"; File file = new File(exportFilePath); if (!file.exists() && !file.isDirectory()) { file.mkdirs(); } exportFilePath += "test-临时文件-" + System.currentTimeMillis() + ".doc"; //设置response返回信息 response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode("处罚书", "UTF-8")))); //得到填充数据后的文件,返回给前端 File newFile = ExportDotFile.getInstance().createDocFile(templateFilePath, dataMap, exportFilePath, 1); //获取文件输入流 InputStream in = new FileInputStream(newFile); int len = 0; byte[] buffer = new byte[1024]; OutputStream out = response.getOutputStream(); while ((len = in.read(buffer)) > 0) { //将缓冲区的数据输出到客户端浏览器 out.write(buffer, 0, len); } out.flush(); out.close(); in.close(); newFile.delete(); } catch (Exception e) { // TODO Auto-generated catch block log.error("处罚书导出异常", e); } }
(7)最后的效果图。导出来的效果图如下:
(8)上述代码中涉及的类我将其贴出来。
/** * @param dataMap */ public static void getData(Map<String, Object> dataMap) throws Exception { dataMap.put("id", changeStr("1")); dataMap.put("name", changeStr("唐三")); dataMap.put("age", changeStr("18")); dataMap.put("sex", changeStr("男")); dataMap.put("email", changeStr("@qq.com")); dataMap.put("phone", changeStr("66666")); } public static String changeStr(String str) { str = str.replaceAll("<br/>", "").replaceAll(" ", "").replaceAll("<p/>", "") .replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&"); return str; }
ExportDotFile类
package com.test.util; import freemarker.template.Configuration; import freemarker.template.Template; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.Map; /**使用freemarker导出doc文件 * @author luojie * @date 2019/11/7 9:29 */ public class ExportDotFile { private static Logger logger = LoggerFactory.getLogger(ExportDotFile.class); private static ExportDotFile service = null; private ExportDotFile() { super(); } public static ExportDotFile getInstance() { if(service == null) { synchronized(ExportDotFile.class){ if(service == null) { service = new ExportDotFile(); } } } return service; } /** * * @param templateFilePath eg: /template/test/test.ftl * @param dataMap * @param exportFilePath eg: /tmp/test/test123.doc * @param loadType 设置路径加载方式。1-绝对路径,2-项目相对路径 * @return * @throws Exception */ public File createDocFile(String templateFilePath, Map<String, Object> dataMap, String exportFilePath, int loadType) { Template t = null; Configuration configuration = new Configuration(Configuration.VERSION_2_3_28); configuration.setDefaultEncoding("UTF-8"); Writer out = null; File outFile = new File(exportFilePath); try { templateFilePath = pathReplace(templateFilePath); String ftlPath = templateFilePath.substring(0, templateFilePath.lastIndexOf("/")); if (loadType == 1) { configuration.setDirectoryForTemplateLoading(new File(ftlPath)); // FTL文件所存在的位置 } else { configuration.setClassForTemplateLoading(this.getClass(), ftlPath);//以类加载的方式查找模版文件路径 } String ftlFile = templateFilePath.substring(templateFilePath.lastIndexOf("/") + 1); t = configuration.getTemplate(ftlFile); // 模板文件名 FileOutputStream fos = new FileOutputStream(outFile); OutputStreamWriter oWriter = new OutputStreamWriter(fos, "UTF-8"); out = new BufferedWriter(oWriter); t.process(dataMap, out); oWriter.flush(); out.flush(); oWriter.close(); } catch (Exception e) { logger.error("导出word文档出错", e); }finally { try { if (out != null) { out.close(); } } catch (IOException e) { logger.error("关闭Write对象出错", e); } } return outFile; } /** * 把路径的\替换成/ * @param path * @return */ private String pathReplace(String path) { while(path != null && path.contains("\\")) { path = path.replace("\\", "/"); } return path; } public static void main(String[] args) { // Map<String, Object> dataMap = new HashMap<String, Object>(); // getData(dataMap); // String templateFile = "C:\\luojie\\test\\chufashu.ftl"; // String exportFile = "C:\\luojie\\test\\bb.doc"; // // try { // ExportDotFile.getInstance().createDocFile(templateFile, dataMap, exportFile, 1); // } catch (Exception e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } } /** * 测试用的 * @param dataMap */ public static void getData(Map<String, Object> dataMap) { dataMap.put("tb111", "2019-11-07"); dataMap.put("tb112", "打架"); dataMap.put("tb113", "行为管理"); dataMap.put("tb114", "3"); dataMap.put("tb115", "不能打架,打输住院,打赢坐牢"); } }
总体效果已经出来了,写的不是很好,还望多多包涵。