版權聲明:本文為HaiyuKing原創文章,轉載請註明出處! 前言 這個方案只能在java中運行,無法在Android項目中運行。所以此方案是:APP將表單數據發送給後臺,後臺通過freemarker將表單數據根據模板ftl文件生成Word文件,然後返回給APP,由APP進行展現。 前期準備 1、下 ...
版權聲明:本文為HaiyuKing原創文章,轉載請註明出處!
前言
這個方案只能在java中運行,無法在Android項目中運行。所以此方案是:APP將表單數據發送給後臺,後臺通過freemarker將表單數據根據模板ftl文件生成Word文件,然後返回給APP,由APP進行展現。
前期準備
1、下載freemarker.jar文件
官網下載地址:https://freemarker.apache.org/freemarkerdownload.html
後續將freemarker.jar文件添加到項目中。
2、製作模板ftl文件
(1)先用office2003或更高版本word軟體編輯好word模版文件【版本要2003以上,2003以下的不支持另存為xml格式功能】
註意:
- 在word模板中寫入相對真實的數據【註意,不要使用英文,儘量使用中文、數字,見附錄1】;
- 對於對勾樣式的數據,在word模板文件中統一用安卓代替(後續需要通過java代碼傳入帶有對勾樣式的數據);
- 需要設置圖片的話,需要在word模板文件中放入真實的圖片占位;請儘量選擇小於50K的圖片,並且把圖片的大小和位置調整好。選擇小圖片的原因是避免xml文件過大導致打開時緩慢甚至卡死。
例子:
(2)另存為Word 2003 XML文檔
對於Word2016,另存為後會自動打開xml文件,所以需要先關閉xml文件,然後再使用FirstObject XML Editor軟體打開xml文件!
(3)下載FirstObject XML Editor軟體
下載FirstObject XML Editor軟體(免安裝版):下載地址:http://www.firstobject.com/dn_editor.htm
官網下載的軟體打開文件的時候可能會出現崩潰的問題。建議使用foxe_CHS.exe軟體進行編輯。下載地址見項目Demo下載地址。
(4)使用FirstObject XML Editor軟體將xml打開,將真實數據換成FreeMarker標記
首先進行“縮進排版”
查找真實數據,替換成FreeMarker標記,其實就是Map<String, Object>中key,如${writeDate},對應Map的key值就是writeDate。
替換成:
對於文本按照上面的方式進行替換,而對於圖片需要這樣替換:
圖片是以base64編碼存在的,且這些編碼放在<w:binData>標簽之中。將這些base64編碼使用占位符代替,然後java代碼中將圖片生成base64編碼,傳入值就能正常顯示了。
替換成
(5)然後保存,直接將文件尾碼修改為.ftl(FreeMarker模板)
註意:一定不要用word打開ftl模板文件查看,否則xml內容會發生變化,導致前面的工作白做了;可以使用EditPlus打開查看。
使用步驟
一、項目組織結構圖
二、導入步驟
1、在項目中引入freemarker.jar
2、將製作的模板文件leaveTemplet.ftl和圖片資源複製到D:/temp目錄下
3、將DocumentHandler.java文件複製到項目中
package com.why.main; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.HashMap; import java.util.Map; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import sun.misc.BASE64Encoder; /** * 生成Doc文檔 */ public class DocumentHandler { //測試 public static void main(String[] args) { DocumentHandler documentHandler = new DocumentHandler(); documentHandler.createDoc(); } // 配置實例:只需要一個實例(單例模式) private Configuration configuration = null; private String tempDirPath = "D:/temp"; public DocumentHandler() { // 通過Freemaker的Configuration讀取相應的ftl configuration = new Configuration(Configuration.VERSION_2_3_28); configuration.setDefaultEncoding("UTF-8");// 設置預設編碼方式 } /** * 生成DOC文檔 */ public void createDoc() { // 要填入模本的數據文件 Map<String,Object> dataMap = new HashMap<String,Object>(); getData(dataMap); // 設置模本裝置方法和路徑,FreeMarker支持多種模板裝載方法。可以重servlet,classpath,資料庫裝載, // 如果模板是放在程式代碼的包下麵 //configuration.setClassForTemplateLoading(this.getClass(),"../"); //如果放到伺服器目錄中,則使用下麵的代碼 try { configuration.setDirectoryForTemplateLoading(new File(tempDirPath)); } catch (IOException e2) { e2.printStackTrace(); } //這裡要設置取消使用Local語言環境 configuration.setLocalizedLookup(false); Template template = null; try { // leaveTemplet.ftl為要裝載的模板 template = configuration.getTemplate("leaveTemplet.ftl","UTF-8"); } catch (IOException e) { e.printStackTrace(); } // 輸出文檔路徑及名稱 File dir = new File(tempDirPath); File outFile = new File(tempDirPath + "/請假條.doc"); if (!dir.isDirectory()) { dir.mkdir(); if (!outFile.exists()) { try { outFile.createNewFile(); } catch (IOException e) { System.out.println("創建文件失敗"); e.printStackTrace(); } } } Writer out = null; try { try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } catch (FileNotFoundException e1) { System.out.println("輸出文件失敗"); e1.printStackTrace(); } try { template.process(dataMap, out); System.out.println("it's success!"); } catch (TemplateException e) { System.out.println("生成失敗"); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 註意dataMap里存放的數據Key值要與模板中的參數相對應 */ private void getData(Map<String,Object> dataMap) { String imgBase64Str = getImageStr(tempDirPath + "/leaderopinion_img.png"); // 使用String的有參構造方法 dataMap.put("writeDate","2018年10月13日");//填寫日期 dataMap.put("name","HaiyuKing");//姓名 dataMap.put("dept","移動組");//部門 dataMap.put("leaveType","☑倒休 √年假 ✔事假 ☐病假 ☐婚假 ☐產假 ☐其他");//請假類型 dataMap.put("leaveReason","倒休休息兩天");//請假理由 dataMap.put("leaveStartDate","2018年10月13日上午");//請假開始日期 dataMap.put("leaveEndDate","2018年10月14日下午");//請假結束日期 dataMap.put("leaveDay","2");//請假天數 dataMap.put("leaveLeader","同意");//直屬領導意見 dataMap.put("leaveDeptLeaderImg",imgBase64Str);//部門領導意見 } /** * 獲取圖片的base64值*/ private String getImageStr(String imgFile) { InputStream in = null; byte[] data = null; try { in = new FileInputStream(imgFile); data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); } }DocumentHandler.java
註意:Map數據中的key值,對應ftl文件中的${xxxx}這裡面的xxxx值。
4、運行
5、效果
附錄
1、Word模板中輸入真實數據的技巧
1、不要使用英文;
2、如果想要保證一個整體,不要將中文、數字、標點符號一起使用(這裡指占位區域);
3、日期想要作為一個整體,不要數字+中文輸入,而是通過Enter鍵輸入;
下麵記錄的是不同輸入的效果(使用FirstObject XML Editor軟體打開xml文件)
使用英文:
使用數字:
使用中文:
日期採用數字+中文:
日期採用Enter鍵輸入:
中文+標點符號:
參考資料
沫沫金:使用Java模版引擎FreeMarker生成複雜的Word文檔
FreeMaker解析Word模板(含圖片)生成Word文檔
項目demo下載地址
鏈接:https://pan.baidu.com/s/19aPNIYWXt5GMN_KDQjFCRA 提取碼:eo0n