常用组件:
WorkbookFactory excel的文档对象
Sheet excel的表单
Row excel的行
Cell excel的格子单元
Font excel字体
样式:
CellStyle cell样式
实现步骤:
1.添加maven依赖
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
2.编写Controller
使用spring webflux文件下载就没有之前基于servlet容器的javax.servlet.http.HttpServletResponse了,取而代之的是org.springframework.http.server.reactive.ServerHttpResponse。
@GetMapping("/caterings/export")
public Mono<Void> export(ServerHttpResponse response, Search search) throws IOException {
return cateringManager.export(response, search);
}
3.编写Manager
public Mono<Void> export(ServerHttpResponse response, Search search)
throws IOException {
//spring webflux文件下载零拷贝(Zero-copy)
ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
//设置文件下载响应头
response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=cateringConsole.xlsx");
response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
//获取数据
return getCateringConsole(search).concatMap(s -> getStatistics(s)).collectList().flatMap(statistics -> {
try {
String relTarget = "/static/cateringConsole.xlsx";
//声明输入流
InputStream inputStream = null;
//声明输出流
OutputStream fout = null;
//声明临时文件
File targetFile = null;
// getResourceAsStream不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
inputStream = this.getClass().getResourceAsStream(relTarget);
//创建临时文件(在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。)
targetFile = File.createTempFile("cateringConsole", "");
//excel的文档对象(WorkbookFactory)
final Workbook wb = WorkbookFactory.create(inputStream);//WorkbookFactory可以读取xls格式或xlsx格式
//获取该工作区的第一个sheet
Sheet sheet = wb.getSheetAt(0);
//创建样式类
CellStyle cellStyle = wb.createCellStyle();
// 设置自动换行
cellStyle.setWrapText(true);
// 水平居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 垂直居中
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 设置字体
Font font = wb.createFont();
font.setFontName("宋体");
// 设置字体粗细
font.setBoldweight(HSSFFont.DEFAULT_CHARSET);
// 设置字体大小
font.setFontHeightInPoints((short) 13);
// 选择需要用到的字体格式
cellStyle.setFont(font);
// 设置边框
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 下边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);// 左边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);// 上边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);// 右边框
//设置该工作区的第一个sheet名字
wb.setSheetName(0, "统计");
for (int i = 0; i < statistics.size(); i++) {
//创建第二行
Row row = sheet.createRow(i + 1);
//设置每行行高
row.setHeightInPoints(28);
//日期
Cell cell1 = row.createCell(0);
cell1.setCellValue(statistics.get(i).getDate());
cell1.setCellStyle(cellStyle);
//地区
Cell cell2 = row.createCell(1);
cell2.setCellValue(statistics.get(i).getPlaceName());
cell2.setCellStyle(cellStyle);
//早餐数
Cell cell3 = row.createCell(2);
cell3.setCellValue(statistics.get(i).getTotalBreakfast());
cell3.setCellStyle(cellStyle);
//中餐数
Cell cell4 = row.createCell(3);
cell4.setCellValue(statistics.get(i).getTotalLunch());
cell4.setCellStyle(cellStyle);
//晚餐数
Cell cell5 = row.createCell(4);
cell5.setCellValue(statistics.get(i).getTotalDinner());
cell5.setCellStyle(cellStyle);
}
//创建最后一行
Row row = sheet.createRow(statistics.size() + 1);
//设置每行行高
row.setHeightInPoints(28);
//创建合并单元格对象(CellRangeAddress:单元格合并函数)
CellRangeAddress callRangeAddress = new CellRangeAddress(statistics.size() + 1, statistics.size() + 1, 0, 1);//起始行,结束行,起始列,结束列
//加载合并单元格对象
sheet.addMergedRegion(callRangeAddress);
Long totalBreakfastSum = statistics.stream().mapToLong(Statistics::getTotalBreakfast).sum();
Long totalLunchSum = statistics.stream().mapToLong(Statistics::getTotalLunch).sum();
Long totalDinner = statistics.stream().mapToLong(Statistics::getTotalDinner).sum();
Cell cell = row.createCell(0);
cell.setCellValue("合计");
cell.setCellStyle(cellStyle);
//合计早餐数
Cell cell0 = row.createCell(1);
cell0.setCellValue("");
cell0.setCellStyle(cellStyle);
//合计午餐数
Cell cell1 = row.createCell(2);
cell1.setCellValue(totalBreakfastSum);
cell1.setCellStyle(cellStyle);
Cell cell2 = row.createCell(3);
cell2.setCellValue(totalLunchSum);
cell2.setCellStyle(cellStyle);
//合计晚餐数
Cell cell3 = row.createCell(4);
cell3.setCellValue(totalDinner);
cell3.setCellStyle(cellStyle);
//将临时文件输出
fout = new BufferedOutputStream(new FileOutputStream(targetFile));
//写入工作区
wb.write(fout);
//这里将数据写入ServerHttpResponse
return zeroCopyResponse.writeWith(targetFile, 0, targetFile.length());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
4.测试
测试的话可以使用swagger或者postman,甚至你前端技术足够ok的话也可以写个简单的页面进行测试,我是用的是postman进行的测试,下面就是我测试的结果了: