## EasyExcel文件导出错误解决
最近在做一个项目,有将记录导出Excle的需求,采用了阿里的EasyExcel工具,导出功能学习很快,很快参考网站上的代码和官网上资料搞定,并且开发环境(windows)使用非常正常,但是上传到内网测试服务器后,导出总是从异常处退回,服务器端也没有什么信息,这个坑费了和2天时间,特记录下来与大家共享。
## 一、 先上代码
服务器站代码如下,这段代码使用官网代码一致,只是修改了数据:
```java
List<QuarantineExport> quarantineExports = employeeService.quarantineExportData(company, department, selectCodeColor, selectQuarState);
String fileName = URLEncoder.encode("健康码统计信息.xls", "UTF-8");
try {
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(), QuarantineExport.class)
.autoCloseStream(Boolean.FALSE)
.sheet("隔离信息")
.doWrite(employeeService.quarantineExportData(company, department,selectCodeColor,selectQuarState));
} catch (Exception e) {
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap<String, String>();
map.put("status", "failure");
map.put("message", "下载文件失败" + e.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
```
前端代码,我有两种模式调整,一种是用按钮直接调URL简单调用,另一种是用ajax和jqery组合复杂条件调用,代码如下。
```javascript
var department = $('#departmentList').val();
var selectCodeColor = $('#selectCodeColor').val();
var selectQuarState = $('#selectQuarState').val();
var url = "/statListExport?department="+department+"&selectCodeColor="+selectCodeColor+"&selectQuarState="+selectQuarState;
$.ajax({
type: "get",
async: true,
url: url,
contentType: "application/vnd.ms-excel",
success: function (data) {
console.log(data);
},
error: function (errorMsg) {
//请求失败时执行该函数
alert("导出失败!");
}
})
```
## 二、错误现象
在开发环境使用非常正常,没有任何问题,上传到测试环境服务器不能导出文件,总是产生一个 "下载文件失败" 的json文件,查了很多资料都没有找到方法。
首先,从前端分析错误,这时从前端控制台上发现有一个警告信息,
Resource interpreted as Document but transferred with MIME type application/msexcel:
以为是后台传输正常,到测试服务器环境后这个原因导致的,在这个问题上搞了我一整天,按了4种前端接受后台文件方法,代码贴出来,给大家分享一下。
```javascript
//这3条是从表单取查询条件
var department = $('#departmentList').val();
var selectCodeColor = $('#selectCodeColor').val();
var selectQuarState = $('#selectQuarState').val();
//w合成后台GET数据的URL,这儿把参数合在一起了,也可以用dataForm或json字符串
var url = "/statListExport?department="+department+"&selectCodeColor="+selectCodeColor+"&selectQuarState="+selectQuarState;
//方法一:
var xhr = new XMLHttpRequest();
xhr.open('Get', url, true);
xhr.responseType = "blob"; // 返回类型blob
xhr.onload = function () {
if (this.status === 200) {
var blob = this.response;
var reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href
reader.onload = function (e) {
var a = document.createElement('a');
a.download = '健康码统计信息.xlsx';//下载文件名
a.href = e.target.result;
$("body").append(a); // 修复firefox中无法触发click
a.click();
$(a).remove();
}
}
};
// 发送ajax请求
xhr.send()
//方法二:
var a = document.createElement('a');
a.setAttribute("href",url);
a.click();
document.body.removeChild(a);*/
//方法三
var iframe = document.createElement('iframe');
iframe.id = "IFRAMEID";
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.src = url;
iframe.addEventListener("load", function () {
console.log("FILE LOAD DONE.. Download should start now");
});
//方法四:
$.ajax({
type: "get",
async: true,
url: url,
contentType: "application/vnd.ms-excel",
success: function (data) {
console.log(data);
},
error: function (errorMsg) {
//请求失败时执行该函数
alert("导出失败!");
}
})
```
从上面代码看,有四种方法可以从后台获取语言件流,供后续使用。这四种方未能分别都试过,原来以为前后端文件流格式不一样导致,由于开发环境没这个问题,只有生产环境有。开发环境与测试环境不一样真是问题大啊,整了一天都没有找到答案。
前端找不到答案只能继续在后台找,第二天折腾后台代码,网上打到一个旧的案例,死马当活马医,试试看,没想到用旧的代码虽然一堆过时的警告,上传到测试环境服务服务器竟然工作了,泪奔啊,代码如下,供大家参考:
```java
List<QuarantineExport> quarantineExports = employeeService.quarantineExportData(company, department, selectCodeColor, selectQuarState);
String fileName = URLEncoder.encode("健康码统计信息.xls", "UTF-8");
//写excel文件
ExcelWriter writer = null;
OutputStream outputStream = response.getOutputStream();
try {
//添加响应头信息
response.setHeader("Content-disposition", "attachment; filename=" + fileName);
response.setContentType("application/msexcel;charset=UTF-8");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
//实例化 ExcelWriter
writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLS, true);
//实例化表单
Sheet sheet = new Sheet(1, 0, QuarantineExport.class);
sheet.setSheetName("隔离信息");
//输出
writer.write(quarantineExports, sheet);
writer.finish();
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
```
## 三、问题原因
搞了一天都没搞定,找到了EasyExcel钉钉群,刚好EasyExcel作之一庄家钜在群中解签问题,在此感谢作都的提示。
作都提示open jdk存在字体不全的问题,可能导致类似问题。
又找了一圈,没有解决问题的头绪,网上有一个说是将生产环境换为oracle JdK,哎,oracle JDK修订版不是免费的啊,这是一个写着玩的项目,算了,继续用过时的方法吧。
注意这个过时的方法导出的excel文件是低版本的,够用了,文件扩展名只能为xls,不要用xlsx否则打不开。
如正式要用,还是将open jdk字体安装全,或都用oracle jdk吧。这是恢复编程学习以来遇到最大的一个坑,坑了我2天时间,特记录。
老伍。
本文暂时没有评论,来添加一个吧(●'◡'●)