java如何用Freemarker導出word

前言:

在項目中應該會經常遇到導出word需求,Java中有5種方式導出word:

所用技術 優點 缺點
Jacob 功能強大 代碼量大,設置樣式繁瑣;需要windows平臺支持,無法跨平臺
Apache POI 讀寫excel功能強大、操作簡單 一般只用它讀取word,能夠創建簡單的word,不能設置樣式,功能太少
Java2word 功能強大,操作簡單 能滿足一般要求,不支持07格式,國人開發的,參考資料較多,需要windows平臺支持
iText 功能全,能滿足一般要求 不能直接生成或操作doc文檔,只能生成rtf格式的文檔,rtf也可以用word打開
JSP 操作簡單,代碼量少 能把當前頁面導出簡單的word,不能設置樣式,美觀性差,無法操作word
Freemarker 代碼量少,樣式、內容容易控制,打印不變形,完全符合office標準 需要提前設計好word模板,把需要替換的地方用特殊標記標出來

具體選擇哪種方式實現Java導出word,要根據自己的需求和實際情況靈活選擇,今天這篇文章主要講解下java怎麼結合freemarker導出word的,我選擇freemarker主要因爲相對於poi導出word,它更靈活。

正文:

Freemarker導出word的思路是,先把word文件中插入特殊的字符串佔位符,另存爲xml,然後將xml翻譯爲FreeMarker模板,最後用java來解析FreeMarker模板,編碼調用FreeMarker實現文本替換並輸出Doc。

一、把插入佔位符word文件另存爲xml

網上很多說不建議用wps,但是我用的wps發現也沒有太大的影響,這是我word製作的表格。

 

然後另存爲Word XML文檔,把生成的xml放到WEB-INF目錄下,我在這個目錄下又建了word目錄,最後我放到word目錄下啦

 

 直接打開xml會發現,格式很錯亂,代碼擠到一塊了,如下圖

我們可以通過idea格式化代碼的快捷鍵,把代碼格式化下,方便閱讀

Ctrl+Alt+L

 

 二、引入Freemarker的maven依賴和lombok的依賴

<dependency>
	<groupId>org.freemarker</groupId>
	<artifactId>freemarker</artifactId>
	<version>2.3.20</version>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.16.18</version>
</dependency>

三、編寫模板展示的類和導出的工具類以及測試類代碼

 User類

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private String sex;
    private String age;
    private String phone;
    private String email;
}

導出的工具類:

public class exportWord {

	
	public void export(Map<String, Object> map) {
		try {
			
			Configuration configuration = new Configuration();
			configuration.setDefaultEncoding("UTF-8");
			//模板文件配置路徑
			configuration.setDirectoryForTemplateLoading(new File("F:\\dao\\exportWord\\src\\main\\webapp\\WEB-INF\\word"));
			configuration.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
			//文件輸出路徑,文件名
			File outFile = new File("E:\\測試模板.doc");
			//掃描模板路徑下 模板文件
			Template template = configuration.getTemplate("測試模板.xml", "UTF-8");
			Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"), 10240);
            template.process(map, out);
            out.flush();
            out.close();
		
		System.out.println("導出完成");
		
		
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TemplateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 測試類:

public class Test {

	public static void main(String[] args) {
		exportWord ew = new exportWord();
		Map<String,Object> dataMap = new HashMap<String,Object>();
		List<User> list = new ArrayList<User>();
		User user1 = new User("ada", "男", "18", "10000000", "[email protected]");
		User user2 = new User("ada", "男", "18", "10000000", "[email protected]");
		User user3 = new User("ada", "男", "18", "10000000", "[email protected]");
		list.add(user1);
		list.add(user2);
		list.add(user3);
		dataMap.put("userList", list);
		ew.export(dataMap);
	}
}

四、如果數據是集合,需要遍歷展示的

 找到 xml文件中 <w:tr> 標籤 用 <#list map中鍵值 as 別名><w:tr></w:tr></#list> 標籤包裹在內即可

五、啓動測試類,看導出效果

六、 常見bug

順利的話,你應該會出現如下圖的bug,你只要格式化代碼啦,按照這個錯誤報的行數,去看下,就知道爲什麼了,原因是word轉xml的時候解析錯誤啦,需要去手動去調節下

freemarker.core.ParseException: Parsing error in template "測試模板.xml" in line 320, column 48:
Encountered "<", but was expecting one of:
    <STRING_LITERAL>
    <RAW_STRING>
    "false"
    "true"
    <INTEGER>
    <DECIMAL>
    "."
    "+"
    "-"
    "!"
    "["
    "("
    "{"
    <ID>
	at freemarker.core.FMParser.generateParseException(FMParser.java:4672)
	at freemarker.core.FMParser.jj_consume_token(FMParser.java:4543)
	at freemarker.core.FMParser.UnaryExpression(FMParser.java:340)
	at freemarker.core.FMParser.MultiplicativeExpression(FMParser.java:452)
	at freemarker.core.FMParser.AdditiveExpression(FMParser.java:402)
	at freemarker.core.FMParser.RangeExpression(FMParser.java:573)
	at freemarker.core.FMParser.RelationalExpression(FMParser.java:528)
	at freemarker.core.FMParser.EqualityExpression(FMParser.java:493)
	at freemarker.core.FMParser.AndExpression(FMParser.java:602)
	at freemarker.core.FMParser.OrExpression(FMParser.java:625)
	at freemarker.core.FMParser.Expression(FMParser.java:238)
	at freemarker.core.FMParser.StringOutput(FMParser.java:1076)
	at freemarker.core.FMParser.Content(FMParser.java:2550)
	at freemarker.core.FMParser.OptionalBlock(FMParser.java:2761)
	at freemarker.core.FMParser.Root(FMParser.java:2933)
	at freemarker.template.Template.<init>(Template.java:193)
	at freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:419)
	at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:330)
	at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:205)
	at freemarker.template.Configuration.getTemplate(Configuration.java:740)
	at freemarker.template.Configuration.getTemplate(Configuration.java:681)
	at com.util.exportWord.export(exportWord.java:25)
	at com.util.test.Test.main(Test.java:54)

 我們提前寫好的佔位符有時候轉完後會錯誤,被拆解了,只要把多餘的部分刪除就可以啦,我們看下<w:r></w:r>標籤是一個標籤,把多餘的刪掉即可,刪完後如下。

                         <w:tc>
                                <w:tcPr>
                                    <w:tcW w:w="2027" w:type="dxa"/>
                                </w:tcPr>
                                <w:p>
                                    <w:pPr>
                                        <w:jc w:val="center"/>
                                        <w:rPr>
                                            <w:rFonts w:asciiTheme="minorEastAsia" w:hAnsiTheme="minorEastAsia"/>
                                            <w:kern w:val="0"/>
                                            <w:sz w:val="24"/>
                                            <w:szCs w:val="20"/>
                                        </w:rPr>
                                    </w:pPr>
                                    <w:r>
                                        <w:rPr>
                                            <w:rFonts w:asciiTheme="minorEastAsia" w:hAnsiTheme="minorEastAsia"/>
                                            <w:kern w:val="0"/>
                                            <w:sz w:val="24"/>
                                            <w:szCs w:val="20"/>
                                        </w:rPr>
                                        <w:t>${user.name}</w:t>
                                    </w:r>
                                </w:p>
                            </w:tc>

總結:

freemarker導出word還是很方便的,轉化後的xml咋看很複雜,其實認真看下,規律還是很明顯的,改動幾個保存下,你就試出作用啦。

我是阿達,一名喜歡分享知識的程序員,時不時的也會荒腔走板的聊一聊電影、電視劇、音樂、漫畫,這裏已經有373小夥伴在等你們啦,感興趣的就趕緊來點擊關注我把,哪裏有不明白或有不同觀點的地方歡迎留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章