使用deepoove根据模板导出word文档,包括文本、表格、图表、图片,使用WordConvertPdf可将word文档转换为pdf导出
模板样例:
导出结果:
一、引入相关依赖
<!-- 工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<!-- poi-->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.11.1</version>
</dependency>
<!-- word转pdf-->
<dependency>
<groupId>WordConvertPdf</groupId>
<artifactId>WordConvertPdf</artifactId>
<version>1.0</version>
</dependency>
二、创建导出数据实体类
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "ExportVO", description = "导出VO")
public class ExportVO {
@ApiModelProperty(value = "标题")
private String title;
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "数量")
private Integer num;
@ApiModelProperty(value = "集合数据")
private List<ExportListVO> list;
@ApiModelProperty(value = "表格")
private List<ExportListVO> table;
@ApiModelProperty(value = "柱状图")
private ChartMultiSeriesRenderData barChart;
@ApiModelProperty(value = "饼图")
private ChartSingleSeriesRenderData pieChart;
@ApiModelProperty(value = "折线图")
private ChartMultiSeriesRenderData lineChart;
@ApiModelProperty(value = "图片")
private PictureRenderData img;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "ExportListVO", description = "导出集合VO")
public class ExportListVO {
@ApiModelProperty(value = "类型")
private String type;
@ApiModelProperty(value = "数量")
private Integer num;
}
三、业务代码
/**
* 文档导出
*
* @param fileType 导出文件类型:1-docx,2-pdf
* @param response 响应流
*/
@Override
public void exportFile(Integer fileType, HttpServletResponse response) throws IOException {
String filePath = "templates/word/test.docx";
//使用poi-tl进行模板处理
ConfigureBuilder builder = Configure.builder();
builder.useSpringEL(true);
//执行循环策略
LoopRowTableRenderPolicy strategy = new LoopRowTableRenderPolicy();
//绑定集合对象
builder.bind("list", strategy);
builder.bind("table", strategy);
//获取模板文件流
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
assert inputStream != null;
//组装数据
ExportVO data = this.createData();
XWPFTemplate render = XWPFTemplate.compile(inputStream, builder.build()).render(data);
// 设置强制下载不打开
response.setContentType("application/force-download");
response.addHeader("Access-Control-Expose-Headers", " Content-Disposition");
if (fileType.equals(1)) {
//如果需要导出为word
response.addHeader("Content-Disposition", "attachment; fileName=" + new String(("导出模板.docx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
render.write(response.getOutputStream());
} else if (fileType.equals(2)) {
//如果需要导出为pdf
response.addHeader("Content-Disposition", "attachment; fileName=" + new String(("导出模板.pdf").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
//设置临时文件的地址
String tempPath = UUID.randomUUID() + ".docx";
//根据模板生成临时文件
render.writeToFile(tempPath);
//将docx流转换为pdf流
FileInputStream fileInputStream = new FileInputStream(tempPath);
WordConvertPdf.getPdfStreamByWordStream(fileInputStream, outputStream);
outputStream.flush();
outputStream.close();
fileInputStream.close();
//删除临时文件
File tempFile = new File(tempPath);
Files.delete(tempFile.toPath());
log.debug("删除临时word文件:{}", tempPath);
}
}
需要注意的时,文档中需要循环的数必须绑定biulder
四、createData方法
private ExportVO createData() {
ExportVO data = new ExportVO();
//普通文本
data.setTitle("食品统计");
data.setName("蔬菜统计");
data.setNum(60);
//集合数据
List<ExportListVO> list = new ArrayList<>();
list.add(new ExportListVO("黄瓜", 10));
list.add(new ExportListVO("茄子", 20));
list.add(new ExportListVO("番茄", 30));
//添加循环文本数据
data.setList(list);
//添加表格数据
data.setTable(list);
//添加柱状图数据
ChartMultiSeriesRenderData barChart = new ChartMultiSeriesRenderData();
barChart.setChartTitle("蔬菜统计柱状图");
barChart.setCategories(list.stream().map(ExportListVO::getType).toArray(String[]::new));
List<SeriesRenderData> barChartSeriesData = new ArrayList<>();
barChartSeriesData.add(new SeriesRenderData("箱", list.stream().map(ExportListVO::getNum).toArray(Integer[]::new)));
barChart.setSeriesDatas(barChartSeriesData);
data.setBarChart(barChart);
//添加饼图数据
ChartSingleSeriesRenderData pieChart = new ChartSingleSeriesRenderData();
pieChart.setChartTitle("蔬菜统计饼图");
pieChart.setCategories(list.stream().map(ExportListVO::getType).toArray(String[]::new));
pieChart.setSeriesData(new SeriesRenderData("箱", list.stream().map(ExportListVO::getNum).toArray(Integer[]::new)));
data.setPieChart(pieChart);
//添加折现图
ChartMultiSeriesRenderData lineChart = new ChartMultiSeriesRenderData();
lineChart.setChartTitle("蔬菜统计折线图");
lineChart.setCategories(list.stream().map(ExportListVO::getType).toArray(String[]::new));
List<SeriesRenderData> lineChartSeriesData = new ArrayList<>();
lineChartSeriesData.add(new SeriesRenderData("箱", list.stream().map(ExportListVO::getNum).toArray(Integer[]::new)));
lineChart.setSeriesDatas(lineChartSeriesData);
data.setLineChart(lineChart);
//添加图片
PictureRenderData img = new PictureRenderData(800, 200, "D:\\files\\img\\test.jpg");
data.setImg(img);
return data;
}
五、模板说明
1.这里面由{{}}包裹的内容对应ExportVO 实体中的属性名称