一般导出流程图如下:
组装数据: 包括excel中表头、数据及样式
导出: 文件流
官方文档总结的都是经典~
表头: 分为固定表头和动态表头,然后再可以继续划分简单版本和复杂版本,其中复杂版本类似有三四级表头(以前写poi硬编码写到爆炸=_=||)~ 示例如下(图片来源):
数据: 随表头变更
固定表头,可声明一个实体类进行定义,如下:
@Data
public class TitleData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
}
动态表头,只能自己手动写代码进行定义,如下:
// 外层数组,一个值代表一列
List<List<String>> headList = new ArrayList<List<String>>();
List<String> head0 = new ArrayList<String>();
head0.add("字符串标题");
headList.add(head0);
List<String> head1 = new ArrayList<String>();
head1.add("日期标题");
headList.add(head1);
List<String> head2 = new ArrayList<String>();
head2.add("数字标题");
headList.add(head2);
@Data
public class ComplexHeadData {
@ExcelProperty({"主标题", "字符串标题"})
private String string;
@ExcelProperty({"主标题", "日期标题"})
private Date date;
@ExcelProperty({"主标题", "数字标题"})
private Double doubleData;
}
web项目一般有两种导出方式:
本文主要关注文件流方式,示例代码如下:
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
本案例比较简单,根据请求参数time来动态定义表头和创建数据,并以文件流方式返回给前端。 效果如下:
pom中添加依赖:
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>2.2.7version>
dependency>
业务逻辑代码如下:
@RestController
public class ResultController {
@PostMapping(value = "/export")
public void export(@RequestParam Integer time) {
try {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
response.setHeader("Content-Disposition", "attachment; filename=export.xlsx");
// 响应类型,编码
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setCharacterEncoding("utf-8");
EasyExcel.write(response.getOutputStream()).head(getHead(time)).sheet("数据").doWrite(getData(time));
} catch (IOException e) {
log.error("导出问卷数据失败!错误信息为:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 获取excel标题栏(姓名、手机号、提交时间)
* @param questionnaireId
* @return
*/
private List<List<String>> getHead(Integer time) {
// 外层数组,一个值代表一列
List<List<String>> headList = new ArrayList<List<String>>();
List<String> nameList = new ArrayList<String>();
nameList.add("姓名");
headList.add(nameList);
List<String> telList = new ArrayList<String>();
telList.add("手机号");
headList.add(telList);
List<String> submitDTList = new ArrayList<String>();
submitDTList.add("提交时间");
headList.add(submitDTList);
for (int i = 0 ; i < time ; i ++ ) {
List<String> list = new ArrayList<String>();
list.add("动态标题" + i);
headList.add(list);
}
return headList;
}
/**
* 获取excel表格数据
* @return
*/
private List<List<Object>> getData(Integer time) {
// 将填写结果 + 提交时间合并为一行数据
List<List<Object>> resultList = new ArrayList<List<Object>>();
for (int i = 0 ; i < 3 ; i ++ ) {
List<Object> list = new ArrayList<Object>();
list.add("花卷" + i);
list.add("1347000000" + i);
list.add("2022-01-18 14:54:00");
for (int j = 0 ; j < time ; j ++ ) {
list.add("动态内容" + j);
}
resultList.add(list);
}
return resultList;
}
}
问题描述: 后台用postman调试都ok,能正常打开excel!但是前端调试时下载的excel提示有破损,无法打开!!!
Tips: 勇敢(不怕死)的质疑前端,你代码有BUG!
解决方案: 前端需在request和response中添加responseType: blob
设置
(以下伪代码,请重点关注responseType设置即可)
responseType为arraybuffer或blob
return request({
url: '/platform/export',
method: 'post',
responseType: 'blob',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: qs.stringify(data)
})
application/msexcel
handleExport(){
exportData({id: this.id}).then(res => {
if(res){
const fileName = this.name + '.xlsx';
var blob = new Blob([res], {
type: "application/msexcel;charset=utf-8",
});
const URL = window.URL || window.webkitURL;
const downloadElement = document.createElement("a");
const href = URL.createObjectURL(blob); // 创建下载的链接
downloadElement.href = href;
downloadElement.download = fileName; // 下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); // 点击下载
document.body.removeChild(downloadElement); // 下载完成移除元素
URL.revokeObjectURL(href); // 释放掉blob对象
}
})
},
测试小姐姐提了个单,token超时后,点击下载按钮还是能正常导出,excel内容是后端认证系统返回的错误码json串 =_=|| ,网上查找一番也找大佬们讨论了下,对于将文件流封装成系统设定的统一返回json方式不可取,最后抱着前端小姐姐的细腿求解决喽
解决方法:前端获取response后根据 content-type
进行区分
网上参考文档