使用freemarker匯出html格式的word(調整頁邊距,頁面檢視,正常表格樣式)
阿新 • • 發佈:2018-11-04
RT,耗費了博主半個月的時間才擠出來的成果,在此記錄下開發過程。
一、建立freemark模板
首先在web專案中指定目錄下建立一個HTML格式的freemarker模板:
<!DOCTYPE html> <html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"> <head> <meta charset="UTF-8"> <!--[if gte mso 9]> <xml> <w:WordDocument> <w:View>Print</w:View> <w:TrackMoves>false</w:TrackMoves> <w:TrackFormatting/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-US</w:LidThemeOther> <w:LidThemeAsian>ZH-CN</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:DontVertAlignCellWithSp/> <w:DontBreakConstrainedForcedTables/> <w:DontVertAlignInTxbx/> <w:Word11KerningPairs/> <w:CachedColBalance/> <w:UseFELayout/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="--"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr> </w:WordDocument> </xml><![endif]--> <style> <!-- /*Page Definitions*/ @page WordSection1 { size: 595.3pt 841.9pt; margin: 72.0pt 1.0cm 72.0pt 1.0cm; mso-header-margin: 42.55pt; mso-footer-margin: 49.6pt; mso-paper-source: 0; } div.WordSection1 { page: WordSection1 } --> </style> <title>匯出html格式Word演示</title> </head> <body> <div class="WordSection1"> <div> <h1 style="font-size: 32px;font-weight: bold;padding:0px 4px 0px 0px;text-align:center;margin:0px 0px 20px;"> <span style="font-size: 22pt;font-family: 宋體,SimSun;"><strong>Word匯出演示</strong></span> </h1> </div> <p style="text-indent: 32px"> <span style="font-size:21px;font-family: 宋體">${basicShow!}</span> </p> <table class="MsoNormalTable" style="mso-cellspacing: 0cm;mso-table-layout-alt: fixed; border:outset black 1.0pt;mso-border-alt: outset black .75pt;mso-yfti-tbllook:1184;mso-padding-alt: 0cm 0cm 0cm 0cm" border="1" cellpadding="0" cellspacing="0" style="border-color:black;"> <tbody> <tr style="height:39px" class="firstRow"> <td width="120" style="padding: 0px 7px;"> <p style="text-align: center"> <strong><span style="font-size: 16px;font-family: 仿宋;">姓名</span></strong> </p> </td> <td width="120" style="padding: 0px 7px;"> <p style="text-align: center"> <strong><span style="font-size: 16px;font-family: 仿宋;">年齡</span></strong> </p> </td> <td width="120" style="padding: 0px 7px;"> <p style="text-align: center"> <strong><span style="font-size: 16px;font-family: 仿宋;">性別</span></strong> </p> </td> </tr> <#if lists??> <#list rows as lists> <tr style="height:39px" class="firstRow"> <td width="120" style="padding: 0px 7px;"> <p style="text-align: center"> <span style="font-size: 16px;font-family: 仿宋;">${rows.name!}</span> </p> </td> <td width="120" style="padding: 0px 7px;"> <p style="text-align: center"> <span style="font-size: 16px;font-family: 仿宋;">${rows.age!}</span> </p> </td> <td width="120" style="padding: 0px 7px;"> <p style="text-align: center"> <span style="font-size: 16px;font-family: 仿宋;">${rows.gender!}</span> </p> </td> </tr> </#list> </#if> </tbody> </table> </div> </body> </html>
其中控制開啟後展示為頁面檢視的是這一段:
<!--[if gte mso 9]>
...
<![endif]-->
百度了好久都沒有百度到相關模板,就寫了個demo先使用html程式碼生成一個word,再在word中修改格式,儲存。
然後使用NodePad開啟儲存後的doc文件分析其中的結構才拼湊成一個格式比較像樣的模板。
控制頁邊距的是以下這一段:
<!-- /*Page Definitions*/ @page WordSection1 { size: 595.3pt 841.9pt; margin: 72.0pt 1.0cm 72.0pt 1.0cm; mso-header-margin: 42.55pt; mso-footer-margin: 49.6pt; mso-paper-source: 0; } div.WordSection1 { page: WordSection1 } -->
使用${param!}引入引數,使用<#if lists??><#list rows as lists></#list></#if>遍歷多條資料插入到模板中;
二、匯入資料到模板並生成word
@ResponseBody @RequestMapping("/exportWord") public Map<String,String> exportWord(HttpServletRequest request){ try { //遍歷獲取所有引數 Enumeration<String> enu = request.getParameterNames(); String paraName = null; Map<String, String> parameters = new HashMap<>(); while (enu.hasMoreElements()) { paraName = enu.nextElement(); parameters.put(paraName, request.getParameter(paraName)); } //準備一段假資料 Map<String, Object> map = new HashMap<>(); map.put("basicShow", "這裡展示一段文字。。。啦啦啦"); List<User> list = new ArrayList<>(); list.add(new User() {{ setAge(18); setGender("男"); setName("趙康"); }}); list.add(new User() {{ setAge(34); setGender("男"); setName("劉天"); }}); list.add(new User() {{ setAge(23); setGender("女"); setName("李逵"); }}); map.put("lists", list); String path = request.getRealPath("/");//獲取專案的根目錄 ServletContext context = request.getServletContext(); String filepath = createDoc(path, context, map, "wordOfHtml.ftl", "測試word文件.doc"); Map<String, String> resultMap = new HashMap<>(); resultMap.put("filepath", filepath); return resultMap; }catch(Exception e){ e.printStackTrace(); } return null; } private String createDoc(String path, ServletContext context, Map<String, Object> data, String templateName, String docName) { long startTime=System.currentTimeMillis(); System.out.println("生成word開始。。。"); Configuration configurationc=new Configuration(); //設定模板編碼格式 configurationc.setDefaultEncoding("utf-8"); //設定模板存放的路徑 configurationc.setServletContextForTemplateLoading(context,"freemarkTemplate"); Template template=null; String filepath=null; String htmlpath=null; try{ //獲取模板設定編碼型別 template=configurationc.getTemplate(templateName,"UTF-8"); //設定生成word檔案的存放路徑 filepath= path+"export"+File.separator;//+"test.doc"; File file=new File(filepath); if(!file.exists()){ // file.createNewFile(); file.mkdirs(); } filepath+=docName; Writer bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filepath),"utf-8")); // BufferedWriter bw=new BufferedWriter(new FileWriter(filepath)); //替換模板中的佔位符並輸出 template.process(data,bw, ObjectWrapper.BEANS_WRAPPER); return filepath; }catch (Exception e){ e.printStackTrace(); }finally { long end=System.currentTimeMillis(); System.out.println("用時:"+(end-startTime)/1000+"秒;"); System.out.println("生成word結束,開始下載。。。"); } return null; }
這裡為了測試,我直接造的假資料放到Map中,替換模板中對應的引數;
三、匯出word
@ResponseBody
@RequestMapping("/downloadWord")
public void downloadWord(HttpServletResponse response,String filepath){
OutputStream os=null;
FileInputStream inputStream=null;
System.out.println("開始下載。。。");
try{
File file=new File(filepath);
String filename=new String(file.getName().getBytes("GB2312"),"ISO8859-1");
//設定輸出檔案型別為 word.doc
response.setContentType("application/msword");
//設定檔名
response.setHeader("Content-Disposition","attachment;filename="+filename);
String len=String.valueOf(file.length());
response.setHeader("Content-length",len);
os=response.getOutputStream();
inputStream=new FileInputStream(file);
byte[] bytes=new byte[1024];
int i;
while((i=inputStream.read(bytes))!=-1){
os.write(bytes,0,i);
}
os.flush();
boolean b=file.delete();
System.out.println(b+"----------");
}catch(Exception e){
e.printStackTrace();
}
finally {
try {
if (inputStream != null) {
inputStream.close();
}
if(os!=null){
os.close();
}
}catch(Exception e){
e.printStackTrace();
}
System.out.println("下載完成。。。");
}
}
前臺js:
$.ajax({
url: _ctx+'/report/common/exportWord',
data: {},
type: 'post',
dataType: 'json',
success: function (obj) {
var filepath=obj.filepath;
console.info(filepath)
if(filepath!=null){
var encode2=encodeURIComponent(filepath);
console.info(encode2)
console.log(_ctx+'/report/common/downloadWord?'+(new Date().getTime())+"&filepath="+encode2)
window.location.href=_ctx+'/report/common/downloadWord?'+(new Date().getTime())+"&filepath="+encode2;
}else{
alert("下載word失敗!");
}
}
})
效果:
使用nodepad開啟word,發現其實格式還是html:
所以如果需要什麼樣式可以直接在word中修改,然後儲存,使用記事本開啟就可以看到對應的樣式,希望對各位小夥伴有所幫助!
-------------------------------------------------華麗的分割線-----------------------------------------------------
(原創文件,轉載請註明出處。)