本文内容:对freemarker 的介绍以及在springboot 中整合freemarker 以实现word 导出功能的代码实现。
1
介绍
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
FreeMarker是免费的,基于Apache许可证2.0版本发布。其模板编写为FreeMarker Template Language(FTL),属于简单、专用的语言。需要准备数据在真实编程语言中来显示,比如数据库查询和业务运算,之后模板显示已经准备好的数据。在模板中,主要用于如何展现数据,而在模板之外注意于要展示什么数据。
2
引入依赖
pom.xml
org.springframework.boot spring-boot-starter-freemarker
3
修改配置文件
application.properties
# 是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性。spring.freemarker.allow-request-override=false# 是否允许HttpSession属性覆盖(隐藏)控制器生成的同名模型属性。spring.freemarker.allow-session-override=false# 是否启用模板缓存。spring.freemarker.cache=false# 模板编码。spring.freemarker.charset=UTF-8# 是否检查模板位置是否存在。spring.freemarker.check-template-location=true# Content-Type value.spring.freemarker.content-type=text/html# 是否启用freemarkerspring.freemarker.enabled=true# 设定所有request的属性在merge到模板的时候,是否要都添加到model中.spring.freemarker.expose-request-attributes=false# 是否在merge模板的时候,将HttpSession属性都添加到model中spring.freemarker.expose-session-attributes=false# 设定是否以springMacroRequestContext的形式暴露RequestContext给Spring’s macro library使用spring.freemarker.expose-spring-macro-helpers=true# 是否优先从文件系统加载template,以支持热加载,默认为truespring.freemarker.prefer-file-system-access=true# 设定模板的后缀.spring.freemarker.suffix=.ftl# 设定模板的加载路径,多个以逗号分隔,默认: spring.freemarker.template-loader-path=classpath:/templates/# 设定FreeMarker keys.spring.freemarker.settings.template_update_delay=0spring.freemarker.settings.default_encoding=UTF-8#spring.freemarker.settings.classic_compatible=true
4
编写模板文件
新建word 模板
新建一个word文档wordLoading.doc,将模板内容替换成变量,这里变量要一次性写完如${user.userName}。
注意:如果变量和符号没有一次性写完,例如先写${},再统一加上变量名,这时当你打开xml的时候"${user.userName}"的“$”,“{}” ,“user.userName”就会分开,导出时会出错。
另存为xml 文件
将wordLoading.doc另存为xml 文件。
注意:这里选择的是2003 版本的,这样的模板可以兼容wps与office 。
打开wordLoading.xml 文件,Ctrl + F 查找 $ 字符,检查变量和符号是否正常。如果$ 分离开来,建议重新修改上一步的word 文档。
保存模板文件到项目中
将wordLoading.xml的后缀名改成ftl,即wordLoading.ftl 模板,将模板放到项目中去。这里我选择的是resources/template 目录。
5
编写工具类
DocumentHandler.java
public class DocumentHandler { // Configuration存储一些全局常量和常用设置 private Configuration configuration = null; // 构造函数生成实例并设置编码 @SuppressWarnings("deprecation") public DocumentHandler() { configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); } /** * * 导出word文档,导出到本地 * * @param tempName,要使用的模板 * * @param docName,导出文档名称 * * @param dataMap,模板中变量数据 * * @param outFile,输出文档路径 * */ @SuppressWarnings("deprecation") public boolean exportDoc(String tempName, Map, ?> dataMap, File outFile) { boolean status = false; // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载, configuration.setClassForTemplateLoading(this.getClass(), "/template"); Template t = null; try { // tempName.ftl为要装载的模板 t = configuration.getTemplate(tempName + ".ftl"); t.setEncoding("utf-8"); } catch (IOException e) { e.printStackTrace(); } Writer out = null; try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8")); status = true; } catch (Exception e1) { e1.printStackTrace(); } try { t.process(dataMap, out); out.close(); } catch (TemplateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return status; } /** * * 导出word文档,响应到请求端 * * @param tempName,要使用的模板 * * @param docName,导出文档名称 * * @param dataMap,模板中变量数据 * * @param resp,HttpServletResponse * */ @SuppressWarnings("deprecation") public boolean exportDoc(String tempName, String docName, Map, ?> dataMap, HttpServletResponse resp) { boolean status = false; ServletOutputStream sos = null; InputStream fin = null; if (resp != null) { resp.reset(); } // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。参数2为模板路径 configuration.setClassForTemplateLoading(this.getClass(), "/template"); Template t = null; try { // tempName.ftl为要装载的模板 t = configuration.getTemplate(tempName + ".ftl"); t.setEncoding("utf-8"); System.out.println(t.getName()); } catch (IOException e) { e.printStackTrace(); } // 输出文档路径及名称 ,以临时文件的形式导出服务器,再进行下载 String name = "temp" + (int) (Math.random() * 100000) + ".doc"; File outFile = new File(name); Writer out = null; try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8")); status = true; } catch (Exception e1) { e1.printStackTrace(); } try { t.process(dataMap, out); out.close(); } catch (TemplateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { fin = new FileInputStream(outFile); } catch (FileNotFoundException e) { e.printStackTrace(); } // 文档下载 resp.setCharacterEncoding("utf-8"); resp.setContentType("application/msword"); try { docName = new String(docName.getBytes("UTF-8"), "ISO-8859-1"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } resp.setHeader("Content-disposition", "attachment;filename=" + docName + ".doc"); try { sos = resp.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } byte[] buffer = new byte[512]; // 缓冲区 int bytesToRead = -1; // 通过循环将读入的Word文件的内容输出到浏览器中 try { while ((bytesToRead = fin.read(buffer)) != -1) { sos.write(buffer, 0, bytesToRead); } } catch (IOException e) { e.printStackTrace(); } finally { if (fin != null) try { fin.close(); } catch (IOException e) { e.printStackTrace(); } if (sos != null) try { sos.close(); } catch (IOException e) { e.printStackTrace(); } if (outFile != null) outFile.delete(); // 删除临时文件 } return status; } }
6
编写测试方法
FreemarkerController.java
@Controllerpublic class WordDownLoading { // localhost:8080/freemarker/exportWord @RequestMapping("exportWord") @ResponseBody public String freemaker(HttpServletRequest req,HttpServletResponse resp) { List
7
浏览器访问测试
启动springboot项目,使用浏览器访问以下网址:
localhost:8080/freemarker/exportWord
能下载exportWord.doc 文档即为成功。
至此,本文结束。欢迎各位关注我的公众号:暗星涌动。