1. pom相關(guān)依賴
工具poi-tl (操作word文檔模板) + jacob (將操作后的word模板轉(zhuǎn)為pdf)
1
2
3
4
5
6
|
<!-- poi-tl的pom依賴 --> < dependency > < groupId >com.deepoove</ groupId > < artifactId >poi-tl</ artifactId > < version >1.9.1</ version > </ dependency > |
1
2
3
4
5
6
7
8
|
<!-- jacob的pom依賴(需自行導(dǎo)入.jar包) --> < dependency > < groupId >com.jacob</ groupId > < artifactId >jacob</ artifactId > < version >1.17</ version > < scope >system</ scope > < systemPath >${project.basedir}/src/main/resources/lib/jacob.jar</ systemPath > </ dependency > |
2. 對word模板進行插入數(shù)據(jù)操作
使用poi-tl操作word需要創(chuàng)建一個用于向word插入數(shù)據(jù)的Map<String, Object>集合, word模板中標簽格式為"{{標簽}}", 其中標簽內(nèi)容為Map<String, Object> 的key.
1
2
3
4
5
6
7
8
9
10
|
// 項目根路徑 String abPath = new File( "" ).getAbsolutePath() + "/src/main/resources" ; // 創(chuàng)建用于插入數(shù)據(jù)的Map Map<String, Object> map = new HashMap<>(); map.put(<k>, <v>); ... // 填充word文檔 XWPFTemplate template = XWPFTemplate.compile(abPath + "<模板路徑>" ).render(map); // 輸出文檔 template.writeAndClose( new FileOutPutStream( "<輸出路徑>" )); |
3. 對word模板的表格執(zhí)行插入數(shù)據(jù)操作(動態(tài)表格)
使用poi-tl操作word的表格,動態(tài)的插入數(shù)據(jù),需要用到poi-tl的可選插件進行自定義渲染策略, 首先在word需要操作的表格中的任意單元格添加標簽“{{標簽}}”
自定義渲染策略
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
|
/** * 自定義渲染策略 * * @author */ public class DetailTablePolicy extends DynamicTableRenderPolicy { // 表格起始行行數(shù) int tableStartRow = 1 ; /** * 自定義渲染策略 * * @data 傳入的封裝好的數(shù)據(jù) */ @Override public void render(XWPFTable table, Object data) throws Exception { // 如果數(shù)據(jù)為空,直接返回 if ( null == data) return ; // 封裝數(shù)據(jù)List的數(shù)據(jù)封裝對象 NdrwhkhzbData detailData = (NdrwhkhzbData) data; // 獲取當(dāng)前列表行高 int height = table.getRow( 2 ).getHeight(); // 從封裝對象中獲取數(shù)據(jù)集合 List<RowRenderData> datas = detailData.getNdrwhkhzbs(); if ( null != datas) { // 循環(huán)移除空白表格中數(shù)據(jù)數(shù)量的空白行 for ( int i = 1 ; i < datas.size() + 2 ; i++) { table.removeRow(i); } // 循環(huán)插入數(shù)據(jù) for ( int i = 0 ; i < datas.size(); i++) { // 新增一行空白行 XWPFTableRow insertNewTableRow = table.insertNewTableRow(tableStartRow); // 設(shè)置行高 insertNewTableRow.setHeight(height); // 循環(huán)添加單元格(4為每行單元格數(shù)量) for ( int j = 0 ; j < 4 ; j++) { insertNewTableRow.createCell(); } // 填充表格 TableRenderPolicy.Helper.renderRow(table.getRow(tableStartRow), datas.get(i)); } } } } |
把自定義渲染策略當(dāng)做工具類, 在主邏輯中直接配置使用
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
|
/** * 操作年度任務(wù)和考核指標表 * * @throws IOException 輸入輸出流異常 */ private void createNdrwhkhzb(Integer uid, String dirPath) throws IOException { PageData datas = new PageData(); NdrwhkhzbData detailTable = new NdrwhkhzbData(); List<RowRenderData> nds = new ArrayList<>(); // 根據(jù)uid查詢年度任務(wù)和考核指標數(shù)據(jù) List<NdrwhkhzbEntity> list = ndrwhkhzbService.selectNdrwhkhzbByUid(uid); for (NdrwhkhzbEntity ndrwhkhzbEntity : list) { RowRenderData rrd = Rows.of(ndrwhkhzbEntity.getNd(), ndrwhkhzbEntity.getNdrw(), ndrwhkhzbEntity.getNdkhzb() , ndrwhkhzbEntity.getZyrwdsjjd()).center().create(); nds.add(rrd); } detailTable.setNdrwhkhzbs(nds); datas.setNdrwhkhzbData(detailTable); // 配置表格 Configure config = Configure.builder().bind( "detail_table" , new DetailTablePolicy()).build(); // 調(diào)用渲染策略進行填充 XWPFTemplate template = XWPFTemplate.compile(dirPath + "/" + uid + "_Complete.docx" , config).render(datas); // 寫入表格中 template.writeToFile(dirPath + "/" + uid + "_Complete.docx" ); } |
用到的一些實體類
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
|
// PageData public class PageData { @Name ( "detail_table" ) private NdrwhkhzbData ndrwhkhzbData; public NdrwhkhzbData getNdrwhkhzbData() { return ndrwhkhzbData; } public void setNdrwhkhzbData(NdrwhkhzbData ndrwhkhzbData) { this .ndrwhkhzbData = ndrwhkhzbData; } } // NdrwhkhzbData public class NdrwhkhzbData { private List<RowRenderData> ndrwhkhzbs; public List<RowRenderData> getNdrwhkhzbs() { return ndrwhkhzbs; } public void setNdrwhkhzbs(List<RowRenderData> ndrwhkhzbs) { this .ndrwhkhzbs = ndrwhkhzbs; } } |
4. 將編輯好的Word轉(zhuǎn)為pdf格式(jacob)
這里將word轉(zhuǎn)為pdf時需要用到j(luò)acob, 這里需要將jacob的dll文件放到j(luò)dk和jre的bin目錄下, 下載的jacob中dll文件一般為兩個版本, X86為32位, X64為64位, 根據(jù)自己安裝的jdk版本添加所對應(yīng)的dll文件
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
|
/* * 將 .docx 轉(zhuǎn)換為 .pdf */ ActiveXComponent app = null ; String wordFile = dirPath + "/" + uid + "_Complete.docx" ; String pdfFile = dirPath + "/" + dirName + ".pdf" ; System.out.println( "開始轉(zhuǎn)換..." ); // 開始時間 long start = System.currentTimeMillis(); try { // 打開word app = new ActiveXComponent( "Word.Application" ); // 設(shè)置word不可見,很多博客下面這里都寫了這一句話,其實是沒有必要的,因為默認就是不可見的,如果設(shè)置可見就是會打開一個word文檔,對于轉(zhuǎn)化為pdf明顯是沒有必要的 //app.setProperty("Visible", false); // 獲得word中所有打開的文檔 Dispatch documents = app.getProperty( "Documents" ).toDispatch(); System.out.println( "打開文件: " + wordFile); // 打開文檔 Dispatch documentP = Dispatch.call(documents, "Open" , wordFile, false , true ).toDispatch(); // 如果文件存在的話,不會覆蓋,會直接報錯,所以我們需要判斷文件是否存在 File target = new File(pdfFile); if (target.exists()) { target.delete(); } System.out.println( "另存為: " + pdfFile); // 另存為,將文檔報錯為pdf,其中word保存為pdf的格式宏的值是17 Dispatch.call(documentP, "SaveAs" , pdfFile, 17 ); // 關(guān)閉文檔 Dispatch.call(documentP, "Close" , false ); // 結(jié)束時間 long end = System.currentTimeMillis(); System.out.println( "轉(zhuǎn)換成功,用時:" + (end - start) + "ms" ); } catch (Exception e) { e.getMessage(); System.out.println( "轉(zhuǎn)換失敗" + e.getMessage()); } finally { // 關(guān)閉office app.invoke( "Quit" , 0 ); } |
5. 通過lo流將生成好的文件傳到瀏覽器下載
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
|
/* * 下載pdf */ String fileName = dirName + ".pdf" ; File file = new File(dirPath + "/" + fileName); if (file.exists()) { BufferedInputStream bis = null ; FileInputStream fis = null ; try { response.setHeader( "Content-disposition" , "attachment; filename=" + fileName); byte [] buff = new byte [ 2048 ]; fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buff); while (i != - 1 ) { os.write(buff, 0 , i); i = bis.read(buff); } os.close(); } catch (Exception e) { e.printStackTrace(); } finally { assert fis != null ; fis.close(); assert bis != null ; bis.close(); } } |
6. 最后的Controller整體代碼
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
|
package org.example.controller; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.data.Includes; import com.deepoove.poi.data.RowRenderData; import com.deepoove.poi.data.Rows; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; import org.example.entity.*; import org.example.service.*; import org.example.utils.DetailTablePolicy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 創(chuàng)建pdf控制器 * * @author: yoojyn * @data: 2021/1/11 */ @Controller @RequestMapping ( "/createPdfController" ) public class CreatePdfController { @Autowired private IKtfmService ktfmService; @Autowired private IKtjbxxService ktjbxxService; @Autowired private IKtbyxfxService ktbyxfxService; @Autowired private IZtmbhkhzbService ztmbhkhzbService; @Autowired private INdrwhkhzbService ndrwhkhzbService; @Autowired private IKtjfysjsmService ktjfysjsmService; @Autowired private IXjxhkxxfxService xjxhkxxfxService; /** * 生成word文件 * * @param session 作用域 */ @Scope ( "prototype" ) @ResponseBody @RequestMapping ( "/createPdf" ) public void createPdf(HttpSession session, HttpServletResponse response) { // 獲取當(dāng)前用戶id Userinfo loginedUser = (Userinfo) session.getAttribute( "loginedUser" ); Integer uid = loginedUser.getUid(); String dirName = DigestUtils.md5DigestAsHex((uid + "_國家重大專項任務(wù)合同申報" ).getBytes()); String dirPath = "D:/" + dirName; String abPath = new File( "" ).getAbsolutePath() + "/src/main/resources" ; try { // 創(chuàng)建用于存儲中間文件的文件夾 new File(dirPath).mkdirs(); // 創(chuàng)建用于存儲數(shù)據(jù)的map集合 Map<String, Object> map = new HashMap<>(); // 獲取封面數(shù)據(jù) createKtfm(uid, map); // 獲取基本信息數(shù)據(jù) createJbxx(uid, map); // 獲取必要性分析 createByxfx(uid, map); // 獲取總體目標和考核指標 createZtmbhkhzb(uid, map); // 獲取經(jīng)費預(yù)算及說明 createJfysjsm(uid, map); // 查詢附件 XjxhkxxfxEntity xjxhkxxfxEntity = xjxhkxxfxService.selectXjxhkxxfxByUid(uid); // 設(shè)置下一步處理表格要用到的標簽 map.put( "page9" , Includes.ofLocal(abPath + "/static/file/upload/" + xjxhkxxfxEntity.getFilename()).create()); map.put( "detail_table" , "{{detail_table}}" ); // 填充文檔 XWPFTemplate template = XWPFTemplate.compile(abPath + "/static/file/moban/moban.docx" ).render(map); // 輸出文檔 template.writeAndClose( new FileOutputStream(dirPath + "/" + uid + "_Complete.docx" )); // 操作年度任務(wù)和考核指標表 createNdrwhkhzb(uid, dirPath); } catch (IOException e) { e.printStackTrace(); } try { /* * 將 .docx 轉(zhuǎn)換為 .pdf */ ActiveXComponent app = null; String wordFile = dirPath + "/" + uid + "_Complete.docx"; String pdfFile = dirPath + "/" + dirName + ".pdf"; System.out.println("開始轉(zhuǎn)換..."); // 開始時間 long start = System.currentTimeMillis(); try { // 打開word app = new ActiveXComponent("Word.Application"); // 設(shè)置word不可見,很多博客下面這里都寫了這一句話,其實是沒有必要的,因為默認就是不可見的,如果設(shè)置可見就是會打開一個word文檔,對于轉(zhuǎn)化為pdf明顯是沒有必要的 //app.setProperty("Visible", false); // 獲得word中所有打開的文檔 Dispatch documents = app.getProperty("Documents").toDispatch(); System.out.println("打開文件: " + wordFile); // 打開文檔 Dispatch documentP = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch(); // 如果文件存在的話,不會覆蓋,會直接報錯,所以我們需要判斷文件是否存在 File target = new File(pdfFile); if (target.exists()) { target.delete(); } System.out.println("另存為: " + pdfFile); // 另存為,將文檔報錯為pdf,其中word保存為pdf的格式宏的值是17 Dispatch.call(documentP, "SaveAs", pdfFile, 17); // 關(guān)閉文檔 Dispatch.call(documentP, "Close", false); // 結(jié)束時間 long end = System.currentTimeMillis(); System.out.println("轉(zhuǎn)換成功,用時:" + (end - start) + "ms"); } catch (Exception e) { e.getMessage(); System.out.println("轉(zhuǎn)換失敗" + e.getMessage()); } finally { // 關(guān)閉office app.invoke("Quit", 0); } /* * 下載pdf */ String fileName = dirName + ".pdf"; File file = new File(dirPath + "/" + fileName); if (file.exists()) { BufferedInputStream bis = null; FileInputStream fis = null; try { response.setHeader("Content-disposition", "attachment; filename=" + fileName); byte[] buff = new byte[2048]; fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buff); while (i != -1) { os.write(buff, 0, i); i = bis.read(buff); } os.close(); } catch (Exception e) { e.printStackTrace(); } finally { assert fis != null; fis.close(); assert bis != null; bis.close(); } } } catch (Exception e) { e.printStackTrace(); } finally { delDir(new File(dirPath)); } } /** * 刪除文件夾 * * @param file 文件夾對象 */ private void delDir(File file) { if (file.isFile()) { file.delete(); } if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { f.delete(); } file.delete(); } } /** * 儲存經(jīng)費預(yù)算及說明 * * @param uid 用戶id * @param map 儲存數(shù)據(jù)的map集合 */ private void createJfysjsm(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號查詢經(jīng)費預(yù)算及說明 KtjfysjsmEntity ktjfysjsmEntity = ktjfysjsmService.getDatesByUid(uid); // 添加到map集合 map.put("zjzyczzj", ktjfysjsmEntity.getZjzyczzj()); map.put("zjdfczzj", ktjfysjsmEntity.getZjdfczzj()); map.put("zjdwzczj", ktjfysjsmEntity.getZjdwzczj()); map.put("zjqt", ktjfysjsmEntity.getZjqt()); } /** * 操作年度任務(wù)和考核指標表 * * @throws IOException 輸入輸出流異常 */ private void createNdrwhkhzb(Integer uid, String dirPath) throws IOException { PageData datas = new PageData(); NdrwhkhzbData detailTable = new NdrwhkhzbData(); List<RowRenderData> nds = new ArrayList<>(); // 根據(jù)uid查詢年度任務(wù)和考核指標數(shù)據(jù) List<NdrwhkhzbEntity> list = ndrwhkhzbService.selectNdrwhkhzbByUid(uid); for (NdrwhkhzbEntity ndrwhkhzbEntity : list) { RowRenderData rrd = Rows.of(ndrwhkhzbEntity.getNd(), ndrwhkhzbEntity.getNdrw(), ndrwhkhzbEntity.getNdkhzb() , ndrwhkhzbEntity.getZyrwdsjjd()).center().create(); nds.add(rrd); } detailTable.setNdrwhkhzbs(nds); datas.setNdrwhkhzbData(detailTable); Configure config = Configure.builder().bind("detail_table", new DetailTablePolicy()).build(); XWPFTemplate template = XWPFTemplate.compile(dirPath + "/" + uid + "_Complete.docx", config).render(datas); template.writeToFile(dirPath + "/" + uid + "_Complete.docx"); } /** * 儲存總體目標和考核指標 * * @param uid 用戶id * @param map 儲存數(shù)據(jù)的map集合 */ private void createZtmbhkhzb(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號查詢總體目標和考核指標 ZtmbhkhzbEntity ztmbhkhzbEntity = ztmbhkhzbService.selectZtmbhkhzbByUid(uid); // 添加到map集合 map.put("page6", ztmbhkhzbEntity.getZtmbhkhzb()); } /** * 儲存必要性分析數(shù)據(jù) * * @param uid 用戶id * @param map 儲存數(shù)據(jù)的map集合 */ private void createByxfx(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號查詢必要性分析數(shù)據(jù) KtbyxfxEntityWithBLOBs ktbyxfxEntity = ktbyxfxService.selectKtbyxfxByUid(uid); // 添加到map集合 map.put("page5_ktyzx", ktbyxfxEntity.getKtyzx()); map.put("page5_ktysfgc", ktbyxfxEntity.getKtysf()); map.put("page5_ktyq", ktbyxfxEntity.getKtyq()); } /** * 儲存基本信息數(shù)據(jù) * * @param uid 用戶編號 * @param map 儲存數(shù)據(jù)的map集合 */ private void createJbxx(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號查詢基本信息數(shù)據(jù) KcjbxxEntity kcjbxxEntity = ktjbxxService.selectKtjbxxByUid(uid); // 添加到map集合 map.put("page3_ktmc", kcjbxxEntity.getKtmc()); map.put("page3_ktmj", kcjbxxEntity.getKtmj()); map.put("page3_yjwcsj", kcjbxxEntity.getYjwcsj()); map.put("page3_kyhdlx", kcjbxxEntity.getKthdlx()); map.put("page3_yqcglx", kcjbxxEntity.getYqcglx()); map.put("page3_dwmc", kcjbxxEntity.getDwmc()); map.put("page3_dwxz", kcjbxxEntity.getDwxz()); map.put("page3_txdz", kcjbxxEntity.getTxdz()); map.put("page3_yzbm", kcjbxxEntity.getYzbm()); map.put("page3_szdq", kcjbxxEntity.getSzdq()); map.put("page3_dwzgbm", kcjbxxEntity.getDwzgbm()); map.put("page3_lxdh", kcjbxxEntity.getLxdh()); map.put("page3_zzjgdm", kcjbxxEntity.getZzjgdm()); map.put("page3_czhm", kcjbxxEntity.getCzhm()); map.put("page3_dwclsj", kcjbxxEntity.getDwclsj()); map.put("page3_dzxx", kcjbxxEntity.getDzxx()); } /** * 儲存課題封面數(shù)據(jù) * * @param uid 用戶編號 * @param map 儲存數(shù)據(jù)的map集合 */ private void createKtfm(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號查詢封面數(shù)據(jù) KtfmEntity ktfmEntity = ktfmService.selectKtfmByUid(uid); // 添加到map集合 map.put( "page1_zxmc" , "5G總體及關(guān)鍵器件" ); map.put( "page1_xmbh" , "2016ZX03001_001" ); map.put( "page1_xmmc" , "新一代寬帶無線移動通信網(wǎng)" ); map.put( "page1_ktbh" , "2016ZX03001_001_002" ); map.put( "page1_ktmc" , "5G高性能基站A/D、D/A轉(zhuǎn)換器試驗樣片研發(fā)" ); map.put( "page1_zrdw" , "program_test" ); map.put( "page1_ktzz" , ktfmEntity.getKtfzr()); map.put( "page1_ktnx1" , "2016-01-01" ); map.put( "page1_ktnx2" , "2017-12-31" ); map.put( "page1_tbrq" , "2020-12-28" ); map.put( "page1_nian" , "二一" ); map.put( "page1_yue" , "一" ); } } |
以上就是Java 實現(xiàn)word模板轉(zhuǎn)為pdf的詳細內(nèi)容,更多關(guān)于Java word模板轉(zhuǎn)為pdf的資料請關(guān)注服務(wù)器之家其它相關(guān)文章!
原文鏈接:https://www.cnblogs.com/yoojyn/p/14386157.html