原本的返回方法
@RequestMapping(value = "/download/{fileName}")
public void downloadFile(@PathVariable String fileName) throws IOException{
// 拼接真实路径
String realPath = getRequest().getServletContext().getRealPath("/")
+ "/" + fileName + ".xls";
// 读取文件
File file = new File(realPath);
if(file.exists()){
OutputStream os = new BufferedOutputStream(getResponse().getOutputStream());
try {
getResponse().setContentType("application/octet-stream");
if (getRequest().getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) { //IE浏览器
fileName = URLEncoder.encode(fileName + ".xls", "UTF-8");
} else {
fileName = URLDecoder.decode(fileName + ".xls");//其他浏览器
}
getResponse().setHeader("Content-disposition", "attachment; filename="
+ new String(fileName.getBytes("utf-8"), "ISO8859-1")); // 指定下载的文件名
os.write(FileUtils.readFileToByteArray(file));
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(os != null){
os.close();
}
}
}
}
使用response 的输出流直接操作。但是其实一般上面的操作都会放进Service层进行,这就需要将HttpServletresponse传进Service层或者在Controller层进行write操作,感觉不是很优雅,于是有了第二种方法。
ResponseEntity<byte[]>
@RequestMapping(value = "/download/{fileName}")
public ResponseEntity<byte[]> downloadFile(@PathVariable String fileName)
throws Exception {
fileName = fileName + ".xls";
// 1.拼接真实路径
String realPath = getRequest().getServletContext().getRealPath("/") + "/" + fileName;
// 2.读取文件
File file = new File(realPath);
// 4.设置格式
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", fileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 5.返回下载
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.OK);
}
是不是看起来清爽多了,不需要自己操作流;
这里有几个需要注意的点:
headers.setContentDispositionFormData("attachment", fileName)
设置的文件名是保存时候的文件名,attachment
表示在浏览器打开url时会直接下载;但是有时候我们有MP3的查看需求,这时候想要在浏览器调用自己的播放器来显示MP3,那就可以将attachment
换成inline
,这样表示直接在浏览器使用;
- ContentType 要准确