POI结构与常用类

Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 .NET的开发人员则可以利用NPOI (POI for .NET) 来存取 Microsoft Office文档的功能。

包名称说明

  • HSSF提供读写Microsoft Excel XLS格式档案的功能。
  • XSSF提供读写Microsoft Excel OOXML XLSX格式档案的功能。
  • HWPF提供读写Microsoft Word DOC格式档案的功能。
  • HSLF提供读写Microsoft PowerPoint格式档案的功能。
  • HDGF提供读Microsoft Visio格式档案的功能。
  • HPBF提供读Microsoft Publisher格式档案的功能。
  • HSMF提供读Microsoft Outlook格式档案的功能。

测试例子

测试模板:

测试代码:

  1. @Test
  2. public void docxExportTest() throws IOException {
  3. InputStream is = null;
  4. FileOutputStream fos = null;
  5. try {
  6. //获取docx解析对象
  7. is = new FileInputStream("F:\\document\\咨询服务合同.docx");
  8. XWPFDocument document = new XWPFDocument(is);
  9.  
  10. //组装参数
  11. File seal = new File("F:\\imgtest\\1.jpg");
  12. Map<String, Object> sealMap = new HashMap<String, Object>();
  13. sealMap.put("width", 50);
  14. sealMap.put("height", 50);
  15. sealMap.put("type", "jpg");
  16. sealMap.put("content", new FileInputStream(seal));
  17.  
  18. Map<String, Object> contentMap = new HashMap<>();
  19. contentMap.put("part_a", "张三");
  20. contentMap.put("address_a", "青岛市市南区动漫产业园E座");
  21. contentMap.put("legal_person_a", "李四");
  22. contentMap.put("seal", sealMap);
  23.  
  24. //解析替换段落文本对象
  25. XWPFUtil.changeParagraph(document, contentMap);
  26.  
  27. //生成新的word文档
  28. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  29. String fileName = "咨询服务合同" + sdf.format(new Date()) + ".docx";
  30. File file = new File("F://" + fileName);
  31. fos = new FileOutputStream(file);
  32. document.write(fos);
  33.  
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. } finally {
  37. if (is != null) {
  38. is.close();
  39. }
  40. if (fos != null) {
  41. fos.close();
  42. }
  43. }
  44. }

工具类:

  1. package com.m2plat.puhui.utils;
  2.  
  3. import com.alibaba.fastjson.JSON;
  4. import org.apache.commons.io.IOUtils;
  5. import org.apache.poi.xwpf.usermodel.XWPFDocument;
  6. import org.apache.poi.xwpf.usermodel.XWPFParagraph;
  7. import org.apache.poi.xwpf.usermodel.XWPFRun;
  8. import org.apache.xmlbeans.XmlException;
  9. import org.apache.xmlbeans.XmlToken;
  10. import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
  11. import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
  12. import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
  13. import org.slf4j.Logger;
  14. import org.slf4j.LoggerFactory;
  15. import org.springframework.core.io.ClassPathResource;
  16.  
  17. import java.io.FileInputStream;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;
  21. import java.util.List;
  22. import java.util.Map;
  23.  
  24. /**
  25. * Created by xiangzh on 2018/11/1.
  26. */
  27. public class XWPFUtils {
  28.  
  29. private static Logger logger = LoggerFactory.getLogger(XWPFUtils.class);
  30.  
  31. /**
  32. * 根据模板生成word文档
  33. * @param os
  34. * @param tempPath
  35. * @param contentMap
  36. */
  37. public static void writeTemp(OutputStream os, String tempPath, Map<String, Object> contentMap){
  38. logger.info("---根据模板生成word文档");
  39. logger.info("---模板地址:{}",tempPath);
  40. logger.info("---替换内容:{}", JSON.toJSONString(contentMap));
  41. ClassPathResource resource = new ClassPathResource(tempPath);
  42. if(resource == null || !resource.exists()){
  43. logger.error("---模板文件不存在,tempPath:{}",tempPath);
  44. return;
  45. }
  46.  
  47. InputStream is = null;
  48. try{
  49. is = resource.getInputStream();
  50. XWPFDocument document = new XWPFDocument(is);
  51. XWPFUtils.changeParagraph(document, contentMap);
  52. //生成新的word文档
  53. document.write(os);
  54. }catch (IOException e){
  55. logger.error("---输出word文档失败,原因:{}",e.getMessage());
  56. }finally {
  57. IOUtils.closeQuietly(is);
  58. }
  59. }
  60.  
  61. /**
  62. * 替换段落文本
  63. *
  64. * @param document docx解析对象
  65. * @param textMap 需要替换的信息集合
  66. */
  67. public static void changeParagraph(XWPFDocument document, Map<String, Object> textMap) {
  68. //获取段落集合
  69. List<XWPFParagraph> paragraphs = document.getParagraphs();
  70.  
  71. for (XWPFParagraph paragraph : paragraphs) {
  72. List<XWPFRun> runs = paragraph.getRuns();
  73. for (XWPFRun run : runs) {
  74. String text = run.getText(0);
  75. //判断文本是否需要进行替换
  76. if (checkText(text)) {
  77. for (Map.Entry<String, Object> entry : textMap.entrySet()) {
  78. //匹配模板与替换值 格式${key}
  79. String key = "${" + entry.getKey() + "}";
  80. Object value = entry.getValue();
  81.  
  82. if (text.contains(key)) {
  83. if (value instanceof String) { //文字替换
  84. text = text.replace(key, (String) value);
  85. } else if (value instanceof Map) { //图片替换
  86. text = text.replace(key, "");
  87. Map picMap = (Map) value;
  88. int width = Integer.parseInt(picMap.get("width").toString());
  89. int height = Integer.parseInt(picMap.get("height").toString());
  90. int picType = getPictureType(picMap.get("type").toString());
  91. FileInputStream fis = (FileInputStream) picMap.get("content");
  92. try {
  93. String blipId = document.addPictureData(fis, picType);
  94. int id = document.getNextPicNameNumber(picType);
  95. XWPFUtils.createPicture(id, blipId, width, height, run);
  96. } catch (Exception e) {
  97. e.printStackTrace();
  98. }
  99. }
  100. }
  101. }
  102. //替换模板原来位置
  103. run.setText(text, 0);
  104. }
  105. }
  106. }
  107. }
  108.  
  109. /**
  110. * @param id
  111. * @param blipId
  112. * @param width 宽
  113. * @param height 高
  114. //* @param paragraph 段落
  115. */
  116. private static void createPicture(int id, String blipId, int width, int height,XWPFRun xwpfRun) {
  117. final int EMU = 9525;
  118. width *= EMU;
  119. height *= EMU;
  120. CTInline inline = xwpfRun.getCTR().addNewDrawing().addNewInline();
  121. //CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline(); //在遍历run列表的时候,创建新的run有可能会导致报错
  122. String picXml = ""
  123. + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
  124. + " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
  125. + " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
  126. + " <pic:nvPicPr>" + " <pic:cNvPr id=\""
  127. + id
  128. + "\" name=\"Generated\"/>"
  129. + " <pic:cNvPicPr/>"
  130. + " </pic:nvPicPr>"
  131. + " <pic:blipFill>"
  132. + " <a:blip r:embed=\""
  133. + blipId
  134. + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
  135. + " <a:stretch>"
  136. + " <a:fillRect/>"
  137. + " </a:stretch>"
  138. + " </pic:blipFill>"
  139. + " <pic:spPr>"
  140. + " <a:xfrm>"
  141. + " <a:off x=\"0\" y=\"0\"/>"
  142. + " <a:ext cx=\""
  143. + width
  144. + "\" cy=\""
  145. + height
  146. + "\"/>"
  147. + " </a:xfrm>"
  148. + " <a:prstGeom prst=\"rect\">"
  149. + " <a:avLst/>"
  150. + " </a:prstGeom>"
  151. + " </pic:spPr>"
  152. + " </pic:pic>"
  153. + " </a:graphicData>" + "</a:graphic>";
  154.  
  155. inline.addNewGraphic().addNewGraphicData();
  156. XmlToken xmlToken = null;
  157. try {
  158. xmlToken = XmlToken.Factory.parse(picXml);
  159. } catch (XmlException xe) {
  160. xe.printStackTrace();
  161. }
  162. inline.set(xmlToken);
  163.  
  164. inline.setDistT(0);
  165. inline.setDistB(0);
  166. inline.setDistL(0);
  167. inline.setDistR(0);
  168.  
  169. CTPositiveSize2D extent = inline.addNewExtent();
  170. extent.setCx(width);
  171. extent.setCy(height);
  172.  
  173. CTNonVisualDrawingProps docPr = inline.addNewDocPr();
  174. docPr.setId(id);
  175. docPr.setName("docx_img_ " + id);
  176. docPr.setDescr("docx Picture");
  177. }
  178.  
  179. /**
  180. * 判断文本中是否包含$
  181. *
  182. * @param text 文本
  183. * @return 包含返回true, 不包含返回false
  184. */
  185. private static boolean checkText(String text) {
  186. if (text == null || "".equals(text)) {
  187. return false;
  188. }
  189. return text.contains("$");
  190. }
  191.  
  192. /**
  193. * 根据图片类型,取得对应的图片类型代码
  194. *
  195. * @param picType
  196. * @return int
  197. */
  198. private static int getPictureType(String picType) {
  199. int res = XWPFDocument.PICTURE_TYPE_PICT;
  200. if (picType != null) {
  201. if (picType.equalsIgnoreCase("png")) {
  202. res = XWPFDocument.PICTURE_TYPE_PNG;
  203. } else if (picType.equalsIgnoreCase("dib")) {
  204. res = XWPFDocument.PICTURE_TYPE_DIB;
  205. } else if (picType.equalsIgnoreCase("emf")) {
  206. res = XWPFDocument.PICTURE_TYPE_EMF;
  207. } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
  208. res = XWPFDocument.PICTURE_TYPE_JPEG;
  209. } else if (picType.equalsIgnoreCase("wmf")) {
  210. res = XWPFDocument.PICTURE_TYPE_WMF;
  211. }
  212. }
  213. return res;
  214. }
  215. }

测试结果:

注意事项

1.实际开发过程中,模板通常存放在项目工程中,获取模板的代码如下:

  1. String tempPath = "static/exportTemplates/咨询服务合同.docx";
  2. ClassPathResource resource = new ClassPathResource(tempPath);
  3. InputStream is = resource.getInputStream();
  4. XWPFDocument document = new XWPFDocument(is);

2.导出文件时如果报错:Failed to read zip entry source,是因为打包编译将文件解压缩导致出问题,解决办法为在pom文件中配置nonFilteredFileExtension:

  1. <plugin>
  2. <artifactId>maven-resources-plugin</artifactId>
  3. <version>2.6</version>
  4. <configuration>
  5. <delimiters>
  6. <delimiter>@</delimiter>
  7. <delimiter>${*}</delimiter>
  8. </delimiters>
  9. <useDefaultDelimiters>false</useDefaultDelimiters>
  10. <encoding>UTF-8</encoding><!-- 指定编码格式,否则在DOS下运行mvn命令时当发生文件资源copy时将使用系统默认使用GBK编码 -->
  11. <nonFilteredFileExtensions>
  12. <nonFilteredFileExtension>bar</nonFilteredFileExtension>
  13. <nonFilteredFileExtension>zip</nonFilteredFileExtension>
  14. <nonFilteredFileExtension>txt</nonFilteredFileExtension>
  15. <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
  16. <nonFilteredFileExtension>ttf</nonFilteredFileExtension>
  17. <nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
  18. <nonFilteredFileExtension>xls</nonFilteredFileExtension>
  19. <nonFilteredFileExtension>docx</nonFilteredFileExtension>
  20. <nonFilteredFileExtension>doc</nonFilteredFileExtension>
  21. </nonFilteredFileExtensions>
  22. </configuration>
  23. </plugin>

 3.所有导出参数必须转换成string类型后才能导出,否则替换不了。

参考:

POI使用详解

POI通过XWPFDocument方式操作word2007

POI操作word模板并生成新的word.docx

war在服务器上读取文件报:java.io.IOException: Failed to read zip entry source

SpringBoot打成jar包后,读取resources目录下的文件

 

poi根据模板导出word文档的更多相关文章

  1. 使用Spire.Doc组件利用模板导出Word文档

    以前一直是用Office的组件实现Word文档导出,但是让客户在服务器安装Office,涉及到版权:而且Office安装,包括权限配置也是比较麻烦. 现在流行使用第三方组件来实现对Office的操作, ...

  2. 前台导出Word文档思路步骤总结(freemarker)

    1. 需求是导出word带表格,表格列数不变,行数由数据库的值决定: 2. 导出最开始想的是直接前端导出,使用了jquery-wordexport插件,导出后,表格边框全没了,无法使用: 3. 采用了 ...

  3. .NET通过调用Office组件导出Word文档

    .NET通过调用Office组件导出Word文档 最近做项目需要实现一个客户端下载word表格的功能,该功能是用户点击"下载表格",服务端将该用户的数据查询出来并生成数据到Word ...

  4. C# 导出word文档及批量导出word文档(1)

         这里用到了两个dll,一个是aspose.word.dll,另外一个是ICSharpCode.SharpZipLib.dll,ICSharpCode.SharpZipLib.dll是用于批量 ...

  5. C# 导出word文档及批量导出word文档(4)

          接下来是批量导出word文档和批量打印word文件,批量导出word文档和批量打印word文件的思路差不多,只是批量打印不用打包压缩文件,而是把所有文件合成一个word,然后通过js来调用 ...

  6. C#导出Word文档开源组件DocX

    1.帮助文档,这东西找了很久,而且它版本很旧,还是英文,W8.1系统上打不开 http://download.csdn.net/detail/zuofangyouyuan/7673573 2.开源网址 ...

  7. Java 用Freemarker完美导出word文档(带图片)

    Java  用Freemarker完美导出word文档(带图片) 前言 最近在项目中,因客户要求,将页面内容(如合同协议)导出成word,在网上翻了好多,感觉太乱了,不过最后还是较好解决了这个问题. ...

  8. freemarker导出word文档

    使用freemarker导出word文档的过程 **************************************************************************** ...

  9. 【Java】导出word文档之freemarker导出

    Java导出word文档有很多种方式,本例介绍freemarker导出,根据现有的word模板进行导出 一.简单导出(不含循环导出) 1.新建一个word文件.如下图: 2.使用word将文件另存为x ...

随机推荐

  1. Linux使用expect实现自动登录的脚本

    前提条件服务器已经安装过tcl和expect, 若未安装:可以先执行 yum  install tcl  expect  进行安装 第一步.编写以下自动登录脚本login.sh ########### ...

  2. 如何快捷地使用ChemBio 3D检查结构信息

    ChemBio 3D是一款三维分子结构演示软件,能够轻松快捷地进行化学结构的制作和立体旋转.ChemBio 3D Ultra 14作为ChemBio 3D的最新版本可以更加快捷地制作化学结构.本教程将 ...

  3. python文件和目录操作方法大全(含实例)【python】

    转自:http://www.jb51.net/article/48001.htm 一.python中对文件.文件夹操作时经常用到的os模块和shutil模块常用方法. 1.得到当前工作目录,即当前Py ...

  4. upper()

    upper() 用于把字符串中的小写字母转换成大写字母 In [1]: str = "Hello World" In [2]: str.upper() Out[2]: 'HELLO ...

  5. 开源项目源码解析-PhotoView 源码解析

    1. 功能介绍 特性(Features): 支持 Pinch 手势自由缩放. 支持双击放大/还原. 支持平滑滚动. 在滑动父控件下能够运行良好.(例如:ViewPager) 支持基于 Matrix 变 ...

  6. IIC协议

    总线信号 :  SDA :串行数据线 SCL  :串行时钟 总线空闲状态 : SDA :高电平 SCL :高电平 起始位:SCL为高电平期间    SDA出现下降沿 终止位:SCL为高电平期间 SDA ...

  7. Android 基于帧布局实现一个进度条 FrameLayout+ProgressBar

    在FrameLayout中添加一个ProgressBar居中 <ProgressBar android:layout_gravity="center" android:id= ...

  8. Apktool源码解析——第二篇

    上一篇讲到ApkDecoder这个类,大部分调用到还是Androlib类,而且上次发现brutall的代码竟然不是最新的,遂去找iBotP.的代码了. 今天来看Androlib的代码: private ...

  9. c++11——lambda表达式

    lambda表达式 函数式编程的一个语法,有如下优点: (1)声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象.以更直接的方式写程序,好的可读性和可维护性. (2) ...

  10. Java多线程详解(二)

    评论区留下邮箱可获得<Java多线程设计模式详解> 转载请指明来源 1)后台线程 后台线程是为其他线程服务的一种线程,像JVM的垃圾回收线程就是一种后台线程.后台线程总是等到非后台线程死亡 ...