poi-tl(poi template language)是Word模板引擎,使用Word模板和数据创建很棒的Word文档,
支持:
1.单系列图表指的是饼图(3D饼图)、圆环图等。
2.多系列图表指的是条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、散点图等。
3.组合图表指的是由多系列图表(柱形图、折线图、面积图)组合而成的图表。
等等...
官网地址:Poi-tl Documentation
poi-tl是干嘛的?
文章目录
展示
一、效果展示
二、模板
三、使用步骤
1.引包
2.代码
四.测试及数据处理
五.总结
该案例使用poi-tl版本: 1.12.0
com.deepoove
poi-tl
1.12.0
该案例引入的包
com.deepoove
poi-tl
1.12.0
org.projectlombok
lombok
1.18.24
org.apache.logging.log4j
log4j-core
2.17.1
org.slf4j
slf4j-nop
1.7.2
jar
com.alibaba
fastjson
1.2.28
org.springframework.boot
spring-boot-starter-web
2.3.12.RELEASE
ServerTablePolicy:主要处理合并数据表格工具类
MergeRowsRenderPolicy:含图片表格合并工具类
MultiImageRenderPolicy:注册添加前缀为'&'的自定义插件:
2.1.ServerTablePolicy:主要处理合并数据表格工具类
public class ServerTablePolicy extends DynamicTableRenderPolicy {
@Override
public void render(XWPFTable xwpfTable, Object tableData) throws Exception {
if (null == tableData) {
return;
}
// 参数数据声明
ServerTableData serverTableData = (ServerTableData) tableData;
List serverDataList = serverTableData.getServerDataList();
List
2.2.MergeRowsRenderPolicy:含图片表格合并工具类
public class MergeRowsRenderPolicy implements RenderPolicy {
private final String prefix;
private final String suffix;
private final boolean onSameLine;
public MergeRowsRenderPolicy() {
this(false);
}
public MergeRowsRenderPolicy(boolean onSameLine) {
this("[", "]", onSameLine);
}
public MergeRowsRenderPolicy(String prefix, String suffix) {
this(prefix, suffix, false);
}
public MergeRowsRenderPolicy(String prefix, String suffix, boolean onSameLine) {
this.prefix = prefix;
this.suffix = suffix;
this.onSameLine = onSameLine;
}
@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 (data instanceof Iterable) {
Iterator> iterator = ((Iterable>) data).iterator();
XWPFTableRow templateRow = table.getRow(templateRowIndex);
int insertPosition = templateRowIndex;
TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(prefix, suffix));
boolean firstFlag = true;
int index = 0;
boolean hasNext = iterator.hasNext();
while (hasNext) {
Object root = iterator.next();
hasNext = iterator.hasNext();
insertPosition = templateRowIndex++;
table.insertNewTableRow(insertPosition);
setTableRow(table, templateRow, insertPosition);
// double set row
XmlCursor newCursor = templateRow.getCtRow().newCursor();
newCursor.toPrevSibling();
XmlObject object = newCursor.getObject();
XWPFTableRow nextRow = new XWPFTableRow((CTRow) object, table);
if (!firstFlag) {
// update VMerge cells for non-first row
List tableCells = nextRow.getTableCells();
for (XWPFTableCell cell : tableCells) {
CTTcPr tcPr = TableTools.getTcPr(cell);
CTVMerge vMerge = tcPr.getVMerge();
if (null == vMerge) {continue;}
if (STMerge.RESTART == vMerge.getVal()) {
vMerge.setVal(STMerge.CONTINUE);
}
}
} else {
firstFlag = false;
}
setTableRow(table, nextRow, insertPosition);
RenderDataCompute dataCompute = template.getConfig()
.getRenderDataComputeFactory()
.newCompute(EnvModel.of(root, EnvIterator.makeEnv(index++, hasNext)));
List cells = nextRow.getTableCells();
cells.forEach(cell -> {
List templates = resolver.resolveBodyElements(cell.getBodyElements());
new DocumentProcessor(template, resolver, dataCompute).process(templates);
});
}
// 处理连续数据相同行合并
int currPos = getTemplateRowIndex(tagCell);
XWPFTableRow prevRow = table.getRow(currPos);
while (currPos <= insertPosition) {
currPos++;
XWPFTableRow nextRow = table.getRow(currPos);
List cells = nextRow.getTableCells();
int currCellPos = 0;
while (currCellPos < cells.size()) {
CTTcPr tcPrPrev = TableTools.getTcPr(prevRow.getCell(currCellPos));
CTVMerge vMergePrev = tcPrPrev.getVMerge();
if (null == vMergePrev) {
vMergePrev = tcPrPrev.addNewVMerge();
vMergePrev.setVal(STMerge.RESTART);
}
CTTcPr tcPrNext = TableTools.getTcPr(nextRow.getCell(currCellPos));
CTVMerge vMergeNext = tcPrNext.getVMerge();
if (null == vMergeNext) {
vMergeNext = tcPrNext.addNewVMerge();
vMergeNext.setVal(STMerge.RESTART);
}
// 判断上下两行的字符串值是否一样,一样就合并
if (StringUtils.equalsIgnoreCase(
prevRow.getCell(currCellPos).getText(),
nextRow.getCell(currCellPos).getText())) {
vMergeNext.setVal(STMerge.CONTINUE);
}
currCellPos++;
}
prevRow = nextRow;
}
}
table.removeRow(templateRowIndex);
afterloop(table, data);
} catch (Exception e) {
throw new RenderException("HackLoopTable for " + eleTemplate + "error: " + e.getMessage(), e);
}
}
private int getTemplateRowIndex(XWPFTableCell tagCell) {
XWPFTableRow tagRow = tagCell.getTableRow();
return onSameLine ? getRowIndex(tagRow) : (getRowIndex(tagRow) + 1);
}
protected void afterloop(XWPFTable table, Object data) {
}
@SuppressWarnings("unchecked")
private void setTableRow(XWPFTable table, XWPFTableRow templateRow, int pos) {
List rows = (List) ReflectionUtils.getValue("tableRows", table);
rows.set(pos, templateRow);
table.getCTTbl().setTrArray(pos, templateRow.getCtRow());
}
private int getRowIndex(XWPFTableRow row) {
List rows = row.getTable().getRows();
return rows.indexOf(row);
}
}
2.3.MultiImageRenderPolicy:注册添加前缀为'&'的自定义插件:
public class MultiImageRenderPolicy extends AbstractRenderPolicy> {
@Override
protected void afterRender(RenderContext> context) {
clearPlaceholder(context, true);
}
@Override
public void doRender(RenderContext> context) throws Exception {
IRunBody iRunBody = context.getRun().getParent();
if (iRunBody instanceof XWPFParagraph) {
XWPFParagraph p = (XWPFParagraph) iRunBody;
Collection data = context.getData();
if (CollectionUtils.isNotEmpty(data)) {
for (PictureRenderData pic : data) {
PictureRenderPolicy.Helper.renderPicture(p.createRun(), pic);
}
}
}
}
}
2.4. 数据表格合并实体类
@Data
public class ServerTableData {
/**
* 携带表格中真实数据
*/
private List serverDataList;
/**
* 携带要分组的信息
*/
private List
public class WordExport {
public static void main(String[] args) throws IOException {
// 获取模板文件流
String filePath = "D:\\poi-tl\\template.docx";
String targetPath = "D:\\poi-tl\\templateTest.docx";
String picturePath = "D:\\poi-tl\\1_1.jpg";
String picturePaths="D:\\poi-tl\\1_1.jpg,D:\\poi-tl\\2_2.jpg,D:\\poi-tl\\3_3.jpg,D:\\poi-tl\\4_4.jpg";
String httpPicturePath = "http://deepoove.com/images/icecream.png";
String httpPicturePaths = "http://deepoove.com/images/icecream.png,http://deepoove.com/images/icecream.png";
//单个图片数据模板
PictureRenderData picture = Pictures.ofStream(new FileInputStream(picturePath), PictureType.JPEG)
.size(400, 300).create();
//多张图片数据模板
ArrayList pictures = new ArrayList() {
{
add(new JSONObject().fluentPut("url",picturePath));
add(new JSONObject().fluentPut("url", httpPicturePath));
}
};
//多张图片处理
List
如果出现出现与项目其他技术不兼容,可单独拉出一个服务,但此时涉及到不同服务之间通过feign实现Response传递可参考: https://mp.csdn.net/mp_blog/creation/editor/129615552
针对于未接触的技术,先了解官方文档,然后百度,谷歌,嘎嘎一顿乱造,想要的结果也就差不多了,
有疑问欢迎交流沟通!!!