java如何根據(jù)提供word模板導(dǎo)出word文檔詳解
本文主要講解,利用poi-tl在word中動態(tài)生成表格行,進(jìn)行文字、圖片填充。一共提供了兩種方式,1.基于本地文件 2.基于網(wǎng)絡(luò)文件
本文講解思路,1.先看示例,2. 示例對應(yīng)的代碼展示 3. 基本概念講解(api自行查閱文檔)。
這樣便于快速展示,不符合你的業(yè)務(wù)需求的可以直接劃走
1.效果示例圖
1.1 word模板

注意:這里提前闡述幾個(gè)概念。
- 基本上所有的變量都由{{}}包裹,交給poi-tl解析(變量命名隨便你,中文,英文都可以)
- {{工作經(jīng)歷列表}}下方的[序號]、[公司名]、[工作時(shí)長]、[salary]、[聯(lián)系]、[崗位],就是使用了 poi-tl的表格行插件,動態(tài)渲染表格行的語法,可以簡單理解為此處表格對應(yīng)的每一行就是一個(gè)對象實(shí)體類,而{{工作經(jīng)歷列表}}就是一個(gè)list
- {{?申明項(xiàng)列表}} {{item}} {{/申明項(xiàng)列表}},此處則是使用了poi-tl的區(qū)塊對標(biāo)簽。區(qū)塊對在此處的,我只是用它來實(shí)現(xiàn)渲染同一個(gè)表格內(nèi)的多行文本渲染,可以理解為<申明項(xiàng)列表>標(biāo)簽對應(yīng)的就是一個(gè)list,< item >就是一個(gè)list中的一個(gè)個(gè)對象元素。并且此處會觸發(fā),換行后序號累加的word編排編號樣式。
- {{@員工簽字圖片}},此處需要注意,word模板中代表圖片的變量,必須要加上@特殊符號修飾!
1.2 參數(shù)替換后的word

看到這里,如果對應(yīng)的效果不滿足你的需求,那么你可以出門右轉(zhuǎn)了。
2.代碼展示
maven 依賴,使用poi-tl需要支持 poi高版本
<!-- POI 依賴 使用xlsx xml的格式(即XSSFWorkbook) -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.17</version>
</dependency>
<!-- poi模板導(dǎo)入,主力包 -->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.1</version>
</dependency>2.1 根據(jù)網(wǎng)絡(luò)生成word
/**
* 根據(jù)網(wǎng)絡(luò)生成word
**/
public static void generateByNetWork() {
String ip = "192.168.x.x";
// 我這里是用文件服務(wù)器返回的網(wǎng)絡(luò)文件流,你也可以直接放置一個(gè)文件的url
String pictureUrl = "http://" + ip + ":8080/api/file/download?id=b9e0ac0336a84fc0b4ebb4cdf2c805e0.png";
HashMap<String, Object> finalMap = new HashMap<>();
finalMap.put("姓名", "張三");
finalMap.put("身份證號", "511232XXXXXXX");
finalMap.put("手機(jī)號", "1328292xxxx");
finalMap.put("員工簽字", "張三");
finalMap.put("日期", "2023-05-16");
// 從網(wǎng)絡(luò)流讀取圖片,置入word模板,等待編譯
if (Validator.isNotEmpty(pictureUrl)) {
PictureRenderData picture = Pictures.ofUrl(pictureUrl).size(40, 30).create();
finalMap.put("員工簽字圖片", picture);
}
ArrayList<Object> workList = CollUtil.newArrayList();
finalMap.put("工作經(jīng)歷列表", workList);
for (int i = 0; i < 3; i++) {
// 模擬從mysql查詢列表數(shù)據(jù)
HashMap<String, Object> workItem = new HashMap<>();
workItem.put("序號", i + 1);
workItem.put("公司名", "四川有限公司" + i);
workItem.put("工作時(shí)長", i + 10 + "小時(shí)");
workItem.put("salary", "800" + i);
workItem.put("聯(lián)系", "項(xiàng)目經(jīng)理" + i);
workItem.put("崗位", "java工程師" + i);
workList.add(workItem);
}
// 注意:此處用的是 <區(qū)塊對> key是字符串,value則放置一個(gè)集合,類似于模板引擎的foreach標(biāo)簽
ArrayList<Object> stateList = CollUtil.newArrayList();
finalMap.put("申明項(xiàng)列表", stateList);
// 模擬從mysql查詢數(shù)據(jù),改造為word模板所需的數(shù)據(jù)結(jié)構(gòu)
List<String> stateListFromMySQL = Arrays.asList("本人所遞交的所有辦理人才引進(jìn)材料及填寫的情況均屬實(shí);"
, "我已認(rèn)真閱讀以上內(nèi)容并確認(rèn);"
, "若在申請期間信息變更不做變更。若違反,本人愿意承擔(dān)由此產(chǎn)生的后果。");
for (int i = 0; i < stateListFromMySQL.size(); i++) {
HashMap<String, Object> stateItem = new HashMap<>();
// 此處在 每行文字后,都添加\n 的換行符。注意:此換行僅僅只是換行,并不等同于enter,不會觸發(fā)類似于 <在word中enter換行,自動觸發(fā)編排序號累加> 的動作
stateItem.put("item", stateListFromMySQL.get(i) + "\n");
stateList.add(stateItem);
}
// 從網(wǎng)絡(luò)url 下載word模板到指定文件夾
File wordTemplate = HttpUtil.downloadFileFromUrl("http://" + ip + ":8080/file/download" + "?id=talentsTemplate.docx", "D://upload" + File.separator);
// 此處使用了poi-tl的<表格行循環(huán)插件>,此處一定要進(jìn)行參數(shù)bind,方便word模板參數(shù)替換
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure build = Configure.builder().bind(policy, "工作經(jīng)歷列表").build();
// 進(jìn)行編譯
XWPFTemplate render = XWPFTemplate.compile(wordTemplate.getAbsolutePath(), build).render(finalMap);
File word = new File("D://upload" + File.separator + IdUtil.getSnowflake().nextId() + ".docx");
try {
// 關(guān)鍵步驟,
render.writeToFile(word.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException(e);
}
// 下面的方法可以根據(jù)業(yè)務(wù)調(diào)整,我這里是將參數(shù)替換后的word上傳到項(xiàng)目對應(yīng)的文件服務(wù)器,拿到的url進(jìn)行存入數(shù)據(jù)庫
String json = HttpUtil.createPost("http://" + ip + ":8080/file/upload")
.header("Content-Type", ContentType.MULTIPART.getValue())
.form("file", word)
.execute()
.body();
// hutool工具類,刪除 word。因?yàn)樵谶@個(gè)流程中,word只是一個(gè)中間產(chǎn)物,因?yàn)槲疑线呉呀?jīng)把該word 上傳到我的文件服務(wù)器,并且文件服務(wù)器 會返回給我它對應(yīng)的url
FileUtil.del(word);
List<String> list = JSONUtil.parseArray(json).toList(String.class);
}2.2 根據(jù)本地文件流生成word
/**
* 根據(jù)本地文件流生成word
**/
public static void generateByFile() {
// 此處直接是本地文件的絕對路徑
String pictureUrl = "C://Users//x//Desktop//博客//word模板填參//generate//sign.png";
HashMap<String, Object> finalMap = new HashMap<>();
finalMap.put("姓名", "張三");
finalMap.put("身份證號", "511232XXXXXXX");
finalMap.put("手機(jī)號", "1328292xxxx");
finalMap.put("員工簽字", "張三");
finalMap.put("日期", "2023-05-16");
// 從本地讀取圖片,置入word模板,等待編譯
if (Validator.isNotEmpty(pictureUrl)) {
PictureRenderData picture = Pictures.ofLocal(pictureUrl).size(60, 50).create();
finalMap.put("員工簽字圖片", picture);
}
ArrayList<Object> workList = CollUtil.newArrayList();
finalMap.put("工作經(jīng)歷列表", workList);
for (int i = 0; i < 3; i++) {
// 模擬從mysql查詢列表數(shù)據(jù)
HashMap<String, Object> workItem = new HashMap<>();
workItem.put("序號", i + 1);
workItem.put("公司名", "成都有限公司" + i);
workItem.put("工作時(shí)長", i + 5 + "小時(shí)");
workItem.put("salary", "1000" + i);
workItem.put("聯(lián)系", "聯(lián)系人" + i);
workItem.put("崗位", "崗位" + i);
workList.add(workItem);
}
// 注意:此處用的是 <區(qū)塊對> key是字符串,value則放置一個(gè)集合,類似于模板引擎的foreach標(biāo)簽
ArrayList<Object> stateList = CollUtil.newArrayList();
finalMap.put("申明項(xiàng)列表", stateList);
// 模擬從mysql查詢數(shù)據(jù),改造為word模板所需的數(shù)據(jù)結(jié)構(gòu)
List<String> stateListFromMySQL = Arrays.asList("本人所遞交的所有辦理人才引進(jìn)材料及填寫的情況均屬實(shí);"
, "我已認(rèn)真閱讀以上內(nèi)容并確認(rèn);"
, "若在申請期間信息變更不做變更。若違反,本人愿意承擔(dān)由此產(chǎn)生的后果。");
for (int i = 0; i < stateListFromMySQL.size(); i++) {
HashMap<String, Object> stateItem = new HashMap<>();
stateItem.put("item", stateListFromMySQL.get(i) + "");
stateList.add(stateItem);
}
// 從網(wǎng)絡(luò)url 下載word模板到指定文件夾
File wordTemplate = new File("C://Users//x//Desktop//博客//word模板填參//talentsTemplate.docx");
// 此處使用了poi-tl的<表格行循環(huán)插件>,此處一定要進(jìn)行參數(shù)bind,方便word模板參數(shù)替換
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure build = Configure.builder().bind(policy, "工作經(jīng)歷列表").build();
// 進(jìn)行編譯
String absolutePath = wordTemplate.getAbsolutePath();
XWPFTemplate render = XWPFTemplate.compile(absolutePath, build).render(finalMap);
// 此處是利用File,直接在本地創(chuàng)建文件,將參數(shù)替換后的文件流寫入到該文件,word就是最終的結(jié)果
File word = new File("C://Users//x//Desktop//博客//word模板填參//generate" + File.separator + IdUtil.getSnowflake().nextId() + ".docx");
try {
render.writeToFile(word.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException(e);
}
// 下面的方法可以根據(jù)業(yè)務(wù)調(diào)整,我這里是將參數(shù)替換后的word上傳到項(xiàng)目對應(yīng)的文件服務(wù)器,拿到的url進(jìn)行存入數(shù)據(jù)庫
// FileUtil.del(word);
// List<String> list = JSONUtil.parseArray(json).toList(String.class);
}2.3 方法調(diào)用
public static void main(String[] args) {
// generateByNetWork();
generateByFile();
}總結(jié): 上面的備注已經(jīng)說的很清楚了,這邊不做過多解釋。如果有哪里看不懂的,評論區(qū)評論,我有空就來給你解答。
3. 基本介紹
此處不做api介紹,只做基本概念介紹,不需要的可以跳過了!官網(wǎng) http://deepoove.com/poi-tl/
poi-tl(poi template language)是Word模板引擎,使用Word模板和數(shù)據(jù)創(chuàng)建很棒的Word文檔。
| 方案 | 移植性 | 功能性 | 易用性 |
|---|---|---|---|
| Poi-tl | Java跨平臺 | Word模板引擎,基于Apache POI,提供更友好的API | 低代碼,準(zhǔn)備文檔模板和數(shù)據(jù)即可 |
| Apache POI | Java跨平臺 | Apache項(xiàng)目,封裝了常見的文檔操作,也可以操作底層XML結(jié)構(gòu) | 文檔不全,這里有一個(gè)教程:Apache POI Word快速入門 |
| Freemarker | XML跨平臺 | 僅支持文本,很大的局限性 | 不推薦,XML結(jié)構(gòu)的代碼幾乎無法維護(hù) |
| OpenOffice | 部署OpenOffice,移植性較差 | - | 需要了解OpenOffice的API |
| HTML瀏覽器導(dǎo)出 | 依賴瀏覽器的實(shí)現(xiàn),移植性較差 | HTML不能很好的兼容Word的格式,樣式糟糕 | - |
| Jacob、winlib | Windows平臺 | - | 復(fù)雜,完全不推薦使用 |
3.1 功能介紹

3.2 版本說明
本文博客使用的是poi-tl最新版,需要apache poi 5.1.0+,不然會報(bào)錯(cuò),no such method

3.3 快速開始
依賴引入
maven <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.12.1</version> </dependency> gradle implementation 'com.deepoove:poi-tl:1.12.1'
官網(wǎng)demo示例
XWPFTemplate template = XWPFTemplate.compile("template.docx").render(
new HashMap<String, Object>(){{
put("title", "Hi, poi-tl Word模板引擎");
}});
template.writeAndClose(new FileOutputStream("output.docx")); 基本就是三部曲:
- compile 編譯模板
- render 渲染數(shù)據(jù)
- write 輸出到流
TDO模式:Template + data-model = output
最后再次貼出官網(wǎng)鏈接,http://deepoove.com/poi-tl/#_why_poi_tl
總結(jié)
到此這篇關(guān)于java如何根據(jù)提供word模板導(dǎo)出word文檔的文章就介紹到這了,更多相關(guān)java導(dǎo)出word文檔內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java8生成時(shí)間方式及格式化時(shí)間的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Java8生成時(shí)間方式及格式化時(shí)間的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Struts2學(xué)習(xí)教程之輸入校驗(yàn)示例詳解
這篇文章主要給大家介紹了關(guān)于Struts2學(xué)習(xí)教程之輸入校驗(yàn)的相關(guān)資料,文中通過示例介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用struts2具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05
基于javaMybatis存進(jìn)時(shí)間戳的問題
這篇文章主要介紹了javaMybatis存進(jìn)時(shí)間戳的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
SpringBoot多租戶配置與實(shí)現(xiàn)示例
本文詳細(xì)介紹了在SpringBoot中實(shí)現(xiàn)多租戶架構(gòu)的方法和步驟,包括配置數(shù)據(jù)源、Hibernate攔截器、租戶解析器等,以共享數(shù)據(jù)庫、共享數(shù)據(jù)表的方式,確保數(shù)據(jù)隔離和安全性,感興趣的可以了解一下2024-09-09
SpringBoot集成selenium實(shí)現(xiàn)自動化測試的代碼工程
Selenium?是支持web?瀏覽器自動化的一系列工具和[庫]?它提供了擴(kuò)展來模擬用戶與瀏覽器的交互,用于擴(kuò)展瀏覽器分配的分發(fā),本文給大家介紹了SpringBoot集成selenium實(shí)現(xiàn)自動化測試的代碼工程,需要的朋友可以參考下2024-08-08
java設(shè)計(jì)日歷可視化的詳細(xì)步驟記錄
這篇文章主要給大家介紹了關(guān)于java設(shè)計(jì)日歷可視化的相關(guān)資料,通過自定義的CircleLabel類來突出顯示今天的日期,并使用BorderLayout布局管理窗口組件,文章詳細(xì)描述了各個(gè)類和方法的設(shè)計(jì)思想和實(shí)現(xiàn)邏輯,需要的朋友可以參考下2024-12-12
解決idea報(bào)錯(cuò) Connot resolve column 的問題
這篇文章主要介紹了解決idea報(bào)錯(cuò) Connot resolve column 的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
MyBatis-Plus多數(shù)據(jù)源的示例代碼
本文主要介紹了MyBatis-Plus多數(shù)據(jù)源的示例代碼,包括依賴配置、數(shù)據(jù)源配置、Mapper 和 Service 的定義,具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05

