功能介绍
平时有一些需求是需要将我们设置好的excel模板上动态渲染上数据,并且实现excel、pdf等格式文件的导出功能。比如将用户填写的表单信息渲染到excel中制成表格并导出。
例如如下表格,希望根据这个模板中的el表达式动态渲染数据,然后生成pdf,并实现下载或者预览功能。
通过springboot程序,生成pdf。
代码实现
springboot依赖
<!--poi相关依赖-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
<groupId>org.apache.poi</groupId>
</dependency>
<!--生成pdf工具-->
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.xls.free</artifactId>
<version>5.1.0</version>
</dependency>
<!--将字符串中的${}替换-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
导出方法
为了方便,我们把模板信息和签字图片直接放在resource目录下,在实际开发中,会将文件放在服务器上。
springboot中sevice层实现。
// excel模板文件
String modelFile = "personalInformation.xlsx";
// 签字图片
String image = "zhangsan.png";
// 生成的pdf文件
String filename = "person.pdf";
/**
* @param userInfoModel
* @param response
*/
@Override
@SneakyThrows
public void createPdf(UserInfoModel userInfoModel, HttpServletResponse response) {
// 将对象转换为map
Map<String, String> map = JSON.parseObject(JSON.toJSONString(userInfoModel)
, new TypeReference<Map<String, String>>() {
});
// 获取resource下的excel模板
ClassPathResource classPathResource = new ClassPathResource(modelFile);
InputStream inputStream = classPathResource.getInputStream();
// 读入创建的模板
XSSFWorkbook wb = new XSSFWorkbook(inputStream);
// 获取第一个sheet
XSSFSheet sheet = wb.getSheetAt(0);
// 获取画布,每个sheet只有一个,向excel渲染图片用
XSSFDrawing drawing = sheet.createDrawingPatriarch();
for (Iterator ite = sheet.rowIterator(); ite.hasNext(); ) {
XSSFRow row = (XSSFRow) ite.next();
// 遍历excel的每个单元格,替换模板中的el表达式${}
for (Iterator itet = row.cellIterator(); itet.hasNext(); ) {
XSSFCell cell = (XSSFCell) itet.next();
if (cell != null) {
// 获取单元格中的文本
String cellValue = cell.getStringCellValue();
// 替换${}
String replaceEl = StringUtil.replaceEl(cellValue, map);
// 回写替换后的文本到excel单元格
cell.setCellValue(replaceEl);
}
}
}
// 获取resource下的用户签字图片
ClassPathResource classPathResource1 = new ClassPathResource(image);
InputStream inputStream1 = classPathResource1.getInputStream();
// 将用户签字图片渲染到excel中
int picture = wb.addPicture(inputStream1, Workbook.PICTURE_TYPE_PNG);
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 5, 6, 5, 6);
drawing.createPicture(anchor, picture).resize(0.05);
// 设置响应头并获取响应输出流
OutputStream outputStream = getOutputStream(response, filename);
// 将渲染好的excel文件写出响应输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
wb.write(byteArrayOutputStream);
// 将输出流转换为输入流
InputStream excelInput = outputToinputStream(byteArrayOutputStream);
// 将生成的excel转换为pdf
PdfUtils.excelToPdf(excelInput, outputStream);
}
/**
* 将ByteArrayOutputStream转换为inputStream
*
* @param byteArrayOutputStream
* @return
*/
private InputStream outputToinputStream(ByteArrayOutputStream byteArrayOutputStream) {
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
/**
* 设置响应头为下载并获取响应输出流
*
* @param response
* @param filename
* @return
*/
private OutputStream getOutputStream(HttpServletResponse response, String filename) {
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
// attachment为文件下载
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
return outputStream;
}
替换el表达式的工具类。
/**
* @author jiangtao
* @create 2022/10/2 17:33
*/
@Slf4j
public class StringUtil {
/**
* 将字符串的${} 转换成map中的字符串,若在map中找不到该字段,则替换为空字符串
*
* @param string
* @param map
* @return
*/
public static String replaceEl(String string, Map map) {
StringSubstitutor stringSubstitutor = new StringSubstitutor(map);
String replace = stringSubstitutor.replace(string);
HashMap<String, String> hashMap = new HashMap<>();
while (StringUtils.isNotBlank(replace) && replace.contains("${")) {
String substring = replace.substring(replace.indexOf("{") + 1, replace.indexOf("}", 2));
log.info("找不到{},替换为空字符串", substring);
hashMap.put(substring, "");
stringSubstitutor = new StringSubstitutor(hashMap);
replace = stringSubstitutor.replace(replace);
}
return replace;
}
}
postman测试
通过发送表单信息,成功将excel模板进行渲染。