目录
- 说明
- 需求场景
- 实现
- 1、准备一个excel模板
- 2、把整个excel模板放在resources里面
- 3、重点代码
- 效果图
说明
需求场景
导出学校中高年级的学生信息,根据班级名称分组,一个班级一个excel导出,如果多个excel需要打包成zip压缩包下载,一个excel里面存在多个sheet的情况。
实现
1、准备一个excel模板
另一个sheet属于动态填充的表头和内容,里面不需要有什么信息
2、把整个excel模板放在resources里面
3、重点代码
@GetMapping("/upload")
public void upload() {
//初始化excel的数据体
List<Map<String, String>> maps = new LinkedList<>();
for (int i = 6; i < 13; i++) {
HashMap<String, String> map = new HashMap<>();
map.put("name", "小" + i);
map.put("age", "" + i);
maps.add(map);
}
//获取模板文件,模板文件需放在 resource下
String templateExcelFileName = "upload.xlsx";
InputStream templateExcelInputStream = this.getClass().getClassLoader().getResourceAsStream(templateExcelFileName);
if (null == templateExcelInputStream) {
log.info("模板文件不存在");
}
ByteArrayOutputStream outputStream = null;
ZipOutputStream zipOut = null;
try {
//处理导出的zip 文件名称,避免中文乱码
String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
String encodedFileName = URLEncoder.encode("高年级数据导出-" + date + ".zip", StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
response.setContentType("application/octet-stream; charset=UTF-8");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + encodedFileName);
zipOut = new ZipOutputStream(response.getOutputStream());
//复制输入模板文件流,避免第一次以后读取为空问题
ByteArrayOutputStream bos = cloneInputStream(templateExcelInputStream);
//多个excel名称
List<String> classList = Arrays.asList("四(二)", "五(二)", "六(二)");
//excel集合
for (int i = 0; i < classList.size(); i++) {
String className = classList.get(i);
InputStream copyInputStream = new ByteArrayInputStream(bos.toByteArray());
outputStream = new ByteArrayOutputStream();
ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(copyInputStream).excelType(ExcelTypeEnum.XLSX).build();
//设置 zip 中的每个文件名称
zipOut.putNextEntry(new ZipEntry("班级 - " + className + templateExcelFileName.substring(templateExcelFileName.lastIndexOf("."))));
/****************** 值填充逻辑开始,请按实际业务修改 ************************/
//固定模板填充内容 {}单个数据填充 {.}是集合数据填充,但是需要转义 这个要注意
WriteSheet writeSheet = EasyExcel.writerSheet(0, "学校信息").build();
Map<String, Object> map = new HashMap<String, Object>();
map.put("schoolName", "新民小学");
map.put("className", className + "班");
map.put("count", maps.size());
map.put("uploadDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
excelWriter.fill(map, writeSheet);
//动态填充表头和内容
WriteSheet attrSheet = EasyExcel.writerSheet(1, "班级学生信息").build();
List<String> heads = Arrays.asList("name", "age");
List<List<String>> excelHeaders = heads.stream().map(Collections::singletonList).collect(Collectors.toList());
attrSheet.setHead(excelHeaders);
excelWriter.write(excelDatas(heads, maps), attrSheet);
/****************** 值填充逻辑结束,请按实际业务修改 ************************/
excelWriter.finish();
outputStream.writeTo(zipOut);
outputStream.flush();
outputStream.close();
zipOut.closeEntry();
copyInputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("导出 excel -> zip 时出现异常" + e.getMessage());
} finally {
if (null != outputStream) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != zipOut) {
try {
zipOut.flush();
zipOut.finish();
zipOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 复制InputStream
* <p>
* InputStream inputStream = new ByteArrayInputStream(ByteArrayOutputStream.toByteArray());
*
* @param input
* @return
*/
public static ByteArrayOutputStream cloneInputStream(InputStream input) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
return baos;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 数据体转换后填充excel的数据
*
* @param attrs
* @param maps
* @return
*/
public List<List<String>> excelDatas(List<String> attrs, List<Map<String, String>> maps) {
List<List<String>> excelDatas = maps.stream().map(data ->
attrs.stream().map(column ->
Optional.ofNullable(data.get(column)).map(Object::toString).orElse("")
).collect(Collectors.toList())
).collect(Collectors.toList());
return excelDatas;
}
效果图
如果有更完善性能更好地方案,欢迎评论提出。
就先说到这
\color{#008B8B}{ 就先说到这}
就先说到这
在下
A
p
o
l
l
o
\color{#008B8B}{在下Apollo}
在下Apollo
一个爱分享
J
a
v
a
、生活的小人物,
\color{#008B8B}{一个爱分享Java、生活的小人物,}
一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞!
\color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!}
咱们来日方长,有缘江湖再见,告辞!