在項目中不免和各類數據報表打交道,如導出XX申請表,登記表,推薦表之類。就能夠經過現有信息導出Word文檔。基於Java語言來導出Word文檔的方式也有不少種,如Jacob,Apache POI,Freemarker,PageOffice,java2word 等等。。。。java
在這裏將經過Freemarker這個模板引擎來實現導出 Word,項目不限於Swing,SSH,SSM,Spring Boot 之類的。。。。。。。。。。mysql
Freemarker介紹
首先說一下Freemarker是個什麼東西:程序員
FreeMarker是一款模板引擎: 即一種基於模板和要改變的數據, 並用來生成輸出文本(HTML網頁、電子郵件、配置文件、源代碼等)的通用工具。 它不是面向最終用戶的,而是一個Java類庫,是一款程序員能夠嵌入他們所開發產品的組件。
FreeMarker是免費的,基於Apache許可證2.0版本發佈。其模板編寫爲FreeMarker Template Language(FTL),屬於簡單、專用的語言。須要準備數據在真實編程語言中來顯示,好比數據庫查詢和業務運算, 以後模板顯示已經準備好的數據。在模板中,主要用於如何展示數據, 而在模板以外注意於要展現什麼數據 。
------百度百科web總的來講:模板 + 數據模型 = 輸出spring
看不懂也不要緊,看一個簡單的例子:一般咱們在Java Web開發的時候,實現一個JSP頁面的輸出須要編寫一個JSP文件《xxxx.jsp》,實際上這個JSP文件主要包含了兩部份內容:
HTML+CSS+JavaScript構成的頁面框架 + 用來動態顯示數據庫數據的Java代碼(通常來講直接寫Java代碼是很是不美觀且修改複雜的事情,不符合MVC開發模式,因此會用JSTL標籤來代替直接寫Java代碼)
sql
在Freemarker中也有一套相似於JSTL的標籤,其實簡單來講freemarker就是用來代替jsp來作處理,由於咱們若是用JSP的話,是須要WEB容器的,如tomcat,JSP在第一次執行的時候會被編譯轉換成Servlet類,以後的每次修改都要編譯和轉換。而FreeMarker模板技術並不存在編譯和轉換的問題,而且與容器無關。咱們在非web項目下也不必再引入一個web容器了。
數據庫
示例用的項目搭建
下面進入正題:
首先建立一個項目,在這裏的項目能夠爲Java swing,Javaweb的SSM,Springboot等項目都是沒問題的。我仍是直接用SpringBoot項目實現這個功能了。
首先用IDEA建立一個Spring Boot項目編程
用其餘IDE的也能夠在https://start.spring.io網站上面直接下載一個springboot項目瀏覽器
下一步填完信息,這裏我用默認的信息了tomcat
開始選擇所須要的插件依賴,也就是jar包,都是經過maven管理的,上圖有說明
1.
2. 選擇Spring Web,就是SpringMVC
3. 選擇用哪一個模板引擎,這裏用Freemarker
4. 選擇數據庫框架,這裏用mybaits+mysql
5. 下一步,選擇項目路徑,點擊完成就能夠了
Freemarker主要依賴的jar包是
# Springboot 提供的 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> # 也能夠選擇其餘版本如: <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> # 網址: https://mvnrepository.com/artifact/org.freemarker/freemarker
FTL模板製做
項目搭建好以後,開始製做FTL模板,此次選擇一個XXX推薦表來實現:
如Word文檔:
開始製做模板:
首先,咱們須要在模板上面添加佔位符,${XXXXX}。這裏全用了拼音簡寫
添加好佔位符以後,將該Word文檔另存爲XML格式的文件
修改一下文件名稱,保存
即獲得一個XML文件
打開觀察一下,正常
接下來,利用文本編輯器打開這個文件,如Notepad++、Sublime Text、EditPlus、UltraEdit什麼都行,我這裏用VSCode。如圖
直接搜索前面添加的佔位符${xxxx},這裏可能會出現一些問題,如符號和花括號分離,這時候就得對它進行修改,恢復原樣
修改後
等檢查一遍沒問題以後呢,就修改完成了,開始進入下一步修改文件後綴
代碼編寫
接下來開始代碼編寫部分,通常來講這裏都是用數據庫的數據做爲導出數據。但因爲麻煩就不寫數據庫部分了,在這裏直接用提交表單的數據來進行導出。
1.回到項目上,新建一個實體類,TableData.java ,將佔位符標識做爲類屬性,生成get、set方法。。。。。發現院系YX和郵箱YX重複了,修改郵箱爲DZYX
2. 新建簡單的測試頁面
3. 編寫導出工具類
首先將實體類封裝爲導出數據所需的map,建立數據模型
**注意:
**在這裏直接用的是封裝實體類,因此在模板裏面也須要改一下佔位符,在前面加上對象名${DZYX}
變爲${tableData.DZYX}
,用文本編輯器一鍵搜索${
替換便可 )
編寫方法,建立freeMarker配置實例,建立數據模型,加載模板,輸出
/** * 導出Word文件 * * @param tableData * @param request * @param response * @throws Exception */ public InputStreamSource exportToWord(TableData tableData, HttpServletRequest request, HttpServletResponse response) throws Exception { // 糾正編碼 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("utf-8"); // ** 初始化配置文件**//* Configuration configuration = new Configuration(); // ** 設置編碼 **//* configuration.setDefaultEncoding("utf-8"); // ** ftl文件的路徑**//* String fileDirectory = "D:\\"; //將模板文件放到了D盤下 // 加載模板文件 configuration.setDirectoryForTemplateLoading(new File(fileDirectory)); // 加載模板,經過Word轉XML文件轉換過來的 Template template = configuration.getTemplate("FreemarkerTest.ftl"); // 準備數據 Map<String, Object> dataMap = data(tableData); // 指定輸出word文件的路徑 // 調用工具類WordUtils的createDoc方法生成Word文檔 InputStreamSource file = UtilTest.createDoc(dataMap, template); InputStream fin = file.getInputStream(); ServletOutputStream out; response.setContentType("application/msword"); // 設置瀏覽器如下載的方式處理該文件 response.setHeader("content-disposition", "attachment;filename=document.doc"); out = response.getOutputStream(); // 緩衝區 byte[] buffer = new byte[512]; int bytesToRead; // 經過循環將讀入的Word文件的內容輸出到瀏覽器中 while ((bytesToRead = fin.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } fin.close(); if (out != null) { out.close(); } return file; }
建立word文件
/** * 建立word文件 * * @param dataMap * @param template * @return * @throws TemplateException * @throws IOException */ public static InputStreamSource createDoc(Map<String, Object> dataMap, Template template) throws TemplateException, IOException { //生成隨機的合同名稱 StringWriter out1 = new StringWriter(); Writer out = new BufferedWriter(out1, 10240); //將數據輸出到模板 template.process(dataMap, out); out.close(); out1.close(); return new ByteArrayResource(out1.toString().getBytes(StandardCharsets.UTF_8)); }
4.編寫控制層
運行項目,跳到測試頁面,填寫相應信息
提交表單,會彈出下載框
將文件下載到本地,打開,能夠看到已經填充完成,
至此,基於Java和freemarker實現的Word文件導出功能已經實現了
再回顧一下步驟:
1.編輯好格式的Word文檔 1份
2.將Word文檔裏須要填充的地方加上佔位符${xxxx}
3.將編輯好佔位符的文檔另存爲XML格式Word 2003 XML文檔,並重命名,用英文命名
4.利用文本編輯器打開該XML文件檢查,搜索第二步編輯的佔位符,遇到$和 { } 分離的狀況則進行修改。檢查完畢後保存退出。
5.將檢查完成的XML文件修改後綴名爲 xxx.ftl
6.模板編輯完成
7.創建Java項目,引入jar包
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency>
8.編寫對應數據的實體類
9.編寫測試頁面
10.編寫導出的工具類(核心
),並修改模板對應的佔位符,有須要的話
11.編寫控制層
12.測試
代碼
項目代碼–工具類
package com.hh.onlinelearning.util; import com.hh.onlinelearning.entity.TableData; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.InputStreamSource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; public class UtilTest { /** * 導出Word文件 * * @param tableData * @param request * @param response * @throws Exception */ public InputStreamSource exportToWord(TableData tableData, HttpServletRequest request, HttpServletResponse response) throws Exception { // 糾正編碼 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("utf-8"); // ** 初始化配置文件**//* Configuration configuration = new Configuration(); // ** 設置編碼 **//* configuration.setDefaultEncoding("utf-8"); // ** ftl文件的路徑**//* String fileDirectory = "D:\\"; // 加載模板文件 configuration.setDirectoryForTemplateLoading(new File(fileDirectory)); // 加載模板,經過Word轉XML文件轉換過來的 Template template = configuration.getTemplate("FreemarkerTest.ftl"); // 準備數據 Map<String, Object> dataMap = data(tableData); // 指定輸出word文件的路徑 // 調用工具類WordUtils的createDoc方法生成Word文檔 InputStreamSource file = UtilTest.createDoc(dataMap, template); InputStream fin = file.getInputStream(); ServletOutputStream out; response.setContentType("application/msword"); // 設置瀏覽器如下載的方式處理該文件 response.setHeader("content-disposition", "attachment;filename=document.doc"); out = response.getOutputStream(); // 緩衝區 byte[] buffer = new byte[512]; int bytesToRead; // 經過循環將讀入的Word文件的內容輸出到瀏覽器中 while ((bytesToRead = fin.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } fin.close(); if (out != null) { out.close(); } return file; } /** * 構造數據,key-value * * @param tableData * @return */ public Map<String, Object> data(TableData tableData) { Map<String, Object> dataMap = new HashMap<>(); dataMap.put("tableData", tableData); return dataMap; } /** * 建立word文件 * * @param dataMap * @param template * @return * @throws TemplateException * @throws IOException */ public static InputStreamSource createDoc(Map<String, Object> dataMap, Template template) throws TemplateException, IOException { //生成隨機的合同名稱 StringWriter out1 = new StringWriter(); Writer out = new BufferedWriter(out1, 10240); //將數據輸出到模板 template.process(dataMap, out); out.close(); out1.close(); return new ByteArrayResource(out1.toString().getBytes(StandardCharsets.UTF_8)); } }