1. 程式人生 > >SpringMVC中使用FreeMarker生成Word文件

SpringMVC中使用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>