1、定义一个xml模板(注意:这个导出的实际还是个XML,使用PowerPoint打开报错,导出pptx路径:
https://blog.csdn.net/xionglangs/article/details/120365758)
一、新建一个PPT,使用WPS或office另存为XML,替换后端的参数;
文本直接替换为${map key}
图片,后台存储Base64二进制流blip找上面的Relationship 的ID,Target路径对应pkg:part pkg:name
后台代码,使用的是模板生成PPT(包含后台直接生成PPT,但需要自己调整样式:)
package com.utils;
import cn.afterturn.easypoi.entity.ImageEntity;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.xslf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import sun.misc.BASE64Encoder;
import java.awt.*;
import java.io.*;
import java.util.List;
import java.util.Map;
/**
* Description:
*
* @Author: leo.xiong
* @CreateDate: 2021/8/30 12:13
* @Email: [email protected]
* @Since:
*/
public class PptUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(PptUtil.class);
public static final String TITLE = "title";
/**
* 首页内容
*/
public static final String FIRST_CONTENT = "firstContent";
/**
* 首页位置 Rectangle,x轴坐标,y轴坐标,宽度,高度
*/
public static final String ANCHOR = "anchor";
/**
* 图片信息
*/
public static final String IMAGE = "image";
public static final String CATALOG = "catalog";
public static String exportPpt(File file, Map<String, Object> keyValueMap) {
//创建ppt对象
XMLSlideShow ppt = new XMLSlideShow();
//首页
XSLFSlide slideFirst = ppt.createSlide();
Map<String, Object> firstValueMap = (Map<String, Object>) keyValueMap.get(FIRST_CONTENT);
fillFirstContent(slideFirst, firstValueMap);
//目录
XSLFSlide slideCatalog = ppt.createSlide();
Map<String, Object> keyCatalogMap = (Map<String, Object>) keyValueMap.get(CATALOG);
List<XSLFSlide> contentSlides = Lists.newArrayList();
if (!CollectionUtils.isEmpty(keyCatalogMap)) {
keyCatalogMap.forEach((key, content) -> {
contentSlides.add(ppt.createSlide());
});
}
fillCatalog(slideCatalog, contentSlides, keyCatalogMap);
Map<String, List<ImageEntity>> imageEntityListMap = (Map<String, List<ImageEntity>>) keyValueMap.get(IMAGE);
fillContent(contentSlides, keyCatalogMap, imageEntityListMap, ppt);
StringBuffer fileUrl = new StringBuffer();
fileUrl.append(file.getName());
fileUrl.append(file.getName());
FileOutputStream out = null;
try {
file = new File(fileUrl.toString());
out = new FileOutputStream(file);
ppt.write(out);
} catch (FileNotFoundException e) {
LOGGER.error("文件创建失败,请尝试给web目录赋权777");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return file.getName();
}
/**
* 填充正文,包含图片
*
* @param contentSlides
* @param keyCatalogMap
* @param imageEntityListMap
* @param ppt
*/
private static void fillContent(List<XSLFSlide> contentSlides, Map<String, Object> keyCatalogMap, Map<String, List<ImageEntity>> imageEntityListMap, XMLSlideShow ppt) {
if (contentSlides != null) {
List<String> titles = (List<String>) keyCatalogMap.get(TITLE);
int len = contentSlides.size();
for (int i = 0; i < len; i++) {
createTitle(contentSlides.get(i), titles.get(i));
List<ImageEntity> entityList = imageEntityListMap.get(titles.get(i));
if (CollectionUtils.isEmpty(entityList)) {
continue;
}
for (ImageEntity imageEntity : entityList) {
createPicture(contentSlides.get(i), imageEntity.getUrl(), ppt, i);
}
}
}
}
/**
* 填充时间
*
* @param xslfSlide
* @param picCreateTime
*/
private static void createTime(XSLFSlide xslfSlide, String picCreateTime) {
//标题文本框
XSLFTextBox xslfTextBox = xslfSlide.createTextBox();
xslfTextBox.setAnchor(new Rectangle(400, 460, 300, 80));
xslfTextBox.setFlipHorizontal(true);
//段落
XSLFTextParagraph paragraph0 = xslfTextBox.addNewTextParagraph();
paragraph0.setTextAlign(TextParagraph.TextAlign.LEFT);
XSLFTextRun xslfTextRun = paragraph0.addNewTextRun();
xslfTextRun.setFontSize(18D);
//宋体 (正文)
xslfTextRun.setFontFamily("宋体");
String text = "123";
xslfTextRun.setText(String.format(text, picCreateTime));
}
/**
* 填充图片
*
* @param slide
* @param picturePath
* @param ppt
* @param flag
*/
private static void createPicture(XSLFSlide slide, String picturePath, XMLSlideShow ppt, int flag) {
try {
byte[] pictureData = IOUtils.toByteArray(new FileInputStream(picturePath));
XSLFPictureData pictureIndex = ppt.addPicture(pictureData, PictureData.PictureType.JPEG);
XSLFPictureShape pictureShape = slide.createPicture(pictureIndex);
if (flag == 4) {
pictureShape.setAnchor(new Rectangle(125, 100, 467, 200));
} else {
pictureShape.setAnchor(new Rectangle(125, 100, 467, 350));
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 目录填充
*
* @param xslfSlide
* @param catalogMap
*/
private static void fillCatalog(XSLFSlide xslfSlide, List<XSLFSlide> contentSlides, Map<String, Object> catalogMap) {
createTitle(xslfSlide, "目录");
//内容文本框
XSLFTextBox xslfTextBox = xslfSlide.createTextBox();
xslfTextBox.setAnchor((Rectangle) catalogMap.get(ANCHOR));
xslfTextBox.setFlipHorizontal(true);
//段落
XSLFTextParagraph paragraph = xslfTextBox.addNewTextParagraph();
paragraph.setTextAlign(TextParagraph.TextAlign.LEFT);
List<String> titles = (List<String>) catalogMap.get(TITLE);
if (CollectionUtils.isEmpty(titles)) {
return;
}
for (int i = 0, len = titles.size(); i < len; i++) {
XSLFTextRun xslfTextRun = paragraph.addNewTextRun();
xslfTextRun.setUnderlined(true);
xslfTextRun.setFontSize(36D);
xslfTextRun.setFontFamily("宋体");
xslfTextRun.setText(i + 1 + "、" + titles.get(i));
xslfTextRun.createHyperlink().setAddress(contentSlides.get(i).toString());
}
}
/**
* 生成标题头
*
* @param xslfSlide
* @param title
*/
private static void createTitle(XSLFSlide xslfSlide, String title) {
//标题文本框
XSLFTextBox xslfTextBox = xslfSlide.createTextBox();
xslfTextBox.setAnchor(new Rectangle(10, 25, 700, 85));
xslfTextBox.setFlipHorizontal(true);
//段落
XSLFTextParagraph paragraph0 = xslfTextBox.addNewTextParagraph();
paragraph0.setTextAlign(TextParagraph.TextAlign.CENTER);
XSLFTextRun xslfTextRun = paragraph0.addNewTextRun();
xslfTextRun.setFontSize(44D);
//黑体
xslfTextRun.setFontFamily("宋体");
xslfTextRun.setBold(true);
xslfTextRun.setText(title);
}
/**
* 填充首页内容
*
* @param xslfSlide
* @param firstValueMap
*/
private static void fillFirstContent(XSLFSlide xslfSlide, Map<String, Object> firstValueMap) {
//文本框
XSLFTextBox xslfTextBox = xslfSlide.createTextBox();
//坐标,x轴,y轴,宽度,高度
xslfTextBox.setAnchor((Rectangle) firstValueMap.get(ANCHOR));
xslfTextBox.setFlipHorizontal(true);
//段落
XSLFTextParagraph paragraph = xslfTextBox.addNewTextParagraph();
paragraph.setTextAlign(TextParagraph.TextAlign.CENTER);
//标题
XSLFTextRun xslfTextRun = paragraph.addNewTextRun();
xslfTextRun.setBold(true);
xslfTextRun.setFontSize(44D);
//宋体 (标题)
xslfTextRun.setFontFamily("宋体");
xslfTextRun.setText((String) firstValueMap.get(TITLE));
}
public static byte[] getFileToByte(File file) {
byte[] bytes = new byte[(int) file.length()];
try {
InputStream is = new FileInputStream(file);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] bb = new byte[2048];
int ch;
ch = is.read(bb);
while (ch != -1) {
byteStream.write(bb, 0, ch);
ch = is.read(bb);
}
bytes = byteStream.toByteArray();
} catch (Exception ex) {
ex.printStackTrace();
}
return bytes;
}
public static void main(String[] args) throws IOException {
Map<String, Object> keyValueMap = Maps.newHashMap();
keyValueMap.put("currentDate", "2021-09-07");
keyValueMap.put("productSerial", "211P-DL3-1-001");
keyValueMap.put("runTime", "2614.7");
ImageEntity imageEntity = new ImageEntity();
BASE64Encoder base64Encoder = new BASE64Encoder();
imageEntity.setData(getFileToByte(new File("C:/Users/熊浪/Desktop/20210611/RESULTS/Cell_voltage_vs_Stack_current_2.jpeg")));
//此处不一定使用imageEntity,只是需要图片的二进制byte数组,不存在二进制图片,这 keyValueMap.put("averageCellVoltageTimeImageBase64", base64EncoderValue);不添加,否则打开PPT报已损坏
String base64EncoderValue = base64Encoder.encode(imageEntity.getData());
keyValueMap.put("averageCellVoltageTimeImage", imageEntity);
keyValueMap.put("averageCellVoltageTimeImageBase64", base64EncoderValue);
keyValueMap.put("averageCellVoltageTimeImageWidth", 300);
keyValueMap.put("averageCellVoltageTimeImageHeight", 500);
keyValueMap.put("averageCellVoltageStackCurrentImage", imageEntity);
keyValueMap.put("averageCellVoltageStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("averageCellVoltageStackCurrentImageWidth", 300);
keyValueMap.put("averageCellVoltageStackCurrentImageHeight", 500);
keyValueMap.put("upperCellVoltageStackCurrentImage", imageEntity);
keyValueMap.put("upperCellVoltageStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("upperCellVoltageStackCurrentImageWidth", 300);
keyValueMap.put("upperCellVoltageStackCurrentImageHeight", 500);
keyValueMap.put("lowerCellVoltageStackCurrentImage", imageEntity);
keyValueMap.put("lowerCellVoltageStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("lowerCellVoltageStackCurrentImageWidth", 300);
keyValueMap.put("lowerCellVoltageStackCurrentImageHeight", 500);
keyValueMap.put("airInletPressureStackCurrentImage", imageEntity);
keyValueMap.put("airInletPressureStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("airInletPressureStackCurrentImageWidth", 300);
keyValueMap.put("airInletPressureStackCurrentImageHeight", 500);
keyValueMap.put("airMassFlowStackCurrentImage", imageEntity);
keyValueMap.put("airMassFlowStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("airMassFlowStackCurrentImageWidth", 300);
keyValueMap.put("airMassFlowStackCurrentImageHeight", 500);
keyValueMap.put("anodeDpWithoutPurgeStackCurrentImage", imageEntity);
keyValueMap.put("anodeDpWithoutPurgeStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("anodeDpWithoutPurgeStackCurrentImageWidth", 300);
keyValueMap.put("anodeDpWithoutPurgeStackCurrentImageHeight", 500);
keyValueMap.put("anodeDpWithPurgeStackCurrentImage", imageEntity);
keyValueMap.put("anodeDpWithPurgeStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("anodeDpWithPurgeStackCurrentImageWidth", 300);
keyValueMap.put("anodeDpWithPurgeStackCurrentImageHeight", 500);
keyValueMap.put("coolantInletTemperatureStackCurrentImage", imageEntity);
keyValueMap.put("coolantInletTemperatureStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("coolantInletTemperatureStackCurrentImageWidth", 300);
keyValueMap.put("coolantInletTemperatureStackCurrentImageHeight", 500);
keyValueMap.put("coolantDtStackCurrentImage", imageEntity);
keyValueMap.put("coolantDtStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("coolantDtStackCurrentImageWidth", 300);
keyValueMap.put("coolantDtStackCurrentImageHeight", 500);
keyValueMap.put("hrbSpeedStackCurrentImage", imageEntity);
keyValueMap.put("hrbSpeedStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("hrbSpeedStackCurrentImageWidth", 300);
keyValueMap.put("hrbSpeedStackCurrentImageHeight", 500);
keyValueMap.put("wcpSpeedStackCurrentImage", imageEntity);
keyValueMap.put("wcpSpeedStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("wcpSpeedStackCurrentImageWidth", 300);
keyValueMap.put("wcpSpeedStackCurrentImageHeight", 500);
keyValueMap.put("acpSpeedStackCurrentImage", imageEntity);
keyValueMap.put("acpSpeedStackCurrentImageBase64", base64EncoderValue);
keyValueMap.put("acpSpeedStackCurrentImageWidth", 300);
keyValueMap.put("acpSpeedStackCurrentImageHeight", 500);
// exportPpt(new File("C:/Users/熊浪/Desktop/20210611/1.ppt"), keyValueMap);
//设置模板格式和路径
Configuration configuration = new Configuration();
configuration.setDefaultEncoding("UTF-8");
configuration.setDirectoryForTemplateLoading(new File("D:/IDEAWORKSPACES/master_data_service/src/main/resources/bin"));
//读取模板路径下的PPT的.xml模板文件
Template template = configuration.getTemplate("IDURABILITY.xml", "UTF-8");
//设置导出路径
File outfile = new File("C:/Users/熊浪/Desktop/20210611/test.xml");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outfile)), 10240);
try {
//将数据替换并导出PPT
template.process(keyValueMap, out);
} catch (TemplateException e) {
e.printStackTrace();
} finally {
out.close();
}
}
}
注意:
1、此处不一定使用imageEntity,只是需要图片的二进制byte数组,不存在二进制图片,这 keyValueMap.put(“averageCellVoltageTimeImageBase64”, base64EncoderValue);不添加,否则打开PPT报已损坏
2、也可以添加一个空图片占位置,防止模板样式不对
模板路径:https://download.csdn.net/download/xionglangs/22010357**