2021年2月8日星期一

Java操作Word('docx'), 填充模板文件并转为pdf

Java操作Word('docx'), 填充模板文件并转为pdf

1. pom相关依赖

工具poi-tl (操作word文档模板) + jacob (将操作后的word模板转为pdf)

<!-- poi-tl的pom依赖 --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.9.1</version></dependency>
<!-- 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.

image-20210129171147108

// 项目根路径String abPath = new File("").getAbsolutePath() + "/src/main/resources";// 创建用于插入数据的MapMap<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需要操作的表格中的任意单元格添加标签"{{标签}}"

image-20210129171116435

自定义渲染策略

/** * 自定义渲染策略 * * @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));   }  } }}

把自定义渲染策略当做工具类, 在主逻辑中直接配置使用

	/**  * 操作年度任务和考核指标表  *  * @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"); }

用到的一些实体类

// PageDatapublic class PageData { @Name("detail_table") private NdrwhkhzbData ndrwhkhzbData; public NdrwhkhzbData getNdrwhkhzbData() {  return ndrwhkhzbData; } public void setNdrwhkhzbData(NdrwhkhzbData ndrwhkhzbData) {  this.ndrwhkhzbData = ndrwhkhzbData; }}// NdrwhkhzbDatapublic 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文件

 /*	* 将 .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流将生成好的文件传到浏览器下载

/* * 下载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;/** * 创建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", "一"); }}








原文转载:http://www.shaoqun.com/a/540609.html

跨境电商:https://www.ikjzd.com/

csa:https://www.ikjzd.com/w/904

prime:https://www.ikjzd.com/w/129


Java操作Word('docx'),填充模板文件并转为pdf1.pom相关依赖工具poi-tl(操作word文档模板)+jacob(将操作后的word模板转为pdf)<!--poi-tl的pom依赖--><dependency><groupId>com.deepoove</groupId><artifactId>poi-
farfetch:farfetch
百思买:百思买
FBA海派存常见问题有哪些?卖家如何规划旺季物流?:FBA海派存常见问题有哪些?卖家如何规划旺季物流?
口述:洞房夜 老公房事玩反串我笑喷反串老公洞房:口述:洞房夜 老公房事玩反串我笑喷反串老公洞房
来啊,互相伤害啊! 欧盟拟对美国加征215亿美元关税:来啊,互相伤害啊! 欧盟拟对美国加征215亿美元关税

没有评论:

发表评论