Ajax⽅式⽂件下载(后台返回为json或⽂件流)
css鼠标按下样式在应⽤开发中,经常需要下载⽂件(如导出Excel),调⽤后台接⼝时,如果后台报错需要弹出错误信息,如果没有报错正常下载⽂件。本⽂主要介绍前台及后台(基于java)的处理⽅法,⽂中使⽤到的软件版本:Spring 4.3.9、Java 1.8.0_191、Jquery 1.12.4、Chrome 85.0.4183.121。
1、实现思路
⽅法⼀:通过原⽣Ajax响应头来区分是⽂本还是流,然后通过blob来处理返回数据
⽅法⼆:分成两个接⼝,先调⽤⽣成⽂件的接⼝,如果⽂件成功⽣成则再调⽤⽂件下载的接⼝;如果⽂件⽣成失败则弹出失败信息
2、⽅法⼀(Ajax响应头区分⽂本还是流)
2.1、后台
/**
* 根据sql导成csv;成功返回⽂件流,失败返回错误信息
* @param sql 导出sql
* @param col 字段信息,以逗号分隔
* @param title ⽂件头信息,以逗号分隔
* @param separator csv⽂件的分隔符
* @param baseServiceName
* @param request
* @param response
*/
@RequestMapping("exportForCsvStream")
@ResponseBody
public R<String> exportForCsvStream(String sql, String col, String title, String separator, String fileName, String baseServiceName, HttpServletRequest request, HttpServletResponse response) {
jquery下载文件请求
logger.info("sql={},title={},separator={},fileName={},baseServiceName={}", sql, title, separator, fileName, baseServiceName);
try {
if (StringUtils.isBlank(separator)) {
separator = ",";
}
if (StringUtils.isBlank(fileName)) {
fileName = "data.csv";
}
setResponse(fileName, request, response);
OutputStream os = new OutputStream(), BUFFER_SIZE);
//调⽤service把⽂件写⼊到输出流,请⾃⾏实现
os.close();
return null;
} catch(Exception e) {
e.printStackTrace();
response.setContentType("application/json");
response.setHeader("Content-Disposition", "");tomcat是中间件吗
(-1, "发⽣异常");
}
}
private void setResponse(String fileName, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
String urlFileName = "";
if (Header("User-Agent").toLowerCase().indexOf("firefox") > 0) {
urlFileName = new Bytes("UTF-8"), "ISO8859-1");
} else {
urlFileName = de(fileName, "UTF-8");
}
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + urlFileName + "\"");
response.setHeader("Connection", "close");
}
2.2、前台
2.2.1、拼接参数
function expForCsv() {
let sql = "";//请⾃⾏设置
let col = "";//请⾃⾏设置
let title = "";//请⾃⾏设置
let fileName = "";//请⾃⾏设置
$.messager.progress({title : '处理中...'});//easyui控件,可⽤其他控件
  let xhr = new XMLHttpRequest();
xhr.open("post", "${tPath}/common/export/exportForCsvStream.do", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    $.messager.progress('close');
if (ResponseHeader("Content-type") == 'application/octet-stream') {
let url = sponse);
let a = ateElement("a");
a.href = url;
a.style.display = 'none'
a.download = fileName;
a.click();
vokeObjectURL(url);
} else {
let reader = new FileReader();
reader.addEventListener('loadend', function (e) {
let data = JSON.parse(sult);
alert('提⽰', "系统出错,错误信息为:" + data.description + ",请将该信息提供给代维⼈员寻求帮助");
});
}
};
xhr.send('sql=' + sql + '&col=' + col + '&title=' + title + '&separator=|&t=' + new Date().getTime());
}
2.2.2、使⽤FormData
function expForCsv(type) {
let sql = "";//请⾃⾏设置
let col = "";//请⾃⾏设置
let title = "";//请⾃⾏设置
let fileName = ";//请⾃⾏设置
$.messager.progress({title : '处理中...'});//easyui控件,可⽤其他控件
let xhr = new XMLHttpRequest();
xhr.open("post", "${tPath}/common/export/exportForCsvStream.do", true);
//xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
$.messager.progress('close');
if (ResponseHeader("Content-type") == 'application/octet-stream') {
let url = sponse);
let a = ateElement("a");
a.href = url;
a.style.display = 'none'
a.download = fileName;
a.click();
vokeObjectURL(url);
} else {
let reader = new FileReader();
reader.addEventListener('loadend', function (e) {
let data = JSON.parse(sult);
alert('提⽰', "系统出错,错误信息为:" + data.description + ",请将该信息提供给代维⼈员寻求帮助");
});
}
};
let data = new FormData();
data.append('sql', getCsql(type));
data.append('col', col);
data.append('title', title);
data.append('separator', '|');
data.append('t', new Date().getTime() + "");
xhr.send(data);
}
3、⽅法⼆(两个接⼝)
3.1、后台
3.1.1、⽣成⽂件接⼝
/
**
* 根据sql导成csv;成功返回⽣成的⽂件名称,失败返回错误信息
* @param sql 导出sql
* @param col 字段信息,以逗号分隔
* @param title ⽂件头信息,以逗号分隔
* @param separator csv⽂件分隔符
* @param baseServiceName
* @return
*/
@RequestMapping("exportForCsv")
@ResponseBody
public CallResult<String> exportForCsv(String sql, String col, String title, String separator) {
logger.info("sql={}", sql);
logger.info("col={}", col);
logger.info("title={}", title);
logger.info("separator={}", separator);
logger.info("baseServiceName={}", baseServiceName);
OutputStream os = null;
CallResult<String> result = new CallResult<>();
try {
String fileName = "数据信息(" + CurrentDateString("yyyyMMddHHmmsss") + ").xlsx";
os = new FileOutputStream(new TempFolder() + "数据信息(" + CurrentDateString("yyyyMMddHHmmsss") + ").xlsx"));     
//调⽤service⽣成⽂件,请⾃⾏实现
getService().exportForCsv(os, sql, col, title, separator);
result.setResult(fileName);
} catch(Exception e) {
result = new CallResult<>(-1, "发⽣异常");
e.printStackTrace();
} finally {
FileUtil.close(os);
}
return result;
}
3.1.2、下载⽂件接⼝
/**
* 下载⽅法
* 1.点击页⾯下载,需传参数:
*        fileName:磁盘上⽂件的名称,必需
*        filePath或pathType或webPath:
*            ⽂件路径,传其中之⼀参数即可;
*            filePath是磁盘的绝对路径;
*            pathType是路径类型,对应webconfig.properties中的key
*            webPath是相对web应⽤的路径,如/spa
*        fileRealName:下载保存后的⽂件名称,可选;如果为空则与fileName⼀样
*
* 2.后台导出⽂件下载,需传属性:
*        fileName:磁盘上⽂件的名称,必需
pycharm激活码不能用*        fileRealName:下载保存后的⽂件名称,可选;如果为空则与fileName⼀样
*/
@RequestMapping("download")
public void download(HttpServletRequest request, HttpServletResponse response) {
String filePath = "";
String fileName = Parameter("fileName");
String fileRealName = "";
if (!Util.isNull(fileName)) {
filePath = Parameter("filePath");
if (Util.isNull(filePath)) {
String webPath = Parameter("webPath");
if (Util.isNull(webPath)) {
String pathType = Parameter("pathType");
filePath = Value(pathType);
} else {
//filePath = RealPath(webPath) + Property("file.separator");
filePath = ServletContext().getRealPath(webPath) + Property("file.separator");
}
}
fileRealName = Parameter("fileRealName");
} else {//后台导出⽂件下载
fileName = (String) Attribute("fileName");
filePath = TempFolder();
fileRealName = (String) Attribute("fileRealName");
}
if (Util.isNull(fileRealName)) {
fileRealName = fileName;
}
BufferedInputStream bis = null;
OutputStream out = null;
try {
String userInfoHeader = "User-Agent";
String firefoxName = "firefox";
String urlFileName = "";
if (Header(userInfoHeader).toLowerCase().indexOf(firefoxName) > 0) {
urlFileName = new Bytes("UTF-8"), "ISO8859-1");
} else {
urlFileName = de(fileRealName, "UTF-8");
}
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + urlFileName + "\"");
response.setHeader("Connection", "close");
bis = new BufferedInputStream(new FileInputStream(filePath + fileName), BUFFER_SIZE);
out = new OutputStream(), BUFFER_SIZE);
byte[] buf = new byte[BUFFER_SIZE];
int len;
while ((len = ad(buf)) != -1) {
out.write(buf, 0, len);
}web服务器没有对应的站点
} catch (Exception e) {
e.printStackTrace();
} finally {
FileUtil.close(bis);
FileUtil.close(out);
}
}
3.2、前台
function exp() {
let sql = "";//请⾃⾏设置
let col = "";//请⾃⾏设置
let title = "";//请⾃⾏设置
$.messager.progress({title : '处理中...'});//easyui控件,可⽤其他控件
$.getJSON(
"${tPath}/common/export/exportForCsv.do",
{
sql : sql,
col : col,
title : title,
separator: "|",
t : new Date().getTime()
},
function(data) {
$.messager.progress('close');//easyui控件,可⽤其他控件
if (urnCode == 0) {
location.href = "${tPath}/common/upDownload/download.do?fileName=" + sult) + "&fileRealName=" + encodeURI("数据.csv") + "&p.folder"            } else {
$.messager.alert('提⽰', "系统出错,错误信息为:" + data.description + ",请将该信息提供给代维⼈员寻求帮助");
}
}
);
}
3、公共类R
package ity;
/
**
* 返回数据
*/
public class R<T> {
/**
* 返回码
* 0 正常,其他异常
*/
private int returnCode = 0;
/**
* 描述
*/
private String description = "OK";
/**
* 结果数据
*/
private T result;
public int getReturnCode() {
return returnCode;
}
public String getDescription() {
return description;
}
public T getResult() {
return result;
}
public static R ok() {
return new R();
}
public static <T> R<T> ok(T result) {
R<T> r = new R<>();
return r;
}
public static <T> R<T> error() {
R<T> r = new R();
r.description = "未知异常,请联系管理员";
return r;
}
public static <T> R<T> error(String description) {
R<T> r = new R();
r.description = description;
return r;
}
public static <T> R<T> error(int returnCode, String description) {
R<T> r = new R();
滚动条长度css
r.description = description;
return r;
}
}
R.java
注意例⼦⾥sql是从台传到后台,这样容易引起SQL注⼊攻击;严谨的做法应该是前台传参数,后台拼sql,并使⽤PrepareStatement来执⾏sql。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。