Java使用FreeMarker來實現(xiàn)Word自定義導出功能
前言
在對一些特定導出功能,使用常規(guī)Excel無法解決的,通常使用Word來實現(xiàn)導出功能,這篇介紹下如何在Java中使用FreeMarker模板注入方式來實現(xiàn)Word導出功能
導出案例(已作打碼處理)

或者:

準備工作
第一步:maven依賴庫
<!-- freemarker (用于Word導出)-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>
第二步:Word導出工具類
import com.zrxt.common.config.RuoYiConfig;
import com.zrxt.common.core.text.CharsetKit;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @ClassName WordUtil
* @Description 使用Freemarker生成Word文檔工具類
* @Author
* @Date 2023/12/14
**/
public class WordUtil {
/**
* 使用Freemarker自動生成Word文檔(磁盤路徑方法)
*
* @param dataMap 保存Word文檔中所需要的數(shù)據(jù)
* @param templatePath 模板文件的絕對路徑
* @param templateFile 模板文件的名稱
* @throws Exception
*/
public static void CreateWord(HttpServletResponse response, Map<String, Object> dataMap, String templatePath, String templateFile) throws Exception {
Writer out = null;
try {
// 設置FreeMarker的版本
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 設置Freemarker的編碼格式
configuration.setDefaultEncoding(CharsetKit.UTF_8);
// 設置FreeMarker生成Word文檔所需要的模板的路徑
configuration.setDirectoryForTemplateLoading(new File(templatePath));
// 設置FreeMarker生成Word文檔所需要的模板名稱
Template t = configuration.getTemplate(templateFile, CharsetKit.UTF_8);
// 創(chuàng)建一個Word文檔的輸出流
out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
//FreeMarker使用Word模板和數(shù)據(jù)生成Word文檔
t.process(dataMap, out);
}catch (Exception e){
e.printStackTrace();
}finally {
assert out != null;
out.flush();
out.close();
}
}
/**
* 使用Freemarker自動生成Word文檔
*
* @param dataMap 保存Word文檔中所需要的數(shù)據(jù)
* @param templatePath 模板文件的路徑(絕對)
* @param templateFile 模板文件的名稱
* @throws Exception
*/
public static void GeneratorWord(HttpServletResponse response, Map<String, Object> dataMap, String templatePath, String templateFile) throws Exception {
Writer out = null;
try {
// 設置FreeMarker的版本
Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
// 設置Freemarker的編碼格式
configuration.setDefaultEncoding(CharsetKit.UTF_8);
//相對路徑加載模板方法
configuration.setTemplateLoader(new ClassTemplateLoader(WordUtil.class,templatePath));
// 設置FreeMarker生成Word文檔所需要的模板名稱
Template template = configuration.getTemplate(templateFile, CharsetKit.UTF_8);
// 創(chuàng)建一個Word文檔的輸出流
out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
//FreeMarker使用Word模板和數(shù)據(jù)生成Word文檔
template .process(dataMap, out);
}catch (Exception e){
e.printStackTrace();
}finally {
assert out != null;
out.flush();
out.close();
}
}
/**
* 下載文件
*
* @param path 文件的位置
* @param fileName 自定義下載文件的名稱
* @param response http響應
* @param request http請求
*/
public static void downloadFile(String path, String fileName, HttpServletResponse response, HttpServletRequest request) {
try {
File file = new File(path);
// 中文亂碼解決
String type = request.getHeader("User-Agent").toLowerCase();
if (type.indexOf("firefox") > 0 || type.indexOf("chrome") > 0) {
// 谷歌或火狐
fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "iso8859-1");
} else {
// IE
fileName = URLEncoder.encode(fileName, CharsetKit.UTF_8);
}
// 設置響應的頭部信息
response.setHeader("content-disposition", "attachment;filename=" + fileName);
// 設置響應內容的類型
response.setContentType(getFileContentType(fileName) + "; charset=" + CharsetKit.UTF_8);
// 設置響應內容的長度
response.setContentLength((int) file.length());
// 輸出
outStream(new FileInputStream(file), response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文件的內容類型
*/
private static String getFileContentType(String name) {
String result = "";
String fileType = name.toLowerCase();
if (fileType.endsWith(".png")) {
result = "image/png";
} else if (fileType.endsWith(".gif")) {
result = "image/gif";
} else if (fileType.endsWith(".jpg") || fileType.endsWith(".jpeg")) {
result = "image/jpeg";
} else if (fileType.endsWith(".svg")) {
result = "image/svg+xml";
} else if (fileType.endsWith(".doc")) {
result = "application/msword";
} else if (fileType.endsWith(".xls")) {
result = "application/x-excel";
} else if (fileType.endsWith(".zip")) {
result = "application/zip";
} else if (fileType.endsWith(".pdf")) {
result = "application/pdf";
} else {
result = "application/octet-stream";
}
return result;
}
/**
* 基礎字節(jié)數(shù)組輸出
*/
private static void outStream(InputStream is, OutputStream os) {
try {
byte[] buffer = new byte[10240];
int length = -1;
while ((length = is.read(buffer)) != -1) {
os.write(buffer, 0, length);
os.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 檢查存儲生成文件的路徑是否存在,如果不存在則新建路徑.
*
* @param directory the directory name, like '\dir-name'
*/
public static void CheckDownloadPath(String directory) {
File path = new File(RuoYiConfig.getDownloadPath() + directory);
if (!path.exists()) {
path.mkdirs();
}
}
}
模板準備
第一步:首先要編寫Word模板,可以參考文章開頭的示例圖片。
第二步:Word模板編寫好后,點擊另存為,然后選擇Word 2003 XML文檔

第三步:保存好后的文件打開,Ctrl+A復制文檔所有內容,然后在線搜索XML格式化在線工具,我這邊提供一個現(xiàn)成的XML格式化在線工具,將內容全部粘貼進去后點擊格式化按鈕。

創(chuàng)建ftl文件
上面所有工作準備好后,就可以在resource目錄下創(chuàng)建一個.ftl文件,然后將格式化后的代碼復制到文件中即可。

測試導出是否完整
在Controller層編寫測試代碼,判斷是否可以正常導出
/**
* 導出(word)關鍵過程控制詳細信息詳細信息(xml版本)
*/
@PostMapping(value = "/exportWord")
public void getInfo(MakeCriticalProcessControl param, HttpServletResponse response) {
try {
MakeCriticalProcessControl obj=
makeCriticalProcessControlService.selectById(param.getId());
Map<String, Object> context = new HashMap<>();
context.put("obj", obj);
WordUtil.GeneratorWord(response, context, "/wordDocumentFtl/make/", "MakeCriticalProcessControl.ftl");
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException("導出Word文件失敗,請稍后重試!");
}
}
WordUtil.GeneratorWord()方法
第二個參數(shù)context為數(shù)據(jù)庫的數(shù)據(jù),要往word中空白單元格所填充的。
第三個參數(shù)為templatePath – 模板文件的路徑(相對路徑)。
第四個參數(shù)為具體的模板的文件名稱(帶后綴)
注:測試后需檢查格式是否混亂,是否有缺少單元格等情況,如果有則檢查原Word模板并修復然后重新走一遍流程即可
如何將數(shù)據(jù)庫數(shù)據(jù)填充到Word中
ftl文件中的內容是一行一行的順序,也就是從第一行的第一個單元格開始,然后是第一行第二個單元格,第三個單元格…
然后第一行如果結束了,則是第二行第一個單元格、第二個單元格、第三個…
以此類推,所以優(yōu)先找到對應標題的對應數(shù)據(jù)單元格在ftl文件的哪個位置。
如果是單個屬性或對象類型的,可以在controller中使用Map<String, Object> context = new HashMap<>();將數(shù)據(jù)put,然后key作為鍵,在ftl文件中可以把屬性獲取出來。例如下圖


如果涉及到遍歷,將一個list結果導出到word,請看以下案例
如果是遍歷導出的話,則在word模板設置時,只需要設置一行表頭,下方對應一行空的單元格即可,我們要循環(huán)空的單元格,然后將數(shù)據(jù)挨個寫入。

只需要在標題下寫一行即可
在controller中依舊是查詢出對應list,然后put到map中


1:判斷l(xiāng)ist是否為空
2:循環(huán)遍歷list
3:一般<w:tr>表示為行,所以這里的意思就是,list有多少數(shù)據(jù),則就生成多少行
如何要獲取值的話就可以${item.屬性名!}

如果涉及到If語句或者是需要將數(shù)字轉為對應的狀態(tài)

以上就是Java使用FreeMarker來實現(xiàn)Word自定義導出功能的詳細內容,更多關于Java FreeMarker Word自定義導出的資料請關注腳本之家其它相關文章!
相關文章
SpringBoot?整合mapstruct的實現(xiàn)步驟
這篇文章主要介紹了SpringBoot整合mapstruct,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
Spring Boot 如何使用Liquibase 進行數(shù)據(jù)庫遷移(操作方法)
在Spring Boot應用程序中使用Liquibase進行數(shù)據(jù)庫遷移是一種強大的方式來管理數(shù)據(jù)庫模式的變化,本文重點講解如何在Spring Boot應用程序中使用Liquibase進行數(shù)據(jù)庫遷移,從而更好地管理數(shù)據(jù)庫模式的變化,感興趣的朋友跟隨小編一起看看吧2023-09-09
java調用webservice接口,并解析返回參數(shù)問題
這篇文章主要介紹了java調用webservice接口,并解析返回參數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07

