package com.sisa.auweb.tools.bookmarkprocess;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.impl.piccolo.io.FileFormatException; import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import static feign.Util.toByteArray; /**
* Created by clyan on 2019/7/2 15:15.
*/
public class Word2007 {
private String wordPath = "";
private String writeFilePath = "";
private Object obj = null;
Map<String, Object> map = new HashMap<String, Object>(); /*
path:文件路径
dataSource/objectMap:数据源.
*/
public Word2007(String path, String newFilePath, Object dataSource, Map<String, Object> objectMap) throws IOException { File file = new File(path); if (file.exists() == false || file.isFile() == false) {
throw new FileNotFoundException("文件不存在");
} InputStream is = new FileInputStream(file);
byte[] bytes = new byte[10]; if (is.read(bytes, 0, bytes.length) == -1) {
is.close();
throw new FileFormatException("文件格式错误,本文件只能解析docx文件");
}
String fileCode = bytesToHexString(bytes).toLowerCase(); if (fileCode.length() > 1) {
if (fileCode.equals("504b0304140006000800") == false) {
is.close();
throw new FileFormatException("文件格式错误,本文件只能解析docx文件");
}
}
is.close(); wordPath = path;
writeFilePath = newFilePath;
obj = dataSource; if (dataSource != null) {
pickFields();
} else {
this.map = objectMap;
}
} public void parseTemplate() { try {
InputStream is = new FileInputStream(wordPath);
XWPFDocument doc = new XWPFDocument(OPCPackage.open(is));
List<XWPFParagraph> list = doc.getParagraphs(); for (int i = 0; i < list.size(); i++) {
XWPFParagraph graph = list.get(i);
replaceInXWPFParagraph(graph, map);
}
replaceTables(map, doc);
OutputStream os = new FileOutputStream(writeFilePath);
doc.write(os);
os.flush();
close(os);
close(is); } catch (Exception ex) {
System.out.print(ex.getStackTrace());
}
} private void replaceInXWPFParagraph(XWPFParagraph para, Map<String, Object> params) { List<XWPFRun> runs = null;
Matcher matcher;
String runText = ""; if (matcher(para.getParagraphText()).find()) {
runs = para.getRuns();
if (runs.size() > 0) {
int j = runs.size();
for (int i = 0; i < j; i++) {
XWPFRun run = runs.get(i);
String i1 = run.toString();
runText += i1;
}
}
int replaceCount = runText.trim().split("\\$").length - 1;
matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
runText = String.valueOf(params.get(matcher.group(1)));
}
//数据源不存在时跳过,以便检查
if (runText.equals("null")) {
runText = "";
}
if (runs.size() > 0) {
boolean handler = false;
for (int i = 0; i < runs.size(); i++) { XWPFRun run = runs.get(i);
String temp = run.toString(); if (handler == false && temp.indexOf("$") >= 0) {
handler = true;
}
if (handler == true) {
if (temp.equals("$") || temp.indexOf("$") == 0) {
if (temp.indexOf("}") >= 0) {
run.setText(runText, 0);
handler = false;
//一行有多个${情况
replaceCount--;
if (replaceCount > 0) {
runText = "";
int j = runs.size();
for (int x = 0; x < j; x++) {
XWPFRun run1 = runs.get(x);
String i1 = run1.toString();
runText += i1;
}
matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
runText = String.valueOf(params.get(matcher.group(1)));
}
}
}
} else {
run.setText("", 0);
}
continue;
}
if (temp.indexOf("}") < 0) {
run.setText("", 0);
continue;
}
if (temp.indexOf("}") >= 0) {
run.setText(runText, 0);
handler = false;
//一行有多个${情况
replaceCount--;
if (replaceCount > 0) {
runText = "";
int j = runs.size();
for (int x = 0; x < j; x++) {
XWPFRun run1 = runs.get(x);
String i1 = run1.toString();
runText += i1;
} matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
runText = String.valueOf(params.get(matcher.group(1)));
}
}
}
}
}
}
}
}
}
} private void pickFields() {
Class dataClass = (Class) obj.getClass();
Field[] fs = dataClass.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
f.setAccessible(true);
Object val = new Object();
try {
val = f.get(obj);
map.put(f.getName(), val);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} private byte[] generalFileContent() throws IOException {
InputStream is = new FileInputStream(writeFilePath);
byte[] data = toByteArray(is);
is.close();
return data;
} private void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} private void close(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} private String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (null == src || src.length < 1)
return null;
for (byte b : src) {
int v = b & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2)
stringBuilder.append(0);
stringBuilder.append(hv);
}
return stringBuilder.toString();
} private static Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
} private void replaceTable(Map<String, Object> params, XWPFTable table) {
int count = table.getNumberOfRows();
for (int i = 0; i < count; i++) {
XWPFTableRow row = table.getRow(i);
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> list = cell.getParagraphs();
for (int j = 0; j < list.size(); j++) {
replaceInXWPFParagraph(list.get(j), params);
}
}
}
} private void replaceTables(Map<String, Object> params, XWPFDocument document) {
Iterator<XWPFTable> itTable = document.getTablesIterator();
while (itTable.hasNext()) {
XWPFTable table = itTable.next();
replaceTable(params, table);
}
}
}

Word模板替换的更多相关文章

  1. C#读取Word模板替换相应的字符串(标签)生成新的Word

    在平常工作中,生成word的方式主要是C#读取html的模板文件处理之后保存为.doc文件,这样的好处是方便,快捷,能满足大部分的需求.不过有些特殊的需求并不能满足,如要生成的Word为一个表格,只是 ...

  2. 利用POI 技术动态替换word模板内容

    项目中需要实现一个功能,动态替换给定模板里面的内容,生成word文档提供下载功能. 中间解决了问题有: 1.页眉的文档logo图片解决,刚开始的时候,HWPFDocument 对象无法读取图片对象(已 ...

  3. POI Word 模板 文字 图片 替换

    实验环境:POI3.7+Word2007 Word模板: 替换后效果: 代码: 1.入口文件 public class Test { public static void main(String[] ...

  4. POI不同版本替换Word模板时的问题

    一.问题描述 通过POI,把Word中的占位符替换为实际的值,以生成复杂结构的业务报告. 在POI 3.9上,功能正常.由于某些原因升级到POI 3.10.1后,项目组反馈说Word模板出错,无法生成 ...

  5. word模板导出的几种方式:第一种:占位符替换模板导出(只适用于word中含有表格形式的)

    1.占位符替换模板导出(只适用于word中含有表格形式的): /// <summary> /// 使用替换模板进行到处word文件 /// </summary> public ...

  6. JAVA Freemarker + Word 模板 生成 Word 文档 (普通的变量替换,数据的循环,表格数据的循环,以及图片的东替换)

    1,最近有个需求,动态生成 Word 文当并供前端下载,网上找了一下,发现基本都是用 word 生成 xml 然后用模板替换变量的方式 1.1,这种方式虽然可行,但是生成的 xml 是在是太乱了,整理 ...

  7. C# 操作word 模板 值 替换

    1.引用 aspose.words   dll 2.word 使用doc 3.给word 模板中添加要替换位置的 书签 .引用 aspose.words dll .word 使用doc .给word ...

  8. tp5 使用phpword 替换word模板并利用com组件转换pdf

    tp5   使用phpword 替换word模板并利用com组件转换pdf 一.首先composer安装PHPword,就不多说了 二.然后是把模板中要替换的部分用变量代替 三.把原始的模板文件放入项 ...

  9. poi 针对word模板内容替换

    最近多了一个需求,需要对word模板内容进行替换,一开始用的是word03版的,替换起来比较简单,主要是range对像替换非常方便,而且可以保留替换前的字体样式. InputStream is = n ...

随机推荐

  1. elastic 基本操作

    官方参考文档: https://www.elastic.co/guide/cn/elasticsearch/guide/current/index-doc.html 1.查看 有哪些索引: curl ...

  2. 5.(基础)tornado异步

    终于到了传说中的异步了,感觉异步这个名字听起来就很酷酷的,以前还不是多擅长Python时,就跑去看twisted的源码,结果给我幼小的心灵留下了创伤.反正包括我在内,都知道异步编程很强大,但是却很少在 ...

  3. 查看jar包依赖树

    在eclipse执行如下命令: 可以在控制台上查看层级依赖关系

  4. STL源码阅读-functor与adapter

    为什么要用仿函数 函数指针不灵活,难以与STL其他组件配合使用 Adapter 将一个class的接口转换为另一个class的接口,使原本因接口不兼容而不能合作的classes,可以一起运作 STL中 ...

  5. zabbix的简单操作(proxy代理分布式监控)

    分布式监控 作用:分担压力,减轻负载,多机房监控 通过zabbix proxy的搭建,zabbix server可以远程从proxy获取到数据,这里的环境相当于zabbix server具有一个公网i ...

  6. win10操作系统下oracle11g客户端/服务端的下载安装配置卸载总结

    win10操作系统下oracle11g客户端/服务端的下载安装配置卸载总结 一:前提 注意:现在有两种安装的方式 1. oracle11g服务端(64位)+oracle客户端(32位)+plsql(3 ...

  7. 关于nmap扫描端口

    nmap查看一个服务器的端口,是通过扫描来实现的.所以在本机执行nmap扫描的端口有可能被防火墙阻止,在外部是访问不了的. 如:开启ORACLE监听后,在本机使用nmap 127.0.0.1是可以扫描 ...

  8. git最最最最...常用命令

    使用git 也有一段时间了,但是一直没有好好的去学下:今天刚好有空,就把自己不足的地方补了一下:废话就不多说了,直接步入正题: 1:git 如何提交代码 以及 如何拉代码 git clone可以将远程 ...

  9. Redis的部署使用文档

    Redis的部署使用文档   简述: redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符 串).list(链表).set( ...

  10. IPC 进程间通信方式——消息队列

    消息队列 消息队列是内核中的一个链表 用户进程将数据传输到内核后,内核重新添加一些如用户ID.组ID.读写进程的ID和优先级等相关信息后并打包成一个数据包称为消息 允许一个或多个进程往消息队列中读写消 ...