解决Springboot文件下载接口无法下载文件和 No converter for [XXX] with preset Content-Type 'application/octet-stream’和Cannot call sendError() after the response has been committed
首先看Controller里的方法,这里只复制了方法,没有把整个类复制下来,接口类有@RestController
@GetMapping("/temp/download")
public ResponseMessage managerDownload(HttpServletRequest request, HttpServletResponse response) {
// 获取当前登陆用户对象
User loginUser = (User) SecurityUtils.getSubject().getPrincipal();
if (!loginUser.getUserType().equals(UserType.MANAGER.getType())) {
return ResponseMessage.newErrorInstance("无法下载对应报告模版");
}
// 获取模版所属服务器路径
ReportTemplate reportTemplate = reportService.getReportTemplateByMajor(loginUser.getUserBelong());
String filePath;
if (ObjectUtil.isNotNull(reportTemplate)) {
filePath = reportTemplate.getPath();
} else {
return ResponseMessage.newErrorInstance("暂无报告模版");
}
// 截取文件名
String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 输入流
bis = new BufferedInputStream(new FileInputStream(new File(filePath)));
// 输出流
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int temp = 0;
// 每次读取的字符串长度
while ((temp = bis.read(buffer)) != -1) {
os.write(buffer, 0, temp);
}
return ResponseMessage.newSuccessInstance("下载模版成功");
} catch (Exception e) {
logger.error("用户{}下载模版失败: {}", loginUser.getRealName(), e.getMessage());
return ResponseMessage.newErrorInstance("下载模版失败");
} finally {
if (ObjectUtil.isNotNull(bis)) {
try {
bis.close();
} catch (IOException e) {
logger.error("{}", e.getMessage());
}
}
if (ObjectUtil.isNotNull(fis)) {
try {
fis.close();
} catch (IOException e) {
logger.error("{}", e.getMessage());
}
}
}
}
返回的ResponseMessage是一个自定义的统一返回数据的包装类
重点在try catch语句块内:
try {
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 输入流
bis = new BufferedInputStream(new FileInputStream(new File(filePath)));
// 输出流
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int temp = 0;
// 每次读取的字符串长度
while ((temp = bis.read(buffer)) != -1) {
os.write(buffer, 0, temp);
}
return ResponseMessage.newSuccessInstance("下载模版成功");
} catch (Exception e) {
//就不全部复制了
}
首先第一个点:文件没法下载的问题
创建输入流的时候用的是
bis = new BufferedInputStream(new FileInputStream(new File(filePath)));
但其实new File(filePath)是冗余的,所以删掉,直接改成:
bis = new BufferedInputStream(new FileInputStream(filePath));
这样能解决文件没法下载的问题
接着是No converter for [XXX] with preset Content-Type ‘application/octet-stream’ 和 Cannot call sendError() after the response has been committed问题
解决方案是:将方法的返回值改为void,并将所有return对象改为return;
@GetMapping("/temp/download")
public void managerDownload(HttpServletRequest request, HttpServletResponse response) {
.......
}
这样就能正常的下载文件而且不会疯狂报错了。