文档地址
http://deepoove.com/poi-tl/
poi-tl的maven依赖
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.1</version>
</dependency>
插件代码
import com.alibaba.fastjson.JSON;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.exception.RenderException;
import com.deepoove.poi.policy.RenderPolicy;
import com.deepoove.poi.render.compute.EnvModel;
import com.deepoove.poi.render.compute.RenderDataCompute;
import com.deepoove.poi.render.processor.DocumentProcessor;
import com.deepoove.poi.render.processor.EnvIterator;
import com.deepoove.poi.resolver.TemplateResolver;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.MetaTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.ReflectionUtils;
import com.deepoove.poi.util.TableTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import java.util.*;
@Slf4j
public class MultilevelLoopRowTableRenderPolicy implements RenderPolicy {
private String prefix;
private String suffix;
private boolean onSameLine;
private String titleName;
private String contextName;
public MultilevelLoopRowTableRenderPolicy(String titleName, String contextName) {
this(titleName, contextName, false);
}
public MultilevelLoopRowTableRenderPolicy(String titleName, String contextName, boolean onSameLine) {
this("{[", "]}", titleName, contextName, onSameLine);
}
public MultilevelLoopRowTableRenderPolicy(String prefix, String suffix, String titleName, String contextName) {
this(prefix, suffix, titleName, contextName, false);
}
public MultilevelLoopRowTableRenderPolicy(String prefix, String suffix, String titleName, String contextName, boolean onSameLine) {
this.prefix = prefix;
this.suffix = suffix;
this.onSameLine = onSameLine;
this.titleName = titleName;
this.contextName = contextName;
}
@Override
public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
RunTemplate runTemplate = (RunTemplate) eleTemplate;
XWPFRun run = runTemplate.getRun();
try {
if (!TableTools.isInsideTable(run)) {
throw new IllegalStateException(
"The template tag " + runTemplate.getSource() + " must be inside a table");
}
XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
XWPFTable table = tagCell.getTableRow().getTable();
run.setText("", 0);
int templateRowIndex = getTemplateRowIndex(tagCell);
if (null != data && data instanceof Iterable) {
TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(prefix, suffix));
List<XWPFTableRow> templateRows = getAllTemplateRow(table, templateRowIndex);
final XWPFTableRow firstTitleTemplateRow = templateRows.get(0);
final XWPFTableRow firstSonRowTemplateRow = templateRows.get(1);
int index = 0;
int titleRowPosition = getRowIndex(firstTitleTemplateRow);
int sonRowPosition = getRowIndex(firstSonRowTemplateRow);
Iterator<?> iterator = ((Iterable<?>) data).iterator();
boolean hasNext = iterator.hasNext();
while (hasNext) {
Object root = iterator.next();
hasNext = iterator.hasNext();
Map<String, Object> jsonObject = JSON.parseObject(JSON.toJSONString(root));
String dqmc = (String) jsonObject.get(titleName);
if (!copy(table, firstTitleTemplateRow, titleRowPosition)) {
throw new RenderException("create new table fail...");
}
XWPFTableRow dqnewRow = table.getRow(titleRowPosition);
setTableRow(table, dqnewRow, titleRowPosition);
Map<String, Object> map = new HashMap<>();
map.put(titleName, dqmc);
List<XWPFTableCell> dqcells = dqnewRow.getTableCells();
RenderDataCompute dqDataCompute = template.getConfig()
.getRenderDataComputeFactory()
.newCompute(EnvModel.of(map, EnvIterator.makeEnv(++index, hasNext)));
dqcells.forEach(tableCell -> {
List<MetaTemplate> metaTemplates = resolver
.resolveBodyElements(tableCell.getBodyElements());
new DocumentProcessor(template, resolver, dqDataCompute)
.process(metaTemplates);
});
titleRowPosition++;
List sonList = (List) jsonObject.get(contextName);
titleRowPosition = titleRowPosition + ((Collection<?>) sonList).size();
Iterator<?> sonDataIterator = ((Iterable<?>) sonList).iterator();
boolean sonDataIteratorHasNext = sonDataIterator.hasNext();
while (sonDataIteratorHasNext) {
Object sonData = sonDataIterator.next();
sonDataIteratorHasNext = sonDataIterator.hasNext();
if (!copy(table, firstSonRowTemplateRow, sonRowPosition)) {
throw new RenderException("create new table fail...");
}
XWPFTableRow newRow = table.getRow(sonRowPosition);
setTableRow(table, newRow, sonRowPosition);
List<XWPFTableCell> cells = newRow.getTableCells();
RenderDataCompute dataCompute = template.getConfig()
.getRenderDataComputeFactory()
.newCompute(EnvModel.of(sonData, EnvIterator.makeEnv(++index, sonDataIteratorHasNext)));
cells.forEach(tableCell -> {
List<MetaTemplate> metaTemplates = resolver
.resolveBodyElements(tableCell.getBodyElements());
new DocumentProcessor(template, resolver, dataCompute)
.process(metaTemplates);
});
sonRowPosition++;
}
sonRowPosition = sonRowPosition + 1;
}
removeTableRow(table, table.getNumberOfRows() - getMultipleTemplateRowNum(), templateRows.size());
}
} catch (Exception e) {
throw new RenderException("HackLoopTable for " + eleTemplate + "error: " + e.getMessage(), e);
}
}
private List<XWPFTableRow> getAllTemplateRow(XWPFTable table, int startIndex) {
int tempRowNum = getMultipleTemplateRowNum();
List<XWPFTableRow> rows = table.getRows();
return new Vector<>(rows.subList(startIndex, startIndex + tempRowNum));
}
private int getMultipleTemplateRowNum() {
return 2;
}
private int getTemplateRowIndex(XWPFTableCell tagCell) {
XWPFTableRow tagRow = tagCell.getTableRow();
return onSameLine ? getRowIndex(tagRow) : (getRowIndex(tagRow) + 1);
}
private void removeTableRow(XWPFTable table, int startIndex, int size) {
for (int i = 0; i < size; ++i) {
table.removeRow(startIndex);
}
}
@SuppressWarnings("unchecked")
private void setTableRow(XWPFTable table, XWPFTableRow templateRow, int pos) {
List<XWPFTableRow> rows = (List<XWPFTableRow>) ReflectionUtils.getValue("tableRows", table);
rows.set(pos, templateRow);
table.getCTTbl().setTrArray(pos, templateRow.getCtRow());
}
private int getRowIndex(XWPFTableRow row) {
List<XWPFTableRow> rows = row.getTable().getRows();
return rows.indexOf(row);
}
public boolean copy(XWPFTable table, XWPFTableRow sourceRow, int rowIndex) {
XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);
targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
List<XWPFTableCell> cellList = sourceRow.getTableCells();
if (null == cellList) {
return false;
}
XWPFTableCell targetCell = null;
for (XWPFTableCell sourceCell : cellList) {
targetCell = targetRow.addNewTableCell();
targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {
targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());
if (sourceCell.getParagraphs().get(0).getRuns() != null && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {
XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
cellR.setText(sourceCell.getText());
cellR.setBold(sourceCell.getParagraphs().get(0).getRuns().get(0).isBold());
} else {
targetCell.setText(sourceCell.getText());
}
} else {
targetCell.setText(sourceCell.getText());
}
}
return true;
}
}
数据格式
@Data
public class ExportBo {
private String titleName;
private List<Map<String, Object>> sonList;
}
使用方法
MultilevelLoopRowTableRenderPolicy policy = new MultilevelLoopRowTableRenderPolicy("titleName", "sonList");
Configure config = Configure.builder().bind("list", policy).build();
InputStream templateIs = getClass().getClassLoader().getResourceAsStream("template/template.docx");
XWPFTemplate template = XWPFTemplate.compile(templateIs, config).render(
new HashMap<String, Object>() {{
put("list", exportBoList);
}}
);
ExportUtil.downloadDocument("XXX.docx", template, request, response);
word模板
测试 |
---|
序号 | 名字 | 专业 |
---|
{{list}}{[titleName]} |
{[num]} | {[name]} | {[major]} |
效果展示
测试 |
---|
序号 | 名字 | 专业 |
---|
1班 |
1 | 张三 | 计算机 |
2 | 张四 | 计算机 |
2班 |
3 | 李四 | 软件工程 |