一、需求
- 正本(普通+带样式文本+图片)
- 表格
- 列表
- 单一饼图
- 单一柱状图
- 单一折线图
- 组合图表
- word 转pdf等其他文档类型
Maven依赖
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.8.2</version>
</dependency>
Poi-tl常用标签
文本
格式:{{var}}
数据模型:
| 类型 | 描述 |
|---|---|
| String | 纯文本 |
| TextRenderData | 带有样式的文本 |
| HyperLinkTextRenderData | 超链接文本 |
| Object | 调用toString()方法转化成文本 |
代码示例:
//文本
TextContentData contentData = new TextContentData();
contentData.setContent("office处理方案").setLabelName("title").setTypeEnum(WordContentTypeEnum.TEXT);
generates.add(contentData);
//带样式文本
TextContentData typeData = new TextContentData();
typeData.setRenderData(new TextRenderData("cc0000","这是带样式的内容")).setLabelName("content").setTypeEnum(WordContentTypeEnum.TEXT);
generates.add(typeData);
//超链接
TextContentData linkData = new TextContentData();
HyperLinkTextRenderData hyperLinkTextRenderData = new HyperLinkTextRenderData("掘金社区", "https://feifan.iflytek.com/welcome/");
linkData.setRenderData(hyperLinkTextRenderData).setLabelName("typeContent").setTypeEnum(WordContentTypeEnum.TEXT);
/*linkData.setLinkData(hyperLinkTextRenderData);*/
generates.add(linkData);
模板示例:

图片
格式:{{@var}}
数据模型:
| 类型 | 描述 |
|---|---|
| PictureRenderData | 可以支持本地图片、也可以支持远程的URL地址(主要讲URL图片转成BufferedImage) |
代码示例:
//插入图片
PictureContentData picData = new PictureContentData();
picData.setWidth(200).setHeight(160).setPicType(PicTypeEnum.JPG).setFile(new File("D:\\data\\tmp\\img\\monkey.png"))
.setLabelName("picture").setTypeEnum(WordContentTypeEnum.PICTURE);
generates.add(picData);
模板示例:

表格
格式:{{#var}}
数据模型:
| 类型 | 描述 |
|---|---|
| MiniTableRenderData | 该类主要也是调用TextRenderData,提供样式等 |
代码示例:
//插入表格
TableSeriesRenderData tableData = new TableSeriesRenderData();
List<TextRenderData[]> contents = Arrays.asList(
new TextRenderData[] {new TextRenderData("杨思宏1"), new TextRenderData("男"), new TextRenderData("18")},
new TextRenderData[] {new TextRenderData("杨思宏2"), new TextRenderData("男"), new TextRenderData("18")});
tableData.setHeader(new TextRenderData[]{new TextRenderData("姓名"), new TextRenderData("性别"), new TextRenderData("年龄")})
.setContents(contents).setLabelName("table").setTypeEnum(WordContentTypeEnum.TABLE);
generates.add(tableData);
模板示例:

列表
格式:{{*var}}
数据模型:
| 类型 | 描述 |
|---|---|
| NumbericRenderData | 该类主要也是调用TextRenderData,提供样式等 |
说明:NumbericRenderData中支持列表样式,主要有罗马字符、有序无序等。
FMT_DECIMAL // 1. 2. 3.
FMT_DECIMAL_PARENTHESES // 1) 2) 3)
FMT_BULLET // ● ● ●
FMT_LOWER_LETTER // a. b. c.
FMT_LOWER_ROMAN // i ⅱ ⅲ
FMT_UPPER_LETTER // A. B. C.
代码示例:
//插入列表
ListRenderData listRenderData = new ListRenderData();
List<TextRenderData> listData = Arrays.asList(
new TextRenderData("第一名"), new TextRenderData("第二名"), new TextRenderData("第三名")
);
listRenderData.setList(listData).setPair(NumbericRenderData.FMT_DECIMAL).setTypeEnum(WordContentTypeEnum.LIST).setLabelName("textList");
模板示例:

单系列图表
描述:单系列图标,是指在图形中只展示一列数据,例如:单数据的柱状图,饼图等。
格式:{{val}}
模板操作:插入-图表-饼图,点击饼图图层,编辑右侧【标题】


数据模型:
| 类型 | 描述 |
|---|---|
| ChartSingleSeriesRenderData | 该类提供了设置标题、类别等 |
代码示例:
//折线
ChartSeriesRenderData lineData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> lineRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData lightRenderData = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData highRenderData = new ChartSeriesRenderData.RenderData();
lightRenderData.setRenderTitle("严重BUG数").setData(new Double[] {11.02,19.42,10.61,11.41,7.91,5.44,5.30,2.75,1.24,0.35});
highRenderData.setRenderTitle("轻微BUG数").setData(new Number[]{12.66,19.41,15.16,19.72,17.05,15.92,15.10,13.04,10.65,9.15});
lineRenderData.add(lightRenderData);
lineRenderData.add(highRenderData);
lineData.setTitle("开发质量报告")
.setCategories(new String[] {"1月","2月","3月","4月","5月","6月","7月","8月","9月","10月"})
.setSenderData(lineRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("qaLine");
generates.add(lineData);
//柱状图
ChartSeriesRenderData barData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> barRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData openRenderData = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData moneyData = new ChartSeriesRenderData.RenderData();
openRenderData.setRenderTitle("2011年GDP(亿)")
.setData(new Number[]{129118.58,122875.6,87435,77715,61345.05,61345.8,53734.92,53109.85,48670.37,45045,44652.8,42370.4,41610.9,32772.68,32074.7,29129.03,28975.1,28954.2,26300.87,25642.59,23159,20164.58,17741.34,16311.34,15901,13070.24,11201.6,6818.22,5069.57,3610.1,2132.64});
moneyData.setRenderTitle("2012年GDP(亿)")
.setData(new Number[]{119118.58,112875.6,81435,71715,62345.05,62345.8,51734.92,51109.85,42670.37,41045,41652.8,41370.4,44610.9,37772.68,39074.7,23129.03,21975.1,21954.2,21300.87,21642.59,21159,20164.58,11741.34,11311.34,19901,12070.24,13201.6,6218.22,5269.57,3310.1,2332.64});
barRenderData.add(openRenderData);
barRenderData.add(moneyData);
barData.setTitle("各省GDP")
.setCategories(new String[] {"广东省","江苏省","山东省","浙江省","河南省","四川省","湖北省","福建省","湖南省","安徽省","上海","河北省","北京","陕西省","江西省","重庆","辽宁省","云南省","广西省","山西省","内蒙古","贵州省","新疆","天津","黑龙江省","吉林省","甘肃省","海南省","宁夏省","青海省","西藏省"})
.setSenderData(barRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdp");
generates.add(barData);
//生成饼图
ChartSeriesRenderData areaData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> areaRenderDatas = new ArrayList<>();
ChartSeriesRenderData.RenderData areaRenderData = new ChartSeriesRenderData.RenderData();
areaRenderData.setData(new Number[]{8200, 1000}).setRenderTitle("比例")
.setComboType(SeriesRenderData.ComboType.AREA);
areaRenderDatas.add(areaRenderData);
areaData.setTitle("研发男女比例").setSenderData(areaRenderDatas).setCharType(CharCombinationType.Single)
.setCategories(new String[]{"男", "女"})
.setLabelName("showRate").setTypeEnum(WordContentTypeEnum.CHART);
generates.add(areaData);
//横向柱状图
ChartSeriesRenderData lateralData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> lateralRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData year22Data = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData year23Data = new ChartSeriesRenderData.RenderData();
year22Data.setRenderTitle("2022年").setData(new Number[]{3000, 3500});
year23Data.setRenderTitle("2023年").setData(new Number[]{3000, 3500});
lateralRenderData.add(year22Data);
lateralRenderData.add(year23Data);
lateralData.setTitle("工资涨幅")
.setCategories(new String[] {"基本工资", "绩效工资"})
.setSenderData(lateralRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("salary");
generates.add(lateralData);
多系统图表
描述:很多报表都需要多系统图表,例如:柱状图与折线图组合展示
格式:{{val}}
模板操作:插入-图表-组合,点击图表图层,编辑右侧【标题】

数据模型:
| 类型 | 描述 |
|---|---|
| ChartMultiSeriesRenderData | 该类提供了设置标题、类别等 |
代码示例:
//组合图表
ChartSeriesRenderData groupData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> groupRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData incrData = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData radioData = new ChartSeriesRenderData.RenderData();
incrData.setComboType(SeriesRenderData.ComboType.BAR).setRenderTitle("薪资涨幅(亿)")
.setData(new Number[]{50, 50, 100, 200, 500});
radioData.setComboType(SeriesRenderData.ComboType.LINE).setRenderTitle("增长率(%)")
.setData(new Number[]{5, 10, 30, 15, 23});
groupRenderData.add(incrData);
groupRenderData.add(radioData);
groupData.setTitle("各年薪资涨幅报告")
.setCategories(new String[] {"2019", "2020", "2021", "2022", "2023"})
.setSenderData(groupRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdpGroup");
generates.add(groupData);
word转换其他文档类型
POI-TL自身并不支持相关文档转换,它只负责生成word
完整代码
File templateFile = null;
try {
templateFile = new ClassPathResource(TEMPLATE_PATH).getFile();
} catch (IOException e) {
log.error("Word模板读取异常:{}", e);
}
List<LabelData> generates = new ArrayList<>();
//文本
TextContentData contentData = new TextContentData();
contentData.setContent("掘金社区office处理方案").setLabelName("title").setTypeEnum(WordContentTypeEnum.TEXT);
generates.add(contentData);
//带样式文本
TextContentData typeData = new TextContentData();
typeData.setRenderData(new TextRenderData("cc0000","这是带样式的内容")).setLabelName("content").setTypeEnum(WordContentTypeEnum.TEXT);
generates.add(typeData);
//超链接
TextContentData linkData = new TextContentData();
HyperLinkTextRenderData hyperLinkTextRenderData = new HyperLinkTextRenderData("掘金社区", "https://feifan.iflytek.com/welcome/");
linkData.setRenderData(hyperLinkTextRenderData).setLabelName("typeContent").setTypeEnum(WordContentTypeEnum.TEXT);
/*linkData.setLinkData(hyperLinkTextRenderData);*/
generates.add(linkData);
//插入图片
PictureContentData picData = new PictureContentData();
picData.setWidth(200).setHeight(160).setPicType(PicTypeEnum.JPG).setFile(new File("D:\\data\\tmp\\img\\monkey.png"))
.setLabelName("picture").setTypeEnum(WordContentTypeEnum.PICTURE);
generates.add(picData);
//插入表格
TableSeriesRenderData tableData = new TableSeriesRenderData();
List<TextRenderData[]> contents = Arrays.asList(
new TextRenderData[] {new TextRenderData("杨思宏1"), new TextRenderData("男"), new TextRenderData("18")},
new TextRenderData[] {new TextRenderData("杨思宏2"), new TextRenderData("男"), new TextRenderData("18")});
tableData.setHeader(new TextRenderData[]{new TextRenderData("姓名"), new TextRenderData("性别"), new TextRenderData("年龄")})
.setContents(contents).setLabelName("table").setTypeEnum(WordContentTypeEnum.TABLE);
generates.add(tableData);
//插入列表
ListRenderData listRenderData = new ListRenderData();
List<TextRenderData> listData = Arrays.asList(
new TextRenderData("第一名"), new TextRenderData("第二名"), new TextRenderData("第三名")
);
listRenderData.setList(listData).setPair(NumbericRenderData.FMT_DECIMAL).setTypeEnum(WordContentTypeEnum.LIST).setLabelName("textList");
generates.add(listRenderData);
//折线
ChartSeriesRenderData lineData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> lineRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData lightRenderData = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData highRenderData = new ChartSeriesRenderData.RenderData();
lightRenderData.setRenderTitle("严重BUG数").setData(new Double[] {11.02,19.42,10.61,11.41,7.91,5.44,5.30,2.75,1.24,0.35});
highRenderData.setRenderTitle("轻微BUG数").setData(new Number[]{12.66,19.41,15.16,19.72,17.05,15.92,15.10,13.04,10.65,9.15});
lineRenderData.add(lightRenderData);
lineRenderData.add(highRenderData);
lineData.setTitle("开发质量报告")
.setCategories(new String[] {"1月","2月","3月","4月","5月","6月","7月","8月","9月","10月"})
.setSenderData(lineRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("qaLine");
generates.add(lineData);
//柱状图
ChartSeriesRenderData barData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> barRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData openRenderData = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData moneyData = new ChartSeriesRenderData.RenderData();
openRenderData.setRenderTitle("2011年GDP(亿)")
.setData(new Number[]{129118.58,122875.6,87435,77715,61345.05,61345.8,53734.92,53109.85,48670.37,45045,44652.8,42370.4,41610.9,32772.68,32074.7,29129.03,28975.1,28954.2,26300.87,25642.59,23159,20164.58,17741.34,16311.34,15901,13070.24,11201.6,6818.22,5069.57,3610.1,2132.64});
moneyData.setRenderTitle("2012年GDP(亿)")
.setData(new Number[]{119118.58,112875.6,81435,71715,62345.05,62345.8,51734.92,51109.85,42670.37,41045,41652.8,41370.4,44610.9,37772.68,39074.7,23129.03,21975.1,21954.2,21300.87,21642.59,21159,20164.58,11741.34,11311.34,19901,12070.24,13201.6,6218.22,5269.57,3310.1,2332.64});
barRenderData.add(openRenderData);
barRenderData.add(moneyData);
barData.setTitle("各省GDP")
.setCategories(new String[] {"广东省","江苏省","山东省","浙江省","河南省","四川省","湖北省","福建省","湖南省","安徽省","上海","河北省","北京","陕西省","江西省","重庆","辽宁省","云南省","广西省","山西省","内蒙古","贵州省","新疆","天津","黑龙江省","吉林省","甘肃省","海南省","宁夏省","青海省","西藏省"})
.setSenderData(barRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdp");
generates.add(barData);
//生成饼图
ChartSeriesRenderData areaData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> areaRenderDatas = new ArrayList<>();
ChartSeriesRenderData.RenderData areaRenderData = new ChartSeriesRenderData.RenderData();
areaRenderData.setData(new Number[]{8200, 1000}).setRenderTitle("比例")
.setComboType(SeriesRenderData.ComboType.AREA);
areaRenderDatas.add(areaRenderData);
areaData.setTitle("研发男女比例").setSenderData(areaRenderDatas).setCharType(CharCombinationType.Single)
.setCategories(new String[]{"男", "女"})
.setLabelName("showRate").setTypeEnum(WordContentTypeEnum.CHART);
generates.add(areaData);
//横向柱状图
ChartSeriesRenderData lateralData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> lateralRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData year22Data = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData year23Data = new ChartSeriesRenderData.RenderData();
year22Data.setRenderTitle("2022年").setData(new Number[]{3000, 3500});
year23Data.setRenderTitle("2023年").setData(new Number[]{3000, 3500});
lateralRenderData.add(year22Data);
lateralRenderData.add(year23Data);
lateralData.setTitle("工资涨幅")
.setCategories(new String[] {"基本工资", "绩效工资"})
.setSenderData(lateralRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("salary");
generates.add(lateralData);
//组合图表
ChartSeriesRenderData groupData = new ChartSeriesRenderData();
List<ChartSeriesRenderData.RenderData> groupRenderData = new ArrayList<>();
ChartSeriesRenderData.RenderData incrData = new ChartSeriesRenderData.RenderData();
ChartSeriesRenderData.RenderData radioData = new ChartSeriesRenderData.RenderData();
incrData.setComboType(SeriesRenderData.ComboType.BAR).setRenderTitle("薪资涨幅(亿)")
.setData(new Number[]{50, 50, 100, 200, 500});
radioData.setComboType(SeriesRenderData.ComboType.LINE).setRenderTitle("增长率(%)")
.setData(new Number[]{5, 10, 30, 15, 23});
groupRenderData.add(incrData);
groupRenderData.add(radioData);
groupData.setTitle("各年薪资涨幅报告")
.setCategories(new String[] {"2019", "2020", "2021", "2022", "2023"})
.setSenderData(groupRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdpGroup");
generates.add(groupData);
//生成word
String destFilePath = "D:\\data\\tmp\\office\\word\\output.docx";
FileOutputStream fos = null;
XWPFTemplate template = null;
try {
template = XWPFTemplate.compile(templateFile).render(new HashMap<String,Object>(contents.size()){{
generates.forEach(content -> {
if (null == content.getTypeEnum()) {
log.error("该图表配置异常:{}", content.toString());
}
GenerateWord backData = GenerateWordFactory.getBackData(content.getTypeEnum());
put(content.getLabelName(),backData.generateWord(content));
});
}});
fos = new FileOutputStream(destFilePath);
template.write(fos);
fos.flush();
}catch (Exception e){
log.error("生成Word异常:{}", e);
}finally {
try{
if (Objects.nonNull(fos)){
fos.close();
}
if (Objects.nonNull(template)){
template.close();
}
}catch (Exception e){
log.error("关闭数据流异常:{}", e);
}
}
导出word示例
