Java 實現(xiàn)word模板轉(zhuǎn)為pdf
1. pom相關(guān)依賴
工具poi-tl (操作word文檔模板) + jacob (將操作后的word模板轉(zhuǎn)為pdf)
<!-- poi-tl的pom依賴 --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.9.1</version> </dependency>
<!-- 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.
// 項目根路徑
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需要操作的表格中的任意單元格添加標簽“{{標簽}}”
自定義渲染策略
/**
* 自定義渲染策略
*
* @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;
// 獲取當前列表行高
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));
}
}
}
}
把自定義渲染策略當做工具類, 在主邏輯中直接配置使用
/**
* 操作年度任務(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");
}
用到的一些實體類
// 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文件
/*
* 將 .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流將生成好的文件傳到瀏覽器下載
/*
* 下載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整體代碼
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) {
// 獲取當前用戶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)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis根據(jù)表逆向自動化生成代碼的實現(xiàn)
若采用mybatis框架,數(shù)據(jù)庫新建表,手動編寫的話,需要編寫大量的實體類、mapper文件、mapper.xml文件,都是一些重復(fù)且有規(guī)律的工作。我們可以引用插件,然后做配置,自動生成這些文件,本文就來詳細的介紹一下2021-08-08
eclipse/IDEA配置javafx項目步驟(圖文教程)
這篇文章主要介紹了eclipse/IDEA配置javafx項目步驟(圖文教程),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Java語言實現(xiàn)簡單FTP軟件 FTP軟件主界面(4)
這篇文章主要為大家詳細介紹了Java語言實現(xiàn)簡單FTP軟件,F(xiàn)TP軟件主界面編寫的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
淺析Java如何優(yōu)雅的設(shè)計接口狀態(tài)碼和異常
HTTP協(xié)議里定義了一系列的狀態(tài)碼用來表明請求的狀態(tài),如常用的200表示請求正常,404表示請求的資源不存在,所以本文就來和大家討論一下如何優(yōu)雅的設(shè)計接口狀態(tài)碼和異常,感興趣的可以了解下2024-03-03
Windows中在IDEA上安裝和使用JetBrains Mono字體的教程
這篇文章主要介紹了Windows IDEA上安裝和使用JetBrains Mono字體的教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03

