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格式档案的功能。

测试例子

测试模板:

测试代码:

@Test
public void docxExportTest() throws IOException {
InputStream is = null;
FileOutputStream fos = null;
try {
//获取docx解析对象
is = new FileInputStream("F:\\document\\咨询服务合同.docx");
XWPFDocument document = new XWPFDocument(is); //组装参数
File seal = new File("F:\\imgtest\\1.jpg");
Map<String, Object> sealMap = new HashMap<String, Object>();
sealMap.put("width", 50);
sealMap.put("height", 50);
sealMap.put("type", "jpg");
sealMap.put("content", new FileInputStream(seal)); Map<String, Object> contentMap = new HashMap<>();
contentMap.put("part_a", "张三");
contentMap.put("address_a", "青岛市市南区动漫产业园E座");
contentMap.put("legal_person_a", "李四");
contentMap.put("seal", sealMap); //解析替换段落文本对象
XWPFUtil.changeParagraph(document, contentMap); //生成新的word文档
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String fileName = "咨询服务合同" + sdf.format(new Date()) + ".docx";
File file = new File("F://" + fileName);
fos = new FileOutputStream(file);
document.write(fos); } catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
}
}

工具类:

package com.m2plat.puhui.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.io.IOUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource; import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map; /**
* Created by xiangzh on 2018/11/1.
*/
public class XWPFUtils { private static Logger logger = LoggerFactory.getLogger(XWPFUtils.class); /**
* 根据模板生成word文档
* @param os
* @param tempPath
* @param contentMap
*/
public static void writeTemp(OutputStream os, String tempPath, Map<String, Object> contentMap){
logger.info("---根据模板生成word文档");
logger.info("---模板地址:{}",tempPath);
logger.info("---替换内容:{}", JSON.toJSONString(contentMap));
ClassPathResource resource = new ClassPathResource(tempPath);
if(resource == null || !resource.exists()){
logger.error("---模板文件不存在,tempPath:{}",tempPath);
return;
} InputStream is = null;
try{
is = resource.getInputStream();
XWPFDocument document = new XWPFDocument(is);
XWPFUtils.changeParagraph(document, contentMap);
//生成新的word文档
document.write(os);
}catch (IOException e){
logger.error("---输出word文档失败,原因:{}",e.getMessage());
}finally {
IOUtils.closeQuietly(is);
}
} /**
* 替换段落文本
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeParagraph(XWPFDocument document, Map<String, Object> textMap) {
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs(); for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
//判断文本是否需要进行替换
if (checkText(text)) {
for (Map.Entry<String, Object> entry : textMap.entrySet()) {
//匹配模板与替换值 格式${key}
String key = "${" + entry.getKey() + "}";
Object value = entry.getValue(); if (text.contains(key)) {
if (value instanceof String) { //文字替换
text = text.replace(key, (String) value);
} else if (value instanceof Map) { //图片替换
text = text.replace(key, "");
Map picMap = (Map) value;
int width = Integer.parseInt(picMap.get("width").toString());
int height = Integer.parseInt(picMap.get("height").toString());
int picType = getPictureType(picMap.get("type").toString());
FileInputStream fis = (FileInputStream) picMap.get("content");
try {
String blipId = document.addPictureData(fis, picType);
int id = document.getNextPicNameNumber(picType);
XWPFUtils.createPicture(id, blipId, width, height, run);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//替换模板原来位置
run.setText(text, 0);
}
}
}
} /**
* @param id
* @param blipId
* @param width 宽
* @param height 高
//* @param paragraph 段落
*/
private static void createPicture(int id, String blipId, int width, int height,XWPFRun xwpfRun) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
CTInline inline = xwpfRun.getCTR().addNewDrawing().addNewInline();
//CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline(); //在遍历run列表的时候,创建新的run有可能会导致报错
String picXml = ""
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=\""
+ id
+ "\" name=\"Generated\"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=\""
+ blipId
+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x=\"0\" y=\"0\"/>"
+ " <a:ext cx=\""
+ width
+ "\" cy=\""
+ height
+ "\"/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst=\"rect\">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>"; inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken); inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0); CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height); CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("docx_img_ " + id);
docPr.setDescr("docx Picture");
} /**
* 判断文本中是否包含$
*
* @param text 文本
* @return 包含返回true, 不包含返回false
*/
private static boolean checkText(String text) {
if (text == null || "".equals(text)) {
return false;
}
return text.contains("$");
} /**
* 根据图片类型,取得对应的图片类型代码
*
* @param picType
* @return int
*/
private static int getPictureType(String picType) {
int res = XWPFDocument.PICTURE_TYPE_PICT;
if (picType != null) {
if (picType.equalsIgnoreCase("png")) {
res = XWPFDocument.PICTURE_TYPE_PNG;
} else if (picType.equalsIgnoreCase("dib")) {
res = XWPFDocument.PICTURE_TYPE_DIB;
} else if (picType.equalsIgnoreCase("emf")) {
res = XWPFDocument.PICTURE_TYPE_EMF;
} else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
res = XWPFDocument.PICTURE_TYPE_JPEG;
} else if (picType.equalsIgnoreCase("wmf")) {
res = XWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}
}

测试结果:

注意事项

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

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

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

<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
<delimiter>${*}</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
<encoding>UTF-8</encoding><!-- 指定编码格式,否则在DOS下运行mvn命令时当发生文件资源copy时将使用系统默认使用GBK编码 -->
<nonFilteredFileExtensions>
<nonFilteredFileExtension>bar</nonFilteredFileExtension>
<nonFilteredFileExtension>zip</nonFilteredFileExtension>
<nonFilteredFileExtension>txt</nonFilteredFileExtension>
<nonFilteredFileExtension>pdf</nonFilteredFileExtension>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
<nonFilteredFileExtension>docx</nonFilteredFileExtension>
<nonFilteredFileExtension>doc</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</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. Yii2自带验证码实现

    总共分为三个方面:控制器配置.模型rules配置和视图配置. 第一步:控制器配置 将下列代码配置在actions中,请求验证码链接对应为 “控制器/captcha” 'captcha' => [ ...

  2. 数字转人民币大写(SQL SERVER)

    --数字转人民币大写NumToRMB ---新建方法create  FUNCTION dbo.NumToRMB (@num numeric(14,5))   RETURNS varchar(100) ...

  3. oracle之trunc(sysdate)

    --截取后得到的仍为date数据类型 select trunc(sysdate) from dual;--2017-03-13 00:00:00select trunc(sysdate+1) from ...

  4. Oracle Apex 有用笔记系列 2 - 文件上传管理

    1. 页面设计 页面A有若干region, 当中一个region用于文件列表管理(包含显示,下载.删除).如图A. 在页面A有一button,点击它会调用页面B,页面B负责文件上传.如图B. 图A 图 ...

  5. ios 添加动画的方法

    转自文顶顶大神的博客:http://www.cnblogs.com/wendingding/p/3751519.html ios 开发UI中,经常会用添加动画效果的需求,下面就总结一下,添加动画的三种 ...

  6. NodeJS-002-Expres启动

    1.打开app.js文件 2.在module.exports = app;之前输入: app.listen(8100,function(){ console.log("Server Star ...

  7. laravel 强大的关联模型

    内容比较多,不总结了,直接看学院君的译文吧,已经写得很详细了 传送门:http://laravelacademy.org/post/6191.html PS1: laravel的关联模型并不是遍历一次 ...

  8. php 获取图片base64编码格式数据

    $image_file = '1.jpg'; $image_info = getimagesize($image_file); $base64_image_content = "data:{ ...

  9. LinkedBlockingQueue(lbq)阻塞队列

    最近开发中,经常使用这个类LinkedBlockingQueue,它是BlockingQueue这个子类. 并发库中的BlockingQueue是一个比较好玩的类,顾名思义,就是阻塞队列.该类主要提供 ...

  10. CSS3 属性组参考资料

    CSS 属性组: 动画 背景 边框和轮廓 盒(框) 颜色 内容分页媒体 定位 可伸缩框 字体 生成内容 网格 超链接 行框 列表 外边距 Marquee 多列 内边距 分页媒体 定位 打印 Ruby ...