目录
前言
很多时候都要根据word模板,往里面填充内容,如下图所示,有各种各样不同的表,要往里面填充数据,此处记录代码,以防后续也用。
代码
package com.fable.ntzw.report.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
/**
* @author lw
* @date 2019/11/30 0030
* @description
* word工具类
*/
@Slf4j
public class WordToNewWordUtils {
//每个表格多少表头
private static int[] headCount = new int[]{2,2,2,2,2,2,2,2,1,1,2,2,2,2};
//每个表格列数
private static int[] cellsCount = new int[]{8,8,8,8,7,7,11,11,8,8,6,6,7,7};
private static int nowTableIndex = -1;
/**
* 根据模板生成新word文档
* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
* @param inputUrl 模板存放地址
* @param outputUrl 新文档存放地址
* @param textMap 需要替换的信息集合
* @param tableList 需要插入的表格信息集合
* @return 成功返回true,失败返回false
*/
public static boolean changWord(String inputUrl, String outputUrl,
Map<String, String> textMap, List<List<List<String>>> tableList) {
//模板转换默认成功
boolean changeFlag = true;
nowTableIndex = -1;
try {
//获取docx解析对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//解析替换文本段落对象
WordToNewWordUtils.changeText(document, textMap);
//解析替换表格对象
WordToNewWordUtils.changeTable(document, textMap, tableList);
//生成新的word
File file = new File(outputUrl);
FileOutputStream stream = new FileOutputStream(file);
document.write(stream);
stream.close();
} catch (IOException e) {
log.error("生成word文档:",e);
changeFlag = false;
}
return changeFlag;
}
/**
* 替换段落文本
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeText(XWPFDocument document, Map<String, String> textMap){
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
if(checkText(text)){
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
run.setText(changeValue(run.toString(), textMap),0);
}
}
}
}
/**
* 替换表格对象方法
* @param document docx解析对象
* @param textMap 需要替换的信息集合
* @param tableList 需要插入的表格信息集合
*/
public static void changeTable(XWPFDocument document, Map<String, String> textMap,
List<List<List<String>>> tableList){
//获取表格对象集合
List<XWPFTable> tables = document.getTables();
for (int i = 0; i < tables.size(); i++) {
//只处理行数大于等于2的表格,且不循环表头
XWPFTable table = tables.get(i);
if(table.getRows().size()>1){
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if(checkText(table.getText())){
List<XWPFTableRow> rows = table.getRows();
//遍历表格,并替换模板
eachTable(rows, textMap);
}else{
// System.out.println("插入"+table.getText());
List<List<String>> oneTableContent = tableList.get(i);
nowTableIndex++;
insertTable(table, oneTableContent);
}
}
}
}
/**
* 遍历表格
* @param rows 表格行对象
* @param textMap 需要替换的信息集合
*/
public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if(checkText(cell.getText())){
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
run.setText(changeValue(run.toString(), textMap),0);
}
}
}
}
}
}
/**
* 为表格插入数据,行数不够添加新行
* @param table 需要插入数据的表格
* @param tableList 插入数据集合
*/
public static void insertTable(XWPFTable table, List<List<String>> tableList){
if(tableList==null||tableList.size()==0){
return;
}
XWPFTableRow modelRow = table.getRow(headCount[nowTableIndex]);
//创建行,根据需要插入的数据添加新行,不处理表头
for(int i = 1; i < tableList.size(); i++){
XWPFTableRow row =table.createRow();
// XWPFTableRow row = table.insertNewTableRow(headCount[nowTableIndex]+1);
//创建行,根据第一行创建的,导致表头合并单位格影响了列数
List<XWPFTableCell> cells = row.getTableCells();
int minusCell = cellsCount[nowTableIndex]-cells.size();
for (int j = 0; j < minusCell; j++) {
row.addNewTableCell();
}
//行属性复制
row.getCtRow().setTrPr(modelRow.getCtRow().getTrPr());
cells = row.getTableCells();
for (int i1 = 0; i1 < cells.size(); i1++) {
XWPFTableCell modelCell = modelRow.getCell(i1);
//列属性复制
cells.get(i1).getCTTc().setTcPr(modelCell.getCTTc().getTcPr());
//段落属性复制
if(modelCell.getParagraphs()!=null&&modelCell.getParagraphs().size()>0){
cells.get(i1).getParagraphs().get(0).getCTP().setPPr(modelCell.getParagraphs().get(0).getCTP().getPPr());
}
}
}
//遍历表格插入数据
List<XWPFTableRow> rows = table.getRows();
int contentIndex = 0;
for(int i = headCount[nowTableIndex]; i < rows.size(); i++,contentIndex++){
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
for(int j = 0; j < cells.size(); j++){
XWPFTableCell cell = cells.get(j);
try{
cell.setText(tableList.get(contentIndex).get(j));
}catch (Exception e){
log.info(contentIndex+":"+nowTableIndex+":"+rows.size()+":"+cells.size());
}
}
}
}
/**
* 判断文本中时候包含$
* @param text 文本
* @return 包含返回true,不包含返回false
*/
public static boolean checkText(String text){
boolean check = false;
if(text.indexOf("$")!= -1){
check = true;
}
return check;
}
/**
* 匹配传入信息集合与模板
* @param value 模板需要替换的区域
* @param textMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
public static String changeValue(String value, Map<String, String> textMap){
Set<Entry<String, String>> textSets = textMap.entrySet();
for (Entry<String, String> textSet : textSets) {
//匹配模板与替换值 格式${key}
String key = "${"+textSet.getKey()+"}";
if(value.indexOf(key)!= -1){
value = textSet.getValue();
}
}
//模板未匹配到区域替换为空
if(checkText(value)){
value = "";
}
return value;
}
}
测试代码
public static void main(String[] args) {
//模板文件地址
String inputUrl = "D:\\tmp\\word\\平台简报模板.docx";
//新生产的模板文件
Random random = new Random();
String outputUrl = "D:\\tmp\\word\\test"+random.nextInt(20)+".docx";
Map<String, String> testMap = new HashMap<String, String>();
testMap.put("title", "要替换的title");
testMap.put("describe", "要替换的describe");
List<List<List<String>>> testList = new ArrayList<>();
//表格一
{
List<List<String>> rows = new ArrayList<>();
List<String> cells = new ArrayList<>();
cells.add("1");
cells.add("companyName");
cells.add("1");
cells.add("33");
cells.add("23");
cells.add("98");
cells.add("23");
cells.add("27");
rows.add(cells); //第一行数据
cells = new ArrayList<>();
cells.add("2");
cells.add("companyName2");
cells.add("1");
cells.add("31");
cells.add("23");
cells.add("96");
cells.add("23");
cells.add("20");
rows.add(cells); //第二行数据
testList.add(rows);
}
//表格二
{
List<List<String>> rows = new ArrayList<>();
List<String> cells = new ArrayList<>();
cells.add("1");
cells.add("companyName");
cells.add("1");
cells.add("33");
cells.add("23");
cells.add("98");
cells.add("23");
cells.add("27");
rows.add(cells); //第一行数据
cells = new ArrayList<>();
cells.add("2");
cells.add("companyName2");
cells.add("1");
cells.add("31");
cells.add("23");
cells.add("96");
cells.add("23");
cells.add("20");
rows.add(cells); //第二行数据
testList.add(rows);
}
WordToNewWordUtils.changWord(inputUrl, outputUrl, testMap, testList);
}
可以用map中的key匹配替换${key} 中内容;
可以获取模板中设置的字号,对齐方式等,这样就是完全往里面填充数据,不需要关注字号,对齐方式了,就沿用模板中设置的。