在我的编程生涯中,首次面对一个令人挑战的任务。使用Java生成并下载PPT文件。这看似不可思议的需求让我陷入了艰难的挣扎,我相信你们也没听过这个需求吧。
这一过程虽然曲折,但最终的成果证明了“功夫不负有心人”的真谛。在漫长的探索和实践中,最终一点一点根据自身的业务需求精心设计实现。
编写这个博客不仅是为了分享成功的经验,更是为了让大家少走弯路,避免在类似的挑战中迷失方向。
一、导入依赖
-
org.apache.poi:poi-ooxml:5.2.2
处理Office Open XML格式文件。 -
org.apache.poi:ooxml-schemas:1.4
提供Office Open XML的验证和模式支持。 -
org.slf4j:slf4j-api:2.0.7
提供日志记录的简单接口,方便更换底层日志库。
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version></dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version></dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version></dependency>
二、导入工具包
由于工具包代码较长,我就上传到资源下载去了。小伙伴们可以前往下载:PPTUtils
三、准备一个PPT模板
1.ppt文本替换
2.ppt图片插入
3.ppt文本拼接成列表
4.生成ppt表格
准备一个表头
5.生成饼图
准备一个模板饼图
6.生成雷达图
准备一个模板雷达图
四、Doem代码示例
这份测试代码仅供参考,是我在面对不同的业务需求时所设计的灵活解决方案。在具体应用中,你可以根据自身业务的独特性进行调整,或者将其封装成接口,以方便未来的调用和集成。
注意:根据ppt模板页码来填充数据。获取ppt页码,下标是从0开始的。
package com.pptx;
import com.utils.PPTUtil;
import com.utils.ParagraphTextStyle;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.xslf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTRadarChart;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
public class CustomerPPTX {
public static void main(String[] args) {
// PPT模板路径
String path = "D:\\BaiduNetdiskDownload\\template-wealthRisk.pptx";
// 通过pptx工具类读取文件路径
PPTUtil pptUtil = new PPTUtil(path);
// 1.ppt文本替换
getPageCustomerName(pptUtil);
// 2.ppt图片插入
getImagesInfo(pptUtil);
// 3.ppt文本拼接成列表
getCustomerDemands(pptUtil);
// 4.生成ppt表格
getCustomerTable(pptUtil);
// 5.生成饼图
getCustomerPieChart(pptUtil);
// 6.生成雷达图
getCustomerRadarMap(pptUtil);
// 生成填充完数据PPT报告
pptUtil.writePPT("D:\\BaiduNetdiskDownload\\张三财富报告.pptx");
}
/**
* 获取ppt第一页,ppt文本替换
*
* @param pptUtil
*/
public static void getPageCustomerName(PPTUtil pptUtil) {
// 获取第一页,下标从0开始
List<XSLFTextParagraph> paragraphs = pptUtil.getParagraphsFromSlide(pptUtil.getSlides().get(0));
// 格式化日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 通过Map定义内容
Map<String, Object> keyMap = new HashMap<>();
keyMap.put("name", "彭先生");
keyMap.put("dateTime", sdf.format(new Date()));
for (XSLFTextParagraph paragraph : paragraphs) {
// 对该段落中所有的标签 {**} 进行替换
pptUtil.replaceTagInParagraph(paragraph, keyMap);
}
}
/**
* 获取ppt第四页,ppt插入图片
*
* @param pptUtil
*/
public static void getImagesInfo(PPTUtil pptUtil) {
// 获取第四页pptx
XSLFSlide slide = pptUtil.getSlides().get(3);
// 调用getPPTX方法获取当前的PPTX对象,然后使用addPicture方法将两张图片插入到PPT中
// XSLFPictureData是Apache POI库中表示PowerPoint中的图像对象的一个类
XSLFPictureData xslfPictureData = null;
try {
// addPicture方法支持File、byte[]、InputStream
xslfPictureData = pptUtil.getPPTX().addPicture(new File("D:\\BaiduNetdiskDownload\\jtsrwgxtzmha.png"), PictureData.PictureType.PNG);
// 创建图片
XSLFPictureShape picture = slide.createPicture(xslfPictureData);
// 设置图片位置:x坐标、y坐标、宽度、高度
picture.setAnchor(new Rectangle(50, 130, 410, 410));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取第五页ppt,诉求列表
*
* @param pptUtil
*/
public static void getCustomerDemands(PPTUtil pptUtil) {
// 获取第五页pptx
List<XSLFTextParagraph> paragraphs = pptUtil.getParagraphsFromSlide(pptUtil.getSlides().get(4));
String[] str = {"婚姻关系中的问题", "离婚和财产分割", "孩子的抚养和教育", "家庭财产问题"};
StringBuffer stringBuffer = new StringBuffer();
int sort = 0;
for (String name : str) {
// 拼接诉求
sort = (sort + 1);
stringBuffer.append(sort + "、" + name + "\n\n");
}
Map<String, Object> keyMap = new HashMap<>();
keyMap.put("typeName", stringBuffer);
for (XSLFTextParagraph paragraph : paragraphs) {
// 对该段落中所有标签 {**} 进行替换
pptUtil.replaceTagInParagraph(paragraph, keyMap);
}
}
/**
* 测试数据集合
* @return list
*/
private static List<CustomerAssets> customerAssetList(){
List<CustomerAssets> list = new ArrayList<>();
list.add(
new CustomerAssets("住宅", "别墅花园", "人民币", BigDecimal.valueOf(100), "境内")
);
list.add(
new CustomerAssets("住宅", "阳光小区", "人民币", BigDecimal.valueOf(200), "境内")
);
list.add(
new CustomerAssets("古董","宋代花瓶","美元",BigDecimal.valueOf(300),"境内")
);
list.add(
new CustomerAssets("古董","清婉瓷器","美元",BigDecimal.valueOf(90),"境内")
);
return list;
}
/**
* 获取第六页ppt,生成表格
*
* @param pptUtil
*/
public static void getCustomerTable(PPTUtil pptUtil) {
// 从指定的幻灯片中获取表格元素
XSLFTable xslfTable = pptUtil.getTableFromSlide(pptUtil.getSlides().get(6));
// 全局设置样式
ParagraphTextStyle cellStyle = new ParagraphTextStyle();
// 设置字体大小
cellStyle.setFontSize("8");
// 调用测试数据集合
List<CustomerAssets> list = customerAssetList();
// 统计总金额
BigDecimal totalAmount = BigDecimal.ZERO;
for (CustomerAssets customerAssets : list) {
XSLFTableRow newRow = xslfTable.addRow();
// 资产类别
XSLFTableCell cell1 = newRow.addCell();
cell1.setText(customerAssets.getCategory());
pptUtil.setCellTextStyle(cell1,cellStyle);
// 资产名称
XSLFTableCell cell2 = newRow.addCell();
cell2.setText(customerAssets.getAssetsName());
pptUtil.setCellTextStyle(cell2,cellStyle);
// 币种
XSLFTableCell cell3 = newRow.addCell();
cell3.setText(customerAssets.getCurrency());
pptUtil.setCellTextStyle(cell3,cellStyle);
// 计算累加总金额
totalAmount = totalAmount.add(customerAssets.getAmount());
// 金额(万元)
XSLFTableCell cell4 = newRow.addCell();
cell4.setText(String.valueOf(customerAssets.getAmount()));
pptUtil.setCellTextStyle(cell4,cellStyle);
// 境内/境外
XSLFTableCell cell5 = newRow.addCell();
cell5.setText(customerAssets.getIsInland());
pptUtil.setCellTextStyle(cell5,cellStyle);
}
XSLFTableRow xslfTableCells = xslfTable.addRow();
// 初始化
fullTableCell(xslfTableCells,4);
// 取初始化的第1个单元格,下标为0的
XSLFTableCell cell = xslfTableCells.getCells().get(0);
cell.setText("合计");
pptUtil.setCellTextStyle(cell,cellStyle);
// 取初始化的4个单元格,下标为3的
cell = xslfTableCells.getCells().get(3);
cell.setText(String.valueOf(totalAmount));
pptUtil.setCellTextStyle(cell,cellStyle);
// 统计住宅、古董数量,可以自己封装一下方便调用
long count1 = list.stream().filter(item -> item.getCategory().equals("住宅")).count();
long count2 = list.stream().filter(item -> item.getCategory().equals("古董")).count();
// 合并相同类别名称单元表格
int mergeIndex = mergeCellsRow(xslfTable,1, (int) count1);
mergeCellsRow(xslfTable,mergeIndex, (int) count2);
}
/**
* 通用合并单元格
* @param table
* @param mergeIndex
* @param size
* @return
*/
private static int mergeCellsRow(XSLFTable table,int mergeIndex,int size){
if (size > 0){
table.mergeCells(mergeIndex,mergeIndex + size -1,0,0);
mergeIndex += size;
}
return mergeIndex;
}
/**
* 初始化列
* @param row
* @param num
*/
private static void fullTableCell(XSLFTableRow row,int num){
for (int i = 0; i < num; i++) {
row.addCell();
}
}
/**
* 获取第七页ppt,生成饼图
* @param pptUtil
*/
public static void getCustomerPieChart(PPTUtil pptUtil){
XSLFChart chart = pptUtil.getChartFromSlide(pptUtil.getSlides().get(7));
// 存储数据
List<List<String>> data = new ArrayList<>();
List<String> tempData1 = new ArrayList<>();
List<String> tempData2 = new ArrayList<>();
// 构造数据
Map<String,Double> map = new HashMap<>();
map.put("金融资产",160.00);
map.put("实物资产",50.00);
map.put("流动性资产",30.00);
map.put("其他资产",10.00);
for (Map.Entry<String, Double> entry : map.entrySet()) {
String key = entry.getKey();
Double value = entry.getValue();
tempData1.add(key);
tempData2.add(value + "");
}
data.add(tempData1);
data.add(tempData2);
CTPieChart pieChart = pptUtil.getPieChartFromChart(chart).get(0);
pptUtil.updatePieCat(pieChart,0,data);
// 替换缓存数据
pptUtil.updatePieDataCache(pieChart,0,tempData2);
}
public static void getCustomerRadarMap(PPTUtil pptUtil){
// 获取雷达图
XSLFChart chart = pptUtil.getAllChartFromSlide(pptUtil.getSlides().get(9)).get(0);
// 存储数据
List<List<String>> data = new ArrayList<>();
List<String> tempData1 = new ArrayList<>();
List<String> tempData2 = new ArrayList<>();
// 构造数据
Map<String,Long> map = new HashMap<>();
map.put("财富档案",160L);
map.put("财富保全",50L);
map.put("定向传承",30L);
map.put("家企隔离",10L);
map.put("财富隔离",80L);
for (Map.Entry<String, Long> entry : map.entrySet()) {
String key = entry.getKey();
Long value = entry.getValue();
tempData1.add(key);
tempData2.add(value + "");
}
data.add(tempData1);
data.add(tempData2);
CTRadarChart radarChart = pptUtil.getRadarChartFromChart(chart).get(0);
pptUtil.updateRadarCat(radarChart,0,data);
// 替换缓存数据
pptUtil.updateRadarDataCache(radarChart,0,tempData2);
}
}