关于使用apache POI使用既有模版生成word文档的技术记录
1.使用依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
2.关于折现统计图的生成
1.首先在word 的文档中插入一张随机的折现统计图(因为实际需要所以我本地的模板有两张折现统计图)
2.插入统计图以后基于统计图对样式做出修改和调整,具体基于实际业务场景进行操作
3.编写代码
//1.获取图表模板
String templatePath = "D:\\youxi\\module1.docx";
// 获取doc文件模板
try{
InputStream is = new FileInputStream(new File(templatePath));
doc = new XWPFDocument(is);
}catch (Exception e){
e.printStackTrace();
}
//2.获取图表信息
List<XWPFChart> list = doc.getCharts();//知道具体几张表
// 操作图表
//1图, 每条线的名称,一张图可以有多条线,每条线可以有多个名称,使用字符数组命名
String[] series1 = {"测试折线1","",""};
//2图,同上
String[] series2 = {"测试折线"};
//给统计图命名标题说明是什么折现统计图
String title1="测试折线图1";
String title2="测试折线图2";
//y轴
List<Number[]> value1 = new ArrayList<>();//每一张折线图,第一个表3条,需要和图中条数一样
List<Number[]> value2 = new ArrayList<>();//每一张折线图,第二个表1条
//第一张图的y轴
Number[] n1={1.02f,0.5f,-0.3f,0.2f,0.55f,2.6f,1.02f,0.5f,-0.3f,0.2f,0.55f,2.6f,1.02f,0.5f,-0.3f,0.2f,0.55f,2.6f,3.0f,-2.45f};
Number[] n2={4,2,1,4};
Number[] n3={5.8,6.2,1,0.2};
value1.add(n1);
value1.add(n2);
value1.add(n3);
//第二张图的y轴
Number[] n={35, 56, 70, 20, 30,210,35, 56, 70, 20, 30,210,35, 56, 70, 20, 30,210, 10, -20};
value2.add(n);
//定义x轴 y轴和x轴一样都用数组的形式包装数据 如果两张图x轴取参不一样同样需要写入x2作为第二张图的x轴
String[] x1={"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"};
XWPFChart xChart1 = doc.getCharts().get(0);//获取第1个图表
XWPFChart xChart2 = doc.getCharts().get(1);//获取第2个图表
//此处生成折线统计图
drawLineChart(xChart1,series1,x1,value1,title1);
drawLineChart(xChart2,series2,x1,value2,title2);
生成折线统计图方法
//chart 图表
//series 折线名
//categories x轴
//values y轴数据
//chartTitle 统计图名称
public static void drawLineChart(XWPFChart chart, String[] series, String[] categories,
List<Number[]> values, String chartTitle){
final List<XDDFChartData> data = chart.getChartSeries();
final XDDFLineChartData line = (XDDFLineChartData) data.get(0);//这里一般获取第一个,我们这里是折线图就是XDDFLineChartData
final int numOfPoints = categories.length;
final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
for (int i = 0; i < values.size(); i++) {
final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, i + 1, i + 1));
Number[] value = values.get(i);
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(value, valuesDataRange, i + 1);
XDDFChartData.Series ser;//图表中的系列
ser = line.getSeries().get(i);
ser.replaceData(categoriesData, valuesData);
CellReference cellReference = chart.setSheetTitle(series[i], 1);//修改系列标题
ser.setTitle(series[i], cellReference);
}
chart.plot(line);
chart.setTitleText(chartTitle);//折线图标题
chart.setTitleOverlay(false);
}
3.操作表格数据
1.基于实际业务编写我们所需要的表格模版
2.编写代码
//获取表格 因为我只有一个表 就直接get(0)
XWPFTable tables = doc.getTables().get(0);
//获取所有行行
List<XWPFTableRow> rows = tables.getRows();
//遍历行获取单元格
for (int i = 0; i < rows.size(); i ++) {
XWPFTableRow row = rows.get(i);
//遍历行里单元格 在单元格内写入数据 此处写入数据需要基于业务自己调试
for (XWPFTableCell cell : row.getTableCells()){
cell.setText(String.valueOf(Math.random()));
}
}
4.操作参数替换
Map<String, String> map = new HashMap<>();
map.put("${template}", "测试信息");
map.put("${templatee}", "2023-05-16");
map.put("${barLine}", "000123");
//获取所有段落
List<XWPFParagraph> paragraphList = doc.getParagraphs();
for (XWPFParagraph par : paragraphList) {
//获取段落的文本对象
List<XWPFRun> runs = par.getRuns();
for (XWPFRun run : runs) {
//获取文本的值
String text = run.getText(0);
//遍历map
for (Map.Entry<String, String> entry : map.entrySet()) {
//获取map的key
String key = entry.getKey();
//判断文本的值和map的key,文本中是否有和key一样的占位符
if (text.indexOf(key) != -1) {
//获取对应key的value
Object value = entry.getValue();
//把文本的内容,key替换为value
text = text.replace(key, value.toString());
//把替换好的文本内容,保存到当前这个文本对象
run.setText(text, 0);
}
}
}
}
注意: 在操作前需要使用$占位符, 当前占位符可以识别需要替换的数据信息, 如果在表格中需要添加占位符数据,则需要在cell中操作此方法编辑
5.操作模版页眉使用占位符修改如作者证书编号等信息
XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
XWPFHeader header = headerFooterPolicy.getDefaultHeader();
List<XWPFParagraph> paragraphs = header.getParagraphs();
//因为此处只有一行 只有一个参数直接可以操作 无需进行匹配如上述占位符匹配 如果是多个的情况还是如上述占位符的方式进行遍历匹配
paragraphs.get(0).getRuns().get(3).setText("John Doe",0);
6.输出已写完的参数信息
try (
FileOutputStream fos = new FileOutputStream("D:\\youxi\\moduleServer.docx")) {
doc.write(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}