java 动态添加行_java使用poi操作word, 支持动态的行(一个占位符插入多条)和表格中动态行, 支持图片)...

模板图

希望可以帮到大家,希望给个start

项目git源码地址

java 动态添加行_java使用poi操作word, 支持动态的行(一个占位符插入多条)和表格中动态行, 支持图片)..._第1张图片

效果图

1,引入maven依赖

org.apache.poi

poi

3.17

org.apache.poi

poi-ooxml

3.17

org.apache.poi

poi-ooxml-schemas

3.17

2,核心工具类

package per.qiao.utils.hutool.poi;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;

import org.apache.poi.openxml4j.opc.OPCPackage;

import org.apache.poi.xwpf.usermodel.*;

import org.apache.xmlbeans.XmlCursor;

import org.junit.Assert;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.util.*;

/**

* Create by IntelliJ Idea 2018.2

*

* @author: qyp

* Date: 2019-10-25 14:48

*/

public class DynWordUtils {

private final Logger logger = LoggerFactory.getLogger(DynWordUtils.class);

/**

* 被list替换的段落 被替换的都是oldParagraph

*/

private XWPFParagraph oldParagraph;

/**

* 参数

*/

private Map paramMap;

/**

* 当前元素的位置

*/

int n = 0;

/**

* 判断当前是否是遍历的表格

*/

boolean isTable = false;

/**

* 模板对象

*/

XWPFDocument templateDoc;

/**

* 默认字体的大小

*/

final int DEFAULT_FONT_SIZE = 10;

/**

* 重复模式的占位符所在的行索引

*/

private int currentRowIndex;

/**

* 入口

*

* @param paramMap 模板中使用的参数

* @param templatePaht 模板全路径

* @param outPath 生成的文件存放的本地全路径

*/

public static void process(Map paramMap, String templatePaht, String outPath) {

DynWordUtils dynWordUtils = new DynWordUtils();

dynWordUtils.setParamMap(paramMap);

dynWordUtils.createWord(templatePaht, outPath);

}

/**

* 生成动态的word

* @param templatePath

* @param outPath

*/

public void createWord(String templatePath, String outPath) {

File inFile = new File(templatePath);

try (FileOutputStream outStream = new FileOutputStream(outPath)) {

templateDoc = new XWPFDocument(OPCPackage.open(inFile));

parseTemplateWord();

templateDoc.write(outStream);

} catch (Exception e) {

StackTraceElement[] stackTrace = e.getStackTrace();

String className = stackTrace[0].getClassName();

String methodName = stackTrace[0].getMethodName();

int lineNumber = stackTrace[0].getLineNumber();

logger.error("错误:第:{}行, 类名:{}, 方法名:{}", lineNumber, className, methodName);

throw new RuntimeException(e.getCause().getMessage());

}

}

/**

* 解析word模板

*/

public void parseTemplateWord() throws Exception {

List elements = templateDoc.getBodyElements();

for (; n < elements.size(); n++) {

IBodyElement element = elements.get(n);

// 普通段落

if (element instanceof XWPFParagraph) {

XWPFParagraph paragraph = (XWPFParagraph) element;

oldParagraph = paragraph;

if (paragraph.getParagraphText().isEmpty()) {

continue;

}

delParagraph(paragraph);

} else if (element instanceof XWPFTable) {

// 表格

isTable = true;

XWPFTable table = (XWPFTable) element;

delTable(table, paramMap);

isTable = false;

}

}

}

/**

* 处理段落

*/

private void delParagraph(XWPFParagraph paragraph) throws Exception {

List runs = oldParagraph.getRuns();

StringBuilder sb = new StringBuilder();

for (XWPFRun run : runs) {

String text = run.getText(0);

if (text == null) {

continue;

}

sb.append(text);

run.setText("", 0);

}

Placeholder(paragraph, runs, sb);

}

/**

* 匹配传入信息集合与模板

*

* @param placeholder 模板需要替换的区域()

* @param paramMap 传入信息集合

* @return 模板需要替换区域信息集合对应值

*/

public void changeValue(XWPFRun currRun, String placeholder, Map paramMap) throws Exception {

String placeholderValue = placeholder;

if (paramMap == null || paramMap.isEmpty()) {

return;

}

Set> textSets = paramMap.entrySet();

for (Map.Entry textSet : textSets) {

//匹配模板与替换值 格式${key}

String mapKey = textSet.getKey();

String docKey = PoiWordUtils.getDocKey(mapKey);

if (placeholderValue.indexOf(docKey) != -1) {

Object obj = textSet.getValue();

// 需要添加一个list

if (obj instanceof List) {

placeholderValue = delDynList(placeholder, (List) obj);

} else {

placeholderValue = placeholderValue.replaceAll(

PoiWordUtils.getPlaceholderReg(mapKey)

, String.valueOf(obj));

}

}

}

currRun.setText(placeholderValue, 0);

}

/**

* 处理的动态的段落(参数为list)

*

* @param placeholder 段落占位符

* @param obj

* @return

*/

private String delDynList(String placeholder, List obj) {

String placeholderValue = placeholder;

List dataList = obj;

Collections.reverse(dataList);

for (int i = 0, size = dataList.size(); i < size; i++) {

Object text = dataList.get(i);

// 占位符的那行, 不用重新创建新的行

if (i == 0) {

placeholderValue = String.valueOf(text);

} else {

XWPFParagraph paragraph = createParagraph(String.valueOf(text));

if (paragraph != null) {

oldParagraph = paragraph;

}

// 增加段落后doc文档会的element的size会随着增加(在当前行的上面添加),回退并解析新增的行(因为可能新增的带有占位符,这里为了支持图片和表格)

if (!isTable) {

n--;

}

}

}

return placeholderValue;

}

/**

* 创建段落

*

* @param texts

*/

public XWPFParagraph createParagraph(String... texts) {

// 使用游标创建一个新行

XmlCursor cursor = oldParagraph.getCTP().newCursor();

XWPFParagraph newPar = templateDoc.insertNewParagraph(cursor);

// 设置段落样式

newPar.getCTP().setPPr(oldParagraph.getCTP().getPPr());

copyParagraph(oldParagraph, newPar, texts);

return newPar;

}

/**

* 处理表格(遍历)

*

* @param table 表格

* @param paramMap 需要替换的信息集合

*/

public void delTable(XWPFTable table, Map paramMap) throws Exception

你可能感兴趣的:(java,动态添加行)