场景背景
1.一般来说,都是使用get请求后台接口,如此后台返回文件流于浏览器,则可直接下载。
2.那么除一般情况,就有特殊情况,比如你的请求接口参数特别长,此时便不可使用get请求,get请求的参数长度是有限的。那么就使用到本文的解决方案。
废话不多说,直接撸代码!!!
一 JAVA后台接口示例
/**
* 下载文件
*
* @param request request请求对象
* @param response response相应对象
* @param userVO 请求参数-接收前端formData对象
*/
@RequestMapping("/download")
@ResponseBody
public void downloadFile(HttpServletRequest request, HttpServletResponse response, UserVO userVO) throws IOException {
//得到要下载的文件名
String fileName = request.getParameter("filename");
fileName = new String(fileName.getBytes("iso8859-1"), StandardCharsets.UTF_8);
//上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
String fileSaveRootPath = request.getServletContext().getRealPath("/WEB-INF/upload");
//通过文件名找出文件的所在目录
String path = findFileSavePathByFileName(fileName, fileSaveRootPath);
//得到要下载的文件
File file = new File(path + "\\" + fileName);
//如果文件不存在
if (!file.exists()) {
request.setAttribute("message", "您要下载的资源已被删除!!");
return;
}
//处理文件名
String realName = fileName.substring(fileName.indexOf("_") + 1);
//设置响应头,控制浏览器下载该文件,此处的文件名要进行编码处理否则前端显示会乱码
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realName, String.valueOf(StandardCharsets.UTF_8)));
try (//读取要下载的文件,保存到文件输入流
FileInputStream in = new FileInputStream(path + "\\" + fileName);
//创建输出流
OutputStream out = response.getOutputStream()) {
//创建缓冲区
byte[] buffer = new byte[1024];
int len = 0;
//循环将输入流中的内容读取到缓冲区当中
while ((len = in.read(buffer)) > 0) {
//输出缓冲区的内容到浏览器,实现文件下载
out.write(buffer, 0, len);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
二 前端代码示例
function exportFn() {
var userVO = new FormData();
userVO.append('id', id)
userVO.append('name', name)
ax({
method: 'post',
url: baseUrl+"/download"),
data: userVO,
//重要:相应类型必须为blob
responseType: 'blob'
}).then(function (res) {
var contentDisposition = decodeURI(res.headers["content-disposition"]);
var fileRegex = /([^(filename=)]+\.xlsx?)$/g;
var result = contentDisposition.match(fileRegex);
var fileName = '检查率统计.xlsx';
if (result.length > 0) {
fileName = result[0]
}
var blob = new Blob([res.data]);
var url = window.URL.createObjectURL(blob); // 创建 url 并指向 blob
var a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url); // 释放该 url
$("input[name=CSRFTid]").hide()
});
}
注意事项:
一 后台文件名需要进行编码操作
//设置响应头,控制浏览器下载该文件,此处的文件名要进行编码处理否则前端显示会乱码
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realName, String.valueOf(StandardCharsets.UTF_8)));
二 前端文件名称进行解码操作
//从header中获取到包含文件名的信息进行解码操作
var contentDisposition = decodeURI(res.headers["content-disposition"]);
三 前端获取文件名
//从header中取得包含文件名的信息并进行解码
var contentDisposition = decodeURI(res.headers["content-disposition"]);
//匹配文件名的正则
var fileRegex = /([^(filename=)]+\.xlsx?)$/g;
var result = contentDisposition.match(fileRegex);
var fileName = '检查率统计.xlsx';
//取得文件名并赋值
if (result.length > 0) {
fileName = result[0]
}
后语:
至此,大功告成!!!