FreeMarker生成Word文档

FreeMarker简介: 
FreeMarker是一款模板引擎:即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具,它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。 
FreeMarker是免费的,基于Apache许可证2.0版本发布。其模板编写为FreeMarker Template Language(FTL),数据简单、专用的语言。需要准备数据在真实编程语言中来显示,比如数据库查询和业务运算,之后模板显示已经准备好的数据。在模板中,主要用于如何展示数据,而在模板之外注意于要展示什么数据。

SpringMVC是啥在这就不介绍了。

这实例主要是完成使用FreeMarker在SpringMVC框架中生成word文档下载。

1、实例是maven工程,工程对jar包的依赖,pom.xml中主要的依赖是对springMVC和freemarker的包依赖:

<properties>
        <!-- spring版本号 -->
        <spring.version>3.2.8.RELEASE</spring.version> <!-- junit版本号 --> <junit.version>4.10</junit.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- freemarker依赖 --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency> <!-- 添加Spring依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!--spring单元测试依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <!-- jstl标签支持 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Servlet核心包 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!--JSP --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> </dependencies>

2、SringMV配置 
applicationContext.xml的配置,这里没有其他复杂的配置,jdbc等,主要为测试FreeMarker的整合:

<!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.zhihua.controller.*"/> <context:annotation-config/>

web.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 配置编码方式过滤器 ,注意一点,要配置所有的过滤器,最前面 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>false</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> 

接下来是SpringMVC整合FreeMarker最主要的配置了,spring-mvc.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- springmvc 注解驱动 --> <mvc:annotation-driven /> <context:component-scan base-package="com.zhihua.*" /> <!-- 访问静态资源 --> <mvc:default-servlet-handler /> <!-- 配置试图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/"></property> <!-- 后缀 --> <property name="suffix" value=".jsp"></property> <property name="order" value="1"/> </bean> <import resource="classpath:applicationContext.xml" /> <!-- FreeMarker配置 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/> <property name="contentType" value="text/html; charset=utf-8"/> <property name="cache" value="true" /> <property name="suffix" value=".ftl" /> <property name="order" value="0"/><!-- 配置视图解析的顺序 --> </bean> <bean id="freeMarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <!-- 模板的根目录 --> <property name="templateLoaderPath" value="/static/templates/"/><!-- freemark模板存放的位置 --> <!-- 编码格式 --> <property name="defaultEncoding" value="utf-8"/><!-- freemark编码格式 --> <property name="freemarkerSettings"> <props> <prop key="template_update_delay">1</prop><!--刷新模板的周期,单位为秒 --> </props> </property> </bean> </beans> 

3、maven工程的目录,其中com.zhihua.templates包中存放的模板文件,例如本实例中的resume.ftl文件:

这里写图片描述

4、我们所需要的模板.ftl文件是从哪里来的呢?(本例中的resume.ftl)其中很简单,FreeMarker是模板引擎,所以我们首先要一个模板,生成word文档当然也不例外,我们先新建一个word文件,然后把需要的改变的数据用类似${xxxx}形式当做占位符。

这里写图片描述

把该word文档另存为XML文件:

这里写图片描述

另存后建议用用Editplus、Notepad++、Sublime等工具打开查看一下,因为有的时候你写的占位符可能会被拆开(可能会出现类似为${xxxx, xxxxx.... .}形式的拆分,要修改成${}形式),用文件工具打开后,可能回出现未格式化的情况

这里写图片描述

建议使用工具格式化一下,也方便我们之后修改那些占位符被拆开的问题,不然我们一个个查找是很繁琐的一件事(个人使用Notepad++ XML格式化插件,这个百度一下有插件安装方式)。

5、好了,前期的准备工作都完成了,现在开始功能的实现了。 
工具类代码:

package com.zhihua.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.Writer; import java.util.HashMap; import java.util.Map; import freemarker.template.Configuration; import freemarker.template.Template; public class Resume_Word { private static Configuration configuration = null; private static Map<String,Template> allTemplate = null; static{ configuration = new Configuration(Configuration.VERSION_2_3_0); configuration.setDefaultEncoding("UTF-8"); configuration.setClassForTemplateLoading(Resume_Word.class, "/com/zhihua/templates"); // try { // configuration.setDirectoryForTemplateLoading(new File("E:\\")); // } catch (IOException e1) { // e1.printStackTrace(); // } allTemplate = new HashMap<String,Template>(); try{ allTemplate.put("test", configuration.getTemplate("resume.ftl")); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException(e); } } private Resume_Word(){ } public static File createDoc(Map<?,?> dataMap,String type){ String name = "temp"+(int)(Math.random()*100000)+".doc"; File f = new File(name); Template t = allTemplate.get(type); try{ //这个地方不能使用FileWriter因为需要指定编码类型否则声场的word文档会因为有无法识别的编码而无法打开 Writer w = new OutputStreamWriter(new FileOutputStream(f),"utf-8"); t.process(dataMap,w); w.close(); }catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e); } return f; } } 

封装的实体类:

package com.zhihua.entity;

public class Resume {

    private String name;//姓名
    private String sex;//性别 private String birthday;//出生日期 private String photo;//照片 private String native_place;//籍贯 private String nation;//民族 private String ps;//身体状况 private String graduate_school;//毕业学校 private String political_status;//政治面貌 private String height;//身高 private String foreign;//外语程度 private String education;//学历 private String business;//曾任职位 private String profession;//专业 private String speciality;//特长 private String graduation_time;//毕业时间 private String phone;//联系电话 private String postalcode;//邮政编码 private String address;//家庭地址 private String personal_website;//个人网站 private String email;//E—mail private String course;//主修课程 private String resume;//个人简历 private String technology;//熟悉技术 private String characteristic;//个人特点 private String ability;//应聘岗位及个人能力 private String practice;//社会实践经历 public Resume(){ } //省略getting和setting方法.... ....... }

controller代码:

package com.zhihua.controller;

import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.zhihua.entity.Resume; import com.zhihua.entity.User; import com.zhihua.util.Resume_Word; import com.zhihua.util.WordGenerator; @Controller @RequestMapping("/freemarker") public class FreeMarkerController { //测试freeMarker @RequestMapping("/index.html") public String Index(Model model){ model.addAttribute("message","freemark这是主页"); return "hello"; } @RequestMapping("/downResumeDoc") public String downResumeDoc(HttpServletRequest request,HttpServletResponse response,Resume resume) throws IOException{ request.setCharacterEncoding("utf-8"); Map<String,Object> map = new HashMap<String,Object>(); /*Enumeration<String> paramNames = request.getParameterNames(); //通过循环将表单参数放入键值对映射中 while(paramNames.hasMoreElements()){ String key = paramNames.nextElement(); String value = request.getParameter(key); map.put(key, value); }*/ //给map填充数据 map.put("name",resume.getName()); map.put("sex", resume.getSex()); map.put("native_place",resume.getNative_place()); map.put("nation", resume.getNation()); map.put("ps", resume.getPs()); map.put("birthday",resume.getBirthday()); map.put("photo","1"); map.put("political_status",resume.getPolitical_status()); map.put("height",resume.getHeight()); map.put("foreign",resume.getForeign()); map.put("graduate_school",resume.getGraduate_school()); map.put("education",resume.getEducation()); map.put("business",resume.getBusiness()); map.put("profession",resume.getProfession()); map.put("speciality",resume.getSpeciality()); map.put("phone",resume.getPhone()); map.put("graduation_time",resume.getGraduation_time()); map.put("address",resume.getAddress()); map.put("postalcode",resume.getPostalcode()); map.put("personal_website",resume.getPersonal_website()); map.put("email",resume.getEmail()); map.put("course",resume.getCourse()); map.put("resume",resume.getResume()); map.put("technology",resume.getTechnology()); map.put("characteristic",resume.getCharacteristic()); map.put("ability",resume.getAbility()); map.put("practice",resume.getPractice()); //提示:在调用工具类生成Word文档之前应当检查所有字段是否完整 //否则Freemarker的模板殷勤在处理时可能会因为找不到值而报错,这里暂时忽略这个步骤 File file = null; InputStream fin = null; ServletOutputStream out = null; try{ //调用工具类WordGenerator的createDoc方法生成Word文档 file = Resume_Word.createDoc(map, "resume"); fin = new FileInputStream(file); response.setCharacterEncoding("utf-8"); response.setContentType("application/msword"); response.addHeader("Content-Disposition", "attachment;filename=resume.doc"); out = response.getOutputStream(); byte[] buffer = new byte[1024];//缓冲区 int bytesToRead = -1; // 通过循环将读入的Word文件的内容输出到浏览器中 while((bytesToRead = fin.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } }catch(Exception ex){ ex.printStackTrace(); } finally{ if(fin != null) fin.close(); if(out != null) out.close(); if(file != null) file.delete(); // 删除临时文件 } return null; } } 

JSP页面代码:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'downDoc.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <style type="text/css"> * { font-family: "微软雅黑"; } .textField { border: none; /* border-bottom: 1px solid gray; */ text-align: center; } #file { border: 1px solid black; width: 80%; margin: 0 auto; } h1 input { font-size: 72px; } td textarea { font-size: 14px; } .key { width: 125px; font-size: 20px; } .photo{ border: 1px solid black; width: 80%; margin: 0 auto; } </style> </head> <body> <form action='<c:url value="/freemarker/downResumeDoc"/>' method="post"> <div id="file" align="center"> <h1><input type="text" class="textField" value="个人简历"/></h1> <hr/> <table style="border-collapse:separate; border-spacing:0px 10px;" id="searchTable" border="1"> <tr> <td class="key">姓&nbsp;&nbsp;名:</td> <td><input type="text" name="name" class="textField"/></td> <td class="key">性&nbsp;&nbsp;别:</td> <td><input type="text" name="sex" class="textField"/></td> <td class="key">出生日期:</td> <td><input type="text" name="birthday" class="textField"/></td> <td rowspan="3" width="150px" align="center"> <a href="" src="">上传照片</a> </td> </tr> <tr> <td class="key">籍&nbsp;&nbsp;贯:</td> <td><input type="text" name="native_place" class="textField"/></td> <td class="key">民族:</td> <td><input type="text" name="nation" class="textField"/></td> <td class="key">身体状况:</td> <td><input type="text" name="ps" class="textField"/></td> </tr> <tr> <td class="key">政治面貌:</td> <td><input type="text" name="political_status" class="textField"/></td> <td class="key">身高:</td> <td><input type="text" name="height" class="textField"/></td> <td class="key">外语程度:</td> <td><input type="text" name="foreign" class="textField"/></td> </tr> <tr> <td class="key">所在学院:</td> <td><input type="text" name="graduate_school" class="textField"/></td> <td class="key">学历:</td> <td><input type="text" name="education" class="textField"/></td> <td class="key">曾任职务:</td> <td colspan="2"><input type="text" name="business" class="textField"/></td> </tr> <tr> <td class="key">所学专业:</td> <td colspan="2"><input type="text" name="profession" class="textField"/></td> <td class="key" colspan="2">特长:</td> <td colspan="2"><input type="text" name="speciality" class="textField"/></td> </tr> <tr> <td class="key">毕业时间:</td> <td colspan="2"><input type="text" name="graduation_time" class="textField"/></td> <td class="key" colspan="2">联系电话:</td> <td colspan="2"><input type="text" name="phone" class="textField"/></td> </tr> <tr> <td rowspan="3" class="key">家庭住址:</td> <td rowspan="3" colspan="2"> <textarea rows="8" cols="35" name="address"></textarea> </td> <td colspan="2" class="key">邮政编码:</td> <td colspan="2"><input type="text" name="postalcode" class="textField"/></td> </tr> <tr> <td colspan="2" class="key">个人网站:</td> <td colspan="2"><input type="text" name="personal_website" class="textField"/></td> </tr> <tr> <td colspan="2" class="key">E-mail:</td> <td colspan="2"><input type="text" name="email" class="textField"/></td> </tr> <tr> <td class="key">主修课程:</td> <td colspan="6"><input type="text" name="course" class="textField"/></td> </tr> <tr> <td class="key">个人简历:</td> <td colspan="6"><input type="text" name="resume" class="textField"/></td> </tr> <tr> <td class="key">熟悉领域:</td> <td colspan="6"><input type="text" name="technology" class="textField"/></td> </tr> <tr> <td class="key">个人特点:</td> <td colspan="6"><input type="text" name="characteristic" class="textField"/></td> </tr> <tr> <td class="key" colspan="2">应聘岗位及个人特长和能力:</td> <td colspan="5"><input type="text" name="ability" class="textField"/></td> </tr> <tr> <td class="key" colspan="2">社会实践经历:</td> <td colspan="5"><input type="text" name="practice" class="textField"/></td> </tr> <tr> <td colspan="7" style="text-align: center;"> 相信您的信任与我的实力将为我们带来共同的成功! 希望我能为咱们公司贡献自己的力量! </td> </tr> </table> </div> <div align="center" style="margin-top:15px;"> <input type="submit" value="保存Word文档" /> </div> </form> </body> </html>

因为resume.ftl文件中的内容太多了,为了避免篇幅过大,这里就不贴出来了,如果按照前面的步骤,获得resume.ftl不难的。

6、代码部分都准备好了, 接下来就是演示部分 
将该工程发布到tomcat中,运行

这里写图片描述

填写好全部信息(说一下我碰到的问题,我发现如果.ftl文件中的所有占位符如果没有全部填充数据的话,freemarker不能解析出来我们的想要的结果,后台会报错,改占位符的为值为null或者是miss,这是不允许的!) 
这里写图片描述

打开下载的word文件,和原本word文档进行比较一下 
这里写图片描述

自此本实例结束!原文地址:https://blog.csdn.net/hundan_520520/article/details/54848165

猜你喜欢

转载自www.cnblogs.com/ggband/p/8980851.html