使用poi,pageOffice合并word操作。主要区别在于
- poi可以进行后台操作,通过各种各样APi接口,直接进行文件io读写操作,,可用于后台操作,pageoffice需要前端预览后保存(根据封装列子,源码修改另行解决)。
- poi对于docx和doc文件兼容不好,提供两套不同api。pageOffice已经封装两类文件。dox转docx本文不做介绍
代码详述
1、poi进行合并
- maven引入poi架包
- poi文档API
<!-- word 操作-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xmlbeans/xmlbeans -->
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>3.1.0</version>
</dependency>
*警告:*部门maven集成时,因为XmlBean架包重读,POi运行报错。自行删除xmlBean架包,使用Poi引入的xmlBean
工具类代码
工具类:
1.ByteArrayInputStream() 获取byte[] 字节流文件
2.wordMergeRetPath() 传入文件地址,生成文件
原理:使用 XWPFDocument.getDocument().getBody().xmlText() 获取xml文件信息。对docx的xml文件操作,拼接头尾数据,加入待拼接doxc的xml数据
package io.fileType.word;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTMarkupRange;
import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: lixiao
* Created Date: 2020/7/3 9:06
* <p>
* 使用pio处理word
*/
public class WordPoiUtil {
public volatile int bookMarkCount = 0;
public static String path = null;
/**
* 默认文件生成地址
* @return
*/
public String localPath() {
String localPath = this.getClass().getResource("/").getPath() + "wordEdit" + File.separator;
File file = new File(localPath);
if (!file.exists()) {
file.mkdir();
}
this.path = localPath;
return path;
}
public WordPoiUtil() {
localPath();
}
/**
* 根据传入文件,返回IO流
* @param inputStreams
* @return
* @throws IOException
* @throws InvalidFormatException
* @throws XmlException
*/
public ByteArrayInputStream wordMergeRetIO(List<InputStream> inputStreams) throws IOException, InvalidFormatException, XmlException {
return wordMerge(inputStreams);
}
/**
* 根据传入文件集合、地址、文件名称生成文件,返回文件全路径
* @param inputStreams
* @param path
* @param fileName
* @return
* @throws IOException
* @throws InvalidFormatException
* @throws XmlException
*/
public String wordMergeRetPath(List<InputStream> inputStreams, String path, String fileName) throws IOException, InvalidFormatException, XmlException {
if (path == null || path == "") {
path = this.path;
}
if (fileName == null || fileName == "") {
fileName = String.valueOf(System.currentTimeMillis()) + String.valueOf((int) Math.random() * 1000) + ".docx";
}
String fileFullPath = path + fileName;
ByteArrayInputStream byteArrayInputStream = wordMerge(inputStreams);
OutputStream outputStream = new FileOutputStream(new File(fileFullPath));
int count = byteArrayInputStream.available();
byte[] bytes = new byte[count];
byteArrayInputStream.read(bytes, 0, count);
outputStream.write(bytes);
outputStream.close();
return fileFullPath;
}
/**
* word合并,返回byte[] 字节流
* @param inputStreams
* @return
* @throws IOException
* @throws InvalidFormatException
* @throws XmlException
*/
protected ByteArrayInputStream wordMerge(List<InputStream> inputStreams) throws IOException, InvalidFormatException, XmlException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Map<BigInteger, BigInteger> mapTemp = new HashMap<>();
XWPFDocument xwpfDoc = null;
//循环处理流文件开始
for (InputStream inputStream : inputStreams) {
XWPFDocument xwpfDocumentOne = new XWPFDocument(inputStream);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++首先处理书签签重排序-----开始++++++++++++++++++++++++++++++
List<XWPFParagraph> paragra = xwpfDocumentOne.getParagraphs();
for (XWPFParagraph xwpfParagraph : paragra) {
//获取书签开始node
List<CTBookmark> bookMarkStart = xwpfParagraph.getCTP().getBookmarkStartList();
//获取书签结束node
List<CTMarkupRange> bookMargEnd = xwpfParagraph.getCTP().getBookmarkEndList();
//循环开始书签更改顺序
for (CTBookmark ctBookmark : bookMarkStart) {
//获取书签当前id
BigInteger id = ctBookmark.getId();
ctBookmark.setId(BigInteger.valueOf(bookMarkCount));
//保存书签新设置的值与原有值,形成map
mapTemp.put(id, BigInteger.valueOf(bookMarkCount));
//新增一次,书签加1
bookMarkCount++;
}
//循环技术书签
for (CTMarkupRange ctMarkupRange : bookMargEnd) {
ctMarkupRange.setId(mapTemp.get(ctMarkupRange.getId()));
}
}
//++++++++++++++++++++++++++++++++++++++++++++++处理书签结束============================================
//初次进入直接复制
if (xwpfDoc == null) {
xwpfDoc = xwpfDocumentOne;
} else {
CTBody src1Body = xwpfDoc.getDocument().getBody();
CTBody src2Body = xwpfDocumentOne.getDocument().getBody();
List<XWPFPictureData> allPictures = xwpfDocumentOne.getAllPictures();
// 记录图片合并前及合并后的ID
Map<String, String> map = new HashMap();
for (XWPFPictureData picture : allPictures) {
String before = xwpfDocumentOne.getRelationId(picture);
//将原文档中的图片加入到目标文档中
String after = xwpfDoc.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
map.put(before, after);
}
XmlOptions optionsOuter = new XmlOptions();
optionsOuter.setSaveOuter();
String appendString = src2Body.xmlText(optionsOuter);
String srcString = src1Body.xmlText();
String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
String sufix = srcString.substring(srcString.lastIndexOf("<"));
String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
//T图片替换
if (map != null && !map.isEmpty()) {
//对xml字符串中图片ID进行替换
for (Map.Entry<String, String> set : map.entrySet()) {
addPart = addPart.replace(set.getKey(), set.getValue());
}
}
//将两个文档的xml内容进行拼接
CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);
String result = makeBody.xmlText();
src1Body.set(makeBody);
}
}
xwpfDoc.write(byteArrayOutputStream);
xwpfDoc.close();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
return byteArrayInputStream;
}
/**
*
* @param args
*/
public static void main(String[] args) {
WordPoiUtil wordPoiUtil = new WordPoiUtil();
List<InputStream> inputStreams = new ArrayList<>();
String fileName = "G:\\toOne\\";
try {
File filePath = new File(fileName);
File[] fileList = filePath.listFiles();
for (File fileOne : fileList) {
FileInputStream fileInputStream = new FileInputStream(fileOne);
inputStreams.add(fileInputStream);
}
System.out.println(wordPoiUtil.wordMergeRetPath(inputStreams, "", ""));
} catch (Exception e) {
e.printStackTrace();
}
}
}
pageOffice合并
1、安装下载pageOffice,网上自行下载 pageOffice官网
原来:使用创建标签和文件插入方法。
//创建标签。标签格式固定为 PO_ 不能改变
DataRegion dataNum = doc.createDataRegion("PO_begin" + (i+1),
DataRegionInsertType.After,"PO_begin"+i);
/**
*两种方式传入word,一种使用网络下载,一种是本地文件名称
*/
//dataNum.setValue("[word]downFile?path=" +files[i].getName()+ "[/word]");
dataNum.setValue("[word]" +files[i].getPath()+ "[/word]");
全dome代码
package com.web.springbootweb.pageOffice;
import com.zhuozhengsoft.pageoffice.FileSaver;
import com.zhuozhengsoft.pageoffice.OpenModeType;
import com.zhuozhengsoft.pageoffice.PageOfficeCtrl;
import com.zhuozhengsoft.pageoffice.wordwriter.DataRegion;
import com.zhuozhengsoft.pageoffice.wordwriter.DataRegionInsertType;
import com.zhuozhengsoft.pageoffice.wordwriter.WordDocument;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: lixiao
* Created Date: 2020/7/6 11:08
*/
@Controller
public class page {
@RequestMapping(value = "/wordShow")
public String wordShow() {
return "wordShow";
}
/**
* 展示简单的word页面
* @param request
* @param map
* @return
*/
@RequestMapping(value = "/word")
public String simpleWord(HttpServletRequest request, Map<String, Object> map) {
PageOfficeCtrl poCtrl = new PageOfficeCtrl(request);
poCtrl.setServerPage(request.getContextPath() + "/poserver.zz");
poCtrl.addCustomToolButton("保存", "Save", 1);
poCtrl.addCustomToolButton("打印设置", "PrintSet", 0);
poCtrl.addCustomToolButton("打印", "PrintFile", 6);
poCtrl.addCustomToolButton("全屏/还原", "IsFullScreen", 4);
poCtrl.addCustomToolButton("-", "", 0);
poCtrl.addCustomToolButton("关闭", "Close", 21);
poCtrl.setSaveFilePage("/save");
poCtrl.webOpen("G:\\docTOone\\2.doc", OpenModeType.docNormalEdit, "光哥");
map.put("pageoffice", poCtrl.getHtmlCode("PageOfficeCtrl1"));
//跳转到word.html
return "word";
}
/**
* 文件数据合并方法
* 例子读取文件夹下是所有文件进行合并
* @param request
* @param map
* @return
* @throws IOException
*/
@RequestMapping(value = "/wordMarge")
public String wordMarge(HttpServletRequest request, Map<String, Object> map) throws IOException {
String Path = "G:\\docTOone";
File file = new File(Path);
File[] files = file.listFiles();
WordDocument doc = new WordDocument();
for (int i=0;i<files.length;i++) {
DataRegion dataNum = doc.createDataRegion("PO_begin" + (i+1),
DataRegionInsertType.After,"PO_begin"+i);
/**
*两种方式传入word,一种使用网络下载,一种是本地文件名称
*/
//dataNum.setValue("[word]downFile?path=" +files[i].getName()+ "[/word]");
dataNum.setValue("[word]" +files[i].getPath()+ "[/word]");
}
PageOfficeCtrl pageOfficeCtrl=new PageOfficeCtrl(request);
pageOfficeCtrl.setServerPage(request.getContextPath() + "/poserver.zz");
pageOfficeCtrl.addCustomToolButton("保存", "Save", 1);
pageOfficeCtrl.setSaveFilePage("save");
pageOfficeCtrl.setWriter(doc);
pageOfficeCtrl.webOpen("G:\\publicWordMarge.doc",OpenModeType.docNormalEdit,"nihao");
map.put("pageoffice", pageOfficeCtrl.getHtmlCode("PageOfficeCtrl1"));
return "wordMarge";
}
/**
* 保存方法入口
* @param request
* @param response
* @return
* @throws IOException
*/
@ResponseBody
@RequestMapping(value = "/save")
public String save(HttpServletRequest request, HttpServletResponse response) throws IOException {
FileSaver fs = new FileSaver(request, response);
FileOutputStream fileOutputStream=new FileOutputStream(new File("G:\\last.doc"));
/**
* 也可以获取byte字节流
*/
fileOutputStream.write(fs.getFileBytes());
fileOutputStream.flush();
fileOutputStream.close();
return "";
}
public static byte[] File2byte(File tradeFile){
byte[] buffer = null;
try
{
FileInputStream fis = new FileInputStream(tradeFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1)
{
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
return buffer;
}
@RequestMapping(value = "/downFile")
public HttpServletResponse download(String path, HttpServletResponse response) {
try {
// path是指欲下载的文件的路径。
path="G:\\docTOone\\"+path;
File file = new File(path);
// 取得文件名。
String filename = file.getName();
// 取得文件的后缀名。
String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
// 以流的形式下载文件。
InputStream fis = new BufferedInputStream(new FileInputStream(path));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
// 清空response
response.reset();
// 设置response的Header
response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
response.addHeader("Content-Length", "" + file.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return response;
}
}
码云地址:https://gitee.com/kissingthefire/javaBase/tree/master/src/main/java/io/fileType/word
https://gitee.com/kissingthefire/springbootweb/tree/master/src/main/java/com/web/springbootweb