写这个博客之前我并不清楚 ajax请求是下载不了文件的 ?? 这段时间在写一个自己的项目,用到了ajax下载文件,请求到了controller层并返回文件下载成功 但是浏览器就是没有反应,找了很多资料以及在网上搜了很多文章,但找到的文章的着重点 还是在controller层对文件的处理上,最后为了验证controller是没有问题的,我就在jsp中直接写了一个form表单提交,可想而知的效果是文件顺利下载下来了,所以反过来想应该是ajax请求的问题,因为我的业务场景是 当用户点击下载按钮时,控制层接收到请求后 先去查询数据,然后拼装成一个Excel文件,把文件上传到服务器,我的想法是由于中间的流程或者说逻辑有些复杂可能会出现一些不可预料的异常 需要反馈给用户,所以这就变成了不仅是下载文件这么简单,如果直接用form表单提交 我就无法展示系统的错误信息。
这中间也发生了这样的异常 java.lang.IllegalStateException: getOutputStream() has already been called for this response;
遇到这样报错的原因是:controller层返回了一个jsp,但是这个请求是 下载文件
返回一个页面时web容器生成的servlet代码中有out.write("") 字符型输出流,但是在写文件到浏览器时 我用response.getOutputStream() 字节型输出流,所以导致了这个冲突
其实这个异常和本次我写这个博客的目的无关 只是我在解决这个业务场景时 原本想到的解决方案但出现了异常也就pass(淘汰)了我这个想法,所以为了让自己以后不会出现相同的问题就随口一说
应对这个场景正确的解决方案:
前端jsp://一个输入框 两个按钮 一个按钮是计算 一个按钮是下载
<label>请输入一个标识符:</label>
<div>
<input id="flagnum" type="text" name="flagNum" />
</div>
<button id="button-cal">calculation</button>
<button id="button-down">download</button>
js:// 计算的忽略 只看下载
$(function(){
// 监听download按钮的点击事件 相当于document.getElementById("button-down")
$("#button-down").click(function(){
// 获取两个标签之间的值用 .text(); 标签内的value值 用 .val();
var flagNum = $("#flagnum").val();
//发送ajax请求
$.ajax({
url: "export",
type: "post",
data: {"flagNum": flagNum},
success: function(data){
//这一块我在后端封装了一个响应对象 {message:{success:true, returnObject{这里是一个map}, msg:"响应信息", code:响应状态码, name:响应名称},data:{这里是一个map}}
var message = data.message;
if(message.success){
//调用如下用于拼接form表单请求的download方法
// url 是请求的路径 name就是input表单中的name value是export这个请求获取的服务器中的文件地址 method 是请求方法 post / get
download("url","name","value","method");
}else {
alert(这里输出一下错误信息);
}
},
error: funciton(e){
alert(接口调用失败);
}
});
});
});
function download(url,name,value,method){
//拼接一个form表单 里面有input标签 追加到<body>标签中 提交后删除这个form表单;
$(<form action="‘+url+‘" method="‘+method+‘"><input type="text" name="‘+name+‘" value="‘+value+‘" /></form>).appendTo("body").submit().remove();
}
controller 层:
@RequestMapper("download")
public void download(HttpServletResponse response, @Param("filePath") String filePath){
FileDowloadUtil.windowDownload(response, filePath);
}
文件下载的工具类 FileDowloadUtil:
public static void windowDownload(HttpServletResponse response, String filePath){
// 判断文件地址是否为空
if(filePath.isEmpty()){
return;
}
//获取文件名
//String fileName = filePath.subString(filePath.lastIndexOf(".") +1);
File file = new File(filePath);
if(file == null){
return;
}
String fileName = file.getName();
//设置响应头,控制浏览器下载该文件 设置下载的文件为excel application/vnd.ms-excel 下载别的文件是 百度下 content-type 对应的文件类型即可
try {
fileName = URLEncoder.encode(fileName,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setHeader("content-type","application/vnd.ms-excel");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
byte[] bytes = new byte[1024];
InputStream is = null;
OutputStream out = null;
try {
is = new FileInputStream(file);
out = response.getOutputStream();
int len = 0;
while ((len = is.read(bytes)) != -1){
out.write(bytes,0,len);
out.flush();
}
} catch (UnsupportedEncodingException e) {
log.error("异常:"+e.getMessage());
} catch (IOException e){
log.error("异常:"+e.getMessage());
} finally {
if (out != null){
try {
out.close();
} catch (IOException e) {
log.error("异常:"+e.getMessage());
}
}
if (is != null){
try {
is.close();
} catch (IOException e) {
log.error("异常:"+e.getMessage());
}
}
}
}
如上就是解决方案的全部代码;