1. pom相關依賴
工具poi-tl (操作word文檔模板) + jacob (將操作后的word模板轉為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依賴(需自行導入.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模板進行插入數據操作
使用poi-tl操作word需要創建一個用于向word插入數據的Map<String, Object>集合, word模板中標簽格式為"{{標簽}}", 其中標簽內容為Map<String, Object> 的key.
1
2
3
4
5
6
7
8
9
10
|
// 項目根路徑 String abPath = new File( "" ).getAbsolutePath() + "/src/main/resources" ; // 創建用于插入數據的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模板的表格執行插入數據操作(動態表格)
使用poi-tl操作word的表格,動態的插入數據,需要用到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 { // 表格起始行行數 int tableStartRow = 1 ; /** * 自定義渲染策略 * * @data 傳入的封裝好的數據 */ @Override public void render(XWPFTable table, Object data) throws Exception { // 如果數據為空,直接返回 if ( null == data) return ; // 封裝數據List的數據封裝對象 NdrwhkhzbData detailData = (NdrwhkhzbData) data; // 獲取當前列表行高 int height = table.getRow( 2 ).getHeight(); // 從封裝對象中獲取數據集合 List<RowRenderData> datas = detailData.getNdrwhkhzbs(); if ( null != datas) { // 循環移除空白表格中數據數量的空白行 for ( int i = 1 ; i < datas.size() + 2 ; i++) { table.removeRow(i); } // 循環插入數據 for ( int i = 0 ; i < datas.size(); i++) { // 新增一行空白行 XWPFTableRow insertNewTableRow = table.insertNewTableRow(tableStartRow); // 設置行高 insertNewTableRow.setHeight(height); // 循環添加單元格(4為每行單元格數量) for ( int j = 0 ; j < 4 ; j++) { insertNewTableRow.createCell(); } // 填充表格 TableRenderPolicy.Helper.renderRow(table.getRow(tableStartRow), datas.get(i)); } } } } |
把自定義渲染策略當做工具類, 在主邏輯中直接配置使用
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
|
/** * 操作年度任務和考核指標表 * * @throws IOException 輸入輸出流異常 */ private void createNdrwhkhzb(Integer uid, String dirPath) throws IOException { PageData datas = new PageData(); NdrwhkhzbData detailTable = new NdrwhkhzbData(); List<RowRenderData> nds = new ArrayList<>(); // 根據uid查詢年度任務和考核指標數據 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" ); } |
用到的一些實體類
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轉為pdf格式(jacob)
這里將word轉為pdf時需要用到jacob, 這里需要將jacob的dll文件放到jdk和jre的bin目錄下, 下載的jacob中dll文件一般為兩個版本, X86為32位, X64為64位, 根據自己安裝的jdk版本添加所對應的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 轉換為 .pdf */ ActiveXComponent app = null ; String wordFile = dirPath + "/" + uid + "_Complete.docx" ; String pdfFile = dirPath + "/" + dirName + ".pdf" ; System.out.println( "開始轉換..." ); // 開始時間 long start = System.currentTimeMillis(); try { // 打開word app = new ActiveXComponent( "Word.Application" ); // 設置word不可見,很多博客下面這里都寫了這一句話,其實是沒有必要的,因為默認就是不可見的,如果設置可見就是會打開一個word文檔,對于轉化為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 ); // 關閉文檔 Dispatch.call(documentP, "Close" , false ); // 結束時間 long end = System.currentTimeMillis(); System.out.println( "轉換成功,用時:" + (end - start) + "ms" ); } catch (Exception e) { e.getMessage(); System.out.println( "轉換失敗" + e.getMessage()); } finally { // 關閉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; /** * 創建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) { // 獲取當前用戶id Userinfo loginedUser = (Userinfo) session.getAttribute( "loginedUser" ); Integer uid = loginedUser.getUid(); String dirName = DigestUtils.md5DigestAsHex((uid + "_國家重大專項任務合同申報" ).getBytes()); String dirPath = "D:/" + dirName; String abPath = new File( "" ).getAbsolutePath() + "/src/main/resources" ; try { // 創建用于存儲中間文件的文件夾 new File(dirPath).mkdirs(); // 創建用于存儲數據的map集合 Map<String, Object> map = new HashMap<>(); // 獲取封面數據 createKtfm(uid, map); // 獲取基本信息數據 createJbxx(uid, map); // 獲取必要性分析 createByxfx(uid, map); // 獲取總體目標和考核指標 createZtmbhkhzb(uid, map); // 獲取經費預算及說明 createJfysjsm(uid, map); // 查詢附件 XjxhkxxfxEntity xjxhkxxfxEntity = xjxhkxxfxService.selectXjxhkxxfxByUid(uid); // 設置下一步處理表格要用到的標簽 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" )); // 操作年度任務和考核指標表 createNdrwhkhzb(uid, dirPath); } catch (IOException e) { e.printStackTrace(); } try { /* * 將 .docx 轉換為 .pdf */ ActiveXComponent app = null; String wordFile = dirPath + "/" + uid + "_Complete.docx"; String pdfFile = dirPath + "/" + dirName + ".pdf"; System.out.println("開始轉換..."); // 開始時間 long start = System.currentTimeMillis(); try { // 打開word app = new ActiveXComponent("Word.Application"); // 設置word不可見,很多博客下面這里都寫了這一句話,其實是沒有必要的,因為默認就是不可見的,如果設置可見就是會打開一個word文檔,對于轉化為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); // 關閉文檔 Dispatch.call(documentP, "Close", false); // 結束時間 long end = System.currentTimeMillis(); System.out.println("轉換成功,用時:" + (end - start) + "ms"); } catch (Exception e) { e.getMessage(); System.out.println("轉換失敗" + e.getMessage()); } finally { // 關閉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(); } } /** * 儲存經費預算及說明 * * @param uid 用戶id * @param map 儲存數據的map集合 */ private void createJfysjsm(Integer uid, Map<String, Object> map) { // 根據用戶編號查詢經費預算及說明 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()); } /** * 操作年度任務和考核指標表 * * @throws IOException 輸入輸出流異常 */ private void createNdrwhkhzb(Integer uid, String dirPath) throws IOException { PageData datas = new PageData(); NdrwhkhzbData detailTable = new NdrwhkhzbData(); List<RowRenderData> nds = new ArrayList<>(); // 根據uid查詢年度任務和考核指標數據 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 儲存數據的map集合 */ private void createZtmbhkhzb(Integer uid, Map<String, Object> map) { // 根據用戶編號查詢總體目標和考核指標 ZtmbhkhzbEntity ztmbhkhzbEntity = ztmbhkhzbService.selectZtmbhkhzbByUid(uid); // 添加到map集合 map.put("page6", ztmbhkhzbEntity.getZtmbhkhzb()); } /** * 儲存必要性分析數據 * * @param uid 用戶id * @param map 儲存數據的map集合 */ private void createByxfx(Integer uid, Map<String, Object> map) { // 根據用戶編號查詢必要性分析數據 KtbyxfxEntityWithBLOBs ktbyxfxEntity = ktbyxfxService.selectKtbyxfxByUid(uid); // 添加到map集合 map.put("page5_ktyzx", ktbyxfxEntity.getKtyzx()); map.put("page5_ktysfgc", ktbyxfxEntity.getKtysf()); map.put("page5_ktyq", ktbyxfxEntity.getKtyq()); } /** * 儲存基本信息數據 * * @param uid 用戶編號 * @param map 儲存數據的map集合 */ private void createJbxx(Integer uid, Map<String, Object> map) { // 根據用戶編號查詢基本信息數據 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()); } /** * 儲存課題封面數據 * * @param uid 用戶編號 * @param map 儲存數據的map集合 */ private void createKtfm(Integer uid, Map<String, Object> map) { // 根據用戶編號查詢封面數據 KtfmEntity ktfmEntity = ktfmService.selectKtfmByUid(uid); // 添加到map集合 map.put( "page1_zxmc" , "5G總體及關鍵器件" ); map.put( "page1_xmbh" , "2016ZX03001_001" ); map.put( "page1_xmmc" , "新一代寬帶無線移動通信網" ); map.put( "page1_ktbh" , "2016ZX03001_001_002" ); map.put( "page1_ktmc" , "5G高性能基站A/D、D/A轉換器試驗樣片研發" ); 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 實現word模板轉為pdf的詳細內容,更多關于Java word模板轉為pdf的資料請關注服務器之家其它相關文章!
原文鏈接:https://www.cnblogs.com/yoojyn/p/14386157.html