java 使用 poi 操作 world 生成饼图,柱状图,折线图,java 微服务架构训练营
List<XWPFChart> charts = doc.getCharts();
//数据源
ChartModel chartModel = new ChartModel();
//标题
List<String> titleList = new ArrayList<String>();
titleList.add("type");
titleList.add("number");
chartModel.setTitleList(titleList);
//字段名
List<String> numberList = new ArrayList<String>();
numberList.add("value1");
numberList.add("value2");
chartModel.setNumberList(numberList);
//记录某本书销售多少册
List<Map<String, String>> sourceModelList = new ArrayList<>();
Map<String, String> publicEm = new HashMap<>();
publicEm.put("value1", "设计模式之禅");
publicEm.put("value2", "555");
Map<String, String> publicEm1 = new HashMap<>();
publicEm1.put("value1", "effective java");
publicEm1.put("value2", "453");
Map<String, String> publicEm2 = new HashMap<>();
publicEm2.put("value1", "红楼梦");
publicEm2.put("value2", "982");
Map<String, String> publicEm3 = new HashMap<>();
publicEm3.put("value1", "水浒传");
publicEm3.put("value2", "759");
sourceModelList.add(publicEm);
sourceModelList.add(publicEm1);
sourceModelList.add(publicEm2);
sourceModelList.add(publicEm3);
chartModel.setSourceModelList(sourceModelList);
//得到模板中第 N 个位置的图表可绘制区域中 条形图
chartModel.setSingleChart(charts,2,0,ChartsEnum.COLUMN);
chartModel.executeFillModel("sheet1");
//得到模板中第 N 个位置的图表可绘制区域中 饼状图
chartModel.setSingleChart(charts,3,0,ChartsEnum.PIE);
chartModel.executeFillModel("sheet1");
//得到模板中第 N 个位置的图表可绘制区域中 折线图
chartModel.setSingleChart(charts,4,0,ChartsEnum.LINE_CHART);
chartModel.executeFillModel("sheet1");
try (FileOutputStream fos = new FileOutputStream("test.docx")) {
doc.write(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
[](
)测试类:组合图表(入口)
第一个图表:
对应 Map 数据源中第一个 key 做 X 轴 第二个 key 做 Y 轴
第二个图表:
对应 Map 数据源中第一个 key 做 X 轴 第三个 key 做 Y 轴
import lombok.SneakyThrows;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import java.io.*;
import java.util.*;
/**
@author BM_hyjw
word 图表写入数据实现测试
*/
public class Combination{
@SneakyThrows
public static void main(String[] args) {
//获取 word 模板
InputStream docis = new FileInputStream("C:\Users\16630\Desktop\htmlToLongImage\haha.docx");
//转成 word
CustomXWPFDocument doc = new CustomXWPFDocument(docis);
//获取 word 中所有图表对象
List<XWPFChart> charts = doc.getCharts();
//数据源
ChartModel chartModel = new ChartModel();
//标题
List<String> titleList = new ArrayList<String>();
titleList.add("type");
titleList.add("number");
titleList.add("max");
chartModel.setTitleList(titleList);
//字段名
List<String> numberList = new ArrayList<String>();
numberList.add("value1");
numberList.add("value2");
numberList.add("value3");
chartModel.setNumberList(numberList);
//记录某本书销售多少册
List<Map<String, String>> sourceModelList = new ArrayList<>();
Map<String, String> publicEm = new HashMap<>();
publicEm.put("value1", "设计模式之禅");
publicEm.put("value2", "555");
publicEm.put("value3", "0");
Map<String, String> publicEm1 = new HashMap<>();
publicEm1.put("value1", "effective java");
publicEm1.put("value2", "453");
publicEm1.put("value3", "0");
Map<String, String> publicEm2 = new HashMap<>();
publicEm2.put("value1", "红楼梦");
publicEm2.put("value2", "982");
publicEm2.put("value3", "982");
Map<String, String> publicEm3 = new HashMap<>();
publicEm3.put("value1", "水浒传");
publicEm3.put("value2", "759");
publicEm3.put("value3", "759");
sourceModelList.add(publicEm);
sourceModelList.add(publicEm1);
sourceModelList.add(publicEm2);
sourceModelList.add(publicEm3);
chartModel.setSourceModelList(sourceModelList);
//得到模板中第 N 个位置的图表可绘制区域中 折线图 和 柱状图 的 组合图
chartModel.setComBiChart(charts,0,0,
Arrays.asList(ChartsEnum.LINE_CHART,ChartsEnum.COLUMN));
chartModel.executeFillModel("sheet1");
//得到模板中第 N 个位置的图表可绘制区域中 折线图 和 散点 的 组合图
chartModel.setComBiChart(charts,1,0,
Arrays.asList(ChartsEnum.LINE_CHART,ChartsEnum.SCATTER));
chartModel.executeFillModel("sheet1");
try (FileOutputStream fos = new FileOutputStream("test.docx")) {
doc.write(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
[](
)工具类:组合数据类
package com.wyz.world.utils;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
@author BM_hyjw
图表要填充的数据格式
*/
@Slf4j
@Getter
@ToString
public class ChartModel {
/**
标记 用来记录当前是否是单元素的图表
*/
private Boolean isSingle = true;
/**
内置表格页名
*/
private String sheetName;
/**
图表
*/
private XWPFChart xwpfChart;
/**
具体图
*/
private List<XmlObject> xmlObjectList = new ArrayList<>();
/**
绘制区域图
*/
private CTChart ctChart;
/**
标题
*/
private List<String> titleList;
/**
数据源对应的 key
*/
private List<String> numberList;
/**
填充的数据源
*/
private List<Map<String, String>> sourceModelList;
/**
目标数据
*/
private List<ChartsEnum> chartsEnumList;
/**
赋值 替换目标
@param numberList
*/
public void setNumberList(List<String> numberList){
this.numberList = numberList;
}
/**
赋值 数据源
@param sourceModelList
*/
public void setSourceModelList(List<Map<String, String>> sourceModelList){
this.sourceModelList = sourceModelList;
}
/**
赋值 标题
@param titleList
*/
public void setTitleList(List<String> titleList){
this.titleList = titleList;
}
/**
单个赋值 图表
@param charts 所有可绘制区域
@param chartSeat 要操作的图表中可绘制区域位置
@param xmlObjSeat 图表在可绘制区域中的位置
@param chartsEnum 目标的表格类型
*/
public void setSingleChart(List<XWPFChart> charts,int chartSeat,int xmlObjSeat,ChartsEnum chartsEnum){
List<ChartsEnum> chartsEnumList = Arrays.asList(chartsEnum);
/**
封装基础数据
*/
this.packageBasic(charts, chartSeat,chartsEnumList);
/**
获得目标图表
*/
XmlObject targetChart = chartsEnum.getTargetChart(chartSeat, this.ctChart, xmlObjSeat);
this.xmlObjectList = Arrays.asList(targetChart);
//当前是单元素
this.isSingle = true;
}
/**
组合赋值 图表
@param charts 所有可绘制区域
@param chartSeat 要操作的图表中可绘制区域位置
@param xmlObjSeat 图表在可绘制区域中的位置
@param chartsEnumList 目标的表格类型
*/
public void setComBiChart(List<XWPFChart> charts,int chartSeat,int xmlObjSeat,List<ChartsEnum> chartsEnumList){
/**
封装基础数据
*/
this.packageBasic(charts, chartSeat,chartsEnumList);
/**
获得目标图表
*/
this.xmlObjectList.clear();
chartsEnumList.stream().forEach(x->{
XmlObject targetChart = x.getTargetChart(chartSeat,this.ctChart, xmlObjSeat);
this.xmlObjectList.add(targetChart);
});
//当前不是单元素
this.isSingle = false;
}
/**
封装部分基础数据
@param charts
@param chartSeat
@param chartsEnumList
*/
private void packageBasic(List<XWPFChart> charts, int chartSeat,List<ChartsEnum> chartsEnumList) {
if(CollectionUtils.isEmpty(charts)){
throw new RuntimeException("模板中图表元素为 null; !!!ctChart:null");
}
if(CollectionUtils.isEmpty(chartsEnumList)){
throw new RuntimeException("图表目标为 null;!!!chartsEnum:null");
}
/**
目标
*/
this.chartsEnumList = chartsEnumList;
/**
第 N 个位置图表
*/
this.xwpfChart = charts.get(chartSeat);
/**
第 N 个位置可绘制区域的图表
*/
this.ctChart = this.xwpfChart.getCTChart();
}
/**
执行模板数据源填充
@param sheetName 展示数据 excel 页名字
*/
public void executeFillModel(String s
heetName) throws IOException, InvalidFormatException {
this.sheetName = sheetName;
//异常校验
String s = this.isSingle ? this.abnormalCheckSingle() : this.abnormalCheckComBi();
//执行填充数据
ChartsEnum.refreshExcel(this);
for (int i = 0; i < chartsEnumList.size(); i++) {
ChartsEnum chartsEnum = chartsEnumList.get(i);
chartsEnum.fillModel(this,this.getXmlObjectList().get(i),i);
}
}
/**
异常校验
*/
private String abnormalCheckSingle() {
if(CollectionUtils.isEmpty(this.numberList)){
throw new RuntimeException("数据源比对为 null; !!!numberList:null");
}
if(CollectionUtils.isEmpty(this.titleList)){
throw new RuntimeException("标题为 null; !!!titleList:null");
}
if(CollectionUtils.isEmpty(this.sourceModelList)){
throw new RuntimeException("数据源为 null; !!!sourceModelList:null");
}
if(Objects.isNull(this.xwpfChart)){
throw new RuntimeException("模板中图表元素为 null; !!!xwpfChart:null");
}
if(CollectionUtils.isEmpty(this.xmlObjectList)){
throw new RuntimeException("模板中具体图表为 null;!!!xmlObjectList:null");
}
if(CollectionUtils.isEmpty(this.chartsEnumList)){
throw new RuntimeException("图表目标为 null;!!!chartsEnum:null");
}
if(Objects.isNull(this.ctChart)){
throw new RuntimeException("图表绘制区域为 null;!!!chartsEnum:null");
}
if(StringUtils.isEmpty(this.sheetName)){
throw new RuntimeException("内置 excel 页名为 null;!!!sheetName:null");
}
return null;
}
/**
异常校验
*/
private String abnormalCheckComBi() {
this.abnormalCheckSingle();
if (this.xmlObjectList.size() < 2) {
throw new RuntimeException("组合图中【图表】元素不足两个; !!!xmlObjectList.size !> 2");
}
if (this.sourceModelList.stream().filter(x->{return x.keySet().size() >= 3;}).collect(Collectors.toList()).size() < 0) {
throw new RuntimeException("组合图中【数据源】元素不足两个; !!!sourceModelList.map.keySet.size !>= 3");
}
if (this.numberList.size() < 3) {
throw new RuntimeException("组合图中【数据源对应的 key】元素不足两个; !!!numberList.size !>= 3");
}
return null;
}
}
[](
)工具类:枚举解析图表类
package com.wyz.world.utils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.values.XmlComplexContentImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTBarChartImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTLineChartImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTPieChartImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTScatterChartImpl;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
@author BM_hyjw
解析 world 中图表
*/
@Slf4j
@Getter
public enum ChartsEnum {
/**
饼图
*/
PIE(CTPieChart.class, CTPieChartImpl.class){
/**
填充模板数据
@param chartModel 图表和数据源
@param xmlObject 当前元素
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTPieChart pieChart = (CTPieChart)xmlObject;
List<CTPieSer> serList = pieChart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTPieSer ser = pieChart.getSerArray(i);
CTAxDataSource cat = ser.getCat();
CTNumDataSource val = ser.getVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
得到目标位置的图表
@param ctChart 可绘制区域图表
@param xmlObjSeat 目标图标位置位置
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
try {
CTPieChart pieChart = ctChart.getPlotArea().getPieChartArray(xmlObjSeat);
return pieChart;
}catch (Exception e){
throw new RuntimeException("当前位置【" + chartSeat + "】不存在【饼图】!!!");
}
}
},
/**
柱图
*/
COLUMN(CTBarChart.class, CTBarChartImpl.class) {
/**
填充模板数据
@param chartModel 图表和数据源
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTBarChart chart = (CTBarChart)xmlObject;
List<CTBarSer> serList = chart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTBarSer ser = chart.getSerArray(i);
CTAxDataSource cat = ser.getCat();
CTNumDataSource val = ser.getVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
得到目标位置的图表
@param ctChart 可绘制区域图表
@param xmlObjSeat 目标图标位置位置
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
try {
CTBarChart barChart = ctChart.getPlotArea().getBarChartArray(xmlObjSeat);
return barChart;
}catch (Exception e){
throw new RuntimeException("当前位置【" + chartSeat + "】不存在【柱状图】!!!");
}
}
},
/**
折线图
*/
LINE_CHART(CTLineChart.class, CTLineChartImpl.class){
/**
填充模板数据
@param chartModel 图表和数据源
@param xmlObject 当前元素
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTLineChart chart = (CTLineChart)xmlObject;
List<CTLineSer> serList = chart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTLineSer ser = chart.getSerArray(i);
CTAxDataSource cat = ser.getCat();
CTNumDataSource val = ser.getVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
得到目标位置的图表
@param ctChart 可绘制区域图表
@param xmlObjSeat 目标图标位置位置
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
评论