前言
最近在項目中,因客戶要求,將頁面內容(如合同協議)導出成word,在網上翻了好多,感覺太亂了,不過最后還是較好解決了這個問題。
準備材料
1.word原件 2.編輯器(推薦Firstobject free XML editor)
實現步驟
1.用Microsoft Office Word打開word原件;
2.把需要動態修改的內容替換成***,如果有圖片,盡量選擇較小的圖片幾十K左右,并調整好位置;
3.另存為,選擇保存類型Word 2003 XML 文檔(*.xml)【這里說一下為什么用Microsoft Office Word打開且要保存為Word 2003XML,本人親測,用WPS找不到Word 2003XML選項,如果保存為Word XML,會有兼容問題,避免出現導出的word文檔不能用Word 2003打開的問題】;
4.用Firstobject free XML editor打開文件,選擇Tools下的Indent【或者按快捷鍵F8】格式化文件內容。左邊是文檔結構,右邊是文檔內容;
5. 將文檔內容中需要動態修改內容的地方,換成freemarker的標識。其實就是Map<String, Object>中key,如${landName};
6.在加入了圖片占位的地方,會看到一片base64編碼后的代碼,把base64替換成${image},也就是Map<String, Object>中key,值必須要處理成base64;
代碼如:<w:binData w:name="wordml://自定義.png" xml:space="preserve">${image}</w:binData>
注意:“>${image}<”這尖括號中間不能加任何其他的諸如空格,tab,換行等符號。
如果需要循環,則使用:<#list maps as map></#list> maps是Map<String, Object>中key,值為數組,map為自定義;
7. 標識替換完之后,模板就弄完了,另存為.ftl后綴文件即可。注意:一定不要用word打開ftl模板文件,否則xml內容會發生變化,導致前面的工作白做了。
代碼實現
工具類WordUtils.Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URLEncoder; import java.util.Date; import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import freemarker.template.Configuration; import freemarker.template.Template; public class WordUtils { //配置信息,代碼本身寫的還是很可讀的,就不過多注解了 private static Configuration configuration = null ; //這里注意的是利用WordUtils的類加載器動態獲得模板文件的位置 // private static final String templateFolder = WordUtils.class.getClassLoader().getResource("../../").getPath() + "WEB-INF/templetes/"; private static final String templateFolder = "H:/我的項目/lm/lm/web/src/main/webapp/WEB-INF/templates" ; static { configuration = new Configuration(); configuration.setDefaultEncoding( "utf-8" ); try { configuration.setDirectoryForTemplateLoading( new File(templateFolder)); } catch (IOException e) { e.printStackTrace(); } } private WordUtils() { throw new AssertionError(); } public static void exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response, Map map,String title,String ftlFile) throws IOException { Template freemarkerTemplate = configuration.getTemplate(ftlFile); File file = null ; InputStream fin = null ; ServletOutputStream out = null ; try { // 調用工具類的createDoc方法生成Word文檔 file = createDoc(map,freemarkerTemplate); fin = new FileInputStream(file); response.setCharacterEncoding( "utf-8" ); response.setContentType( "application/msword" ); // 設置瀏覽器以下載的方式處理該文件名 String fileName = title+DateUtil.formatDateDetailTime( new Date()) + ".doc" ; response.setHeader( "Content-Disposition" , "attachment;filename=" .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8" )))); out = response.getOutputStream(); byte [] buffer = new byte [ 512 ]; // 緩沖區 int bytesToRead = - 1 ; // 通過循環將讀入的Word文件的內容輸出到瀏覽器中 while ((bytesToRead = fin.read(buffer)) != - 1 ) { out.write(buffer, 0 , bytesToRead); } } finally { if (fin != null ) fin.close(); if (out != null ) out.close(); if (file != null ) file.delete(); // 刪除臨時文件 } } private static File createDoc(Map<?, ?> dataMap, Template template) { String name = "sellPlan.doc" ; File f = new File(name); Template t = template; try { // 這個地方不能使用FileWriter因為需要指定編碼類型否則生成的Word文檔會因為有無法識別的編碼而無法打開 Writer w = new OutputStreamWriter( new FileOutputStream(f), "utf-8" ); t.process(dataMap, w); w.close(); } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } return f; } } |
Action
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@RequestMapping ( "/exportSellPlan" ) public @ResponseBody void exportSellPlan(Long id){ Calendar calendar = Calendar.getInstance(); // 取當前日期。 if (id!= null ){ SellPlan plan=sellService.getSellPlanInfo(id); //獲得數據 Map<String, Object> map = new HashMap<String, Object>(); map.put( "bYear" , plan.getBusinessYear()!= null ?plan.getBusinessYear(): "" ); map.put( "lYear" , plan.getLiveYear()!= null ?plan.getLiveYear(): "" ); map.put( "leader" ,plan.getLeader()!= null ?plan.getLeader(): "" ); map.put( "phone" , plan.getPhone()!= null ?plan.getPhone(): "" ); map.put( "curYear" , calendar.get(Calendar.YEAR)+ "" ); map.put( "image" , getImageBase(plan.getPositionImage())); try { WordUtils.exportMillCertificateWord(getRequest(),getResponse(),map, "方案" , "sellPlan.ftl" ); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
Base64處理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//獲得圖片的base64碼 @SuppressWarnings ( "deprecation" ) public String getImageBase(String src) { if (src== null ||src== "" ){ return "" ; } File file = new File(getRequest().getRealPath( "/" )+src.replace(getRequest().getContextPath(), "" )); if (!file.exists()) { return "" ; } InputStream in = null ; byte [] data = null ; try { in = new FileInputStream(file); } catch (FileNotFoundException e1) { e1.printStackTrace(); } try { data = new byte [in.available()]; in.read(data); in.close(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); } |
Javascript
1
|
window.location.href= "<%=path%>/exportSellPlan?id=" rel= "external nofollow" + id; |
結束語
如果對Freemarker標簽不熟的,可以在網上先學習下,了解文檔結構。
相關鏈接
Firstobject free XML editor下載地址:http://www.firstobject.com/dn_editor.htm
freemarker 官網:http://freemarker.org/
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.cnblogs.com/zwqh/p/7182953.html?utm_source=tuicool&utm_medium=referral