SpringBoot之结合前端axios及其他多种方式下载文件
1. 后端
以spring boot工程为例进行文件下载
1. 文件下载工具类
package ***.yuan.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.***mons.io.FileUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.***.URLEncoder;
/**
* @Description: 文件操作工具类
* @Author: 袁金生
* @CreateTime: 2022-11-15 14:56
* @LastEditors: 袁金生
* @LastEditTime: 2022-11-15 14:56
*/
@Slf4j
public class FileUtil {
/**
* 文件下载
*
* @param response 响应对象
* @param fileName 文件全名
* @param filePath 文件路径(路径+文件名)
*/
public final static void fileDownload(HttpServletResponse response, String fileName, String filePath) {
OutputStream outputStream = null;
try {
File saveFile = new File(filePath);
if (saveFile.exists()) {
//设置返回类型
response.setContentType("application/octet-stream");
//对文件名称进行编码,解决文件名称中中文乱码问题
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//获取文件输入流字节数组,这里使用的是org.apache.***mons.io.FileUtil工具类
byte[] byteArray = FileUtils.readFileToByteArray(saveFile);
//输入流转输出流返回给客户端
outputStream = new BufferedOutputStream(response.getOutputStream());
if (byteArray != null && byteArray.length > 0) {
outputStream.write(byteArray);
}
} else {
//设置头信息
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write("[" + fileName + "]文件不存在!");
log.warn("[{}]文件不存在!", fileName);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
log.info("下载完成:{}", fileName);
}
}
2. 文件下载controller
package ***.yuan.wechat.controller;
import ***.yuan.utils.ApiResult;
import ***.yuan.utils.FileUtil;
import org.apache.***mons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
/**
* <p>
* 通用跳转前端控制器
* </p>
*
* @author 袁金生
* @since 2022-11-02
*/
@RestController
@RequestMapping("/wechat")
public class ***monController {
/**
* 通用跳转
*
* @param pageName
* @return
*/
@RequestMapping("/toPage")
public ModelAndView toPage(@RequestParam String pageName) {
return new ModelAndView(pageName);
}
@GetMapping("/downloadReport")
public Object downloadReport(@RequestParam("reportName") String reportName, @RequestParam("reportPath") String reportPath, HttpServletResponse response) {
if (StringUtils.isBlank(reportName) || StringUtils.isBlank(reportPath)) {
return ApiResult.error("报告名或报告路径不能为空");
}
String diskFilePath = reportPath + reportName;
FileUtil.fileDownload(response, reportName, diskFilePath);
return null;
}
}
2. 前端多种方式下载
1. 下载方式1(a标签)
const downloadReport = (reportName, reportPath) => {
console.log("下载报告reportName===1》", reportName)
console.log("下载报告reportPath===1》", reportPath)
reportName = "Java开发手册(黄山版).pdf";
reportPath = "D:/aa/files/"
/* const url = ctxPath + '/wechat/downloadReport?reportName='+reportName+'&reportPath='+reportPath
let link = document.createElement('a');
link.href = url
//link.download = item.fileName || '下载文件';//下载后文件名
document.body.appendChild(link);
link.click();//点击下载
link.remove();//下载完成移除元素
window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放;*/
// 上述请求也可以按以下方式完成(可选)
axios.get(ctxPath + '/wechat/downloadReport', {
params: {
reportName,
reportPath
},
responseType: 'blob',//响应类型为流
onDownloadProgress: (ProgressEvent) => {//用来计算下载量(实际项目中可以用来显示下载进度)
let total = item.fileLength;
console.log(total);
let load = ProgressEvent.loaded;
console.log(load);
}
}).then(function (resp) {
console.log("resp",resp);
if (resp) {
let blob = new Blob([resp]);//处理文档流
let url = window.URL.createObjectURL(blob);
let link = document.createElement('a');
link.href = url
link.download = reportName || '下载文件';//下载后文件名
document.body.appendChild(link);
link.click();//点击下载
link.remove();//下载完成移除元素
window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放;
} else {
console.error('文件下载失败,请重试!');
}
}).catch(function (error) {
console.log(error);
}).finally(() => {
//请求结束回调
})
// http://localhost:7001/lims/wechat/toPage?pageName=wechat/tabbar
//window.location.href = ctxPath + "wechat/toPage?pageName=wechat/pdfView";
};
2. 下载方式2(window.location.href)
const downloadReport = (reportName, reportPath) => {
console.log("下载报告reportName===1》", reportName)
console.log("下载报告reportPath===1》", reportPath)
reportName = "Java开发手册(黄山版).pdf";
reportPath = "D:/aa/files/"
window.location.href = ctxPath + '/wechat/downloadReport?reportName='+reportName+'&reportPath='+reportPath
};
3. 下载方式3(axios)
- 案例1,文件名从响应对象中获取
const downloadReport = () => {
axios(ctxPath + '/generator/genCloudCode', {
method: 'post', // 默认值get
data: {...cloudForm},
//更多配置查看官网 https://www.axios-http.***/docs/req_config
responseType: 'blob',//表示浏览器将要响应的数据类型(默认json),选项包括 'arraybuffer', 'document', 'json', 'text', 'stream';浏览器专属:'blob'
headers: {'Content-Type': 'application/json; application/octet-stream'},
onDownloadProgress: (ProgressEvent) => {//用来计算下载量(实际项目中可以用来显示下载进度)
let load = ProgressEvent.loaded;
console.log(load);
}
}).then(function (resp) {
console.log("resp", resp);
//响应回来后其实还是使用的a标签进行下载的
if (resp) {
//从响应对象中获取头信息,content-disposition包含了服务端返回的文件名
let header = resp.headers['content-disposition'];
const fileName = decodeURI(header.substring(header.indexOf("=") + 1));
console.log("header",header)
console.log("fileName",fileName)
let blob = new Blob([resp.data], {type: resp.headers['content-type']});//type指定响应的ContentType,这里从响应头中获取
let url = window.URL.createObjectURL(blob);
let link = document.createElement('a');
link.href = url
link.download = fileName || '下载文件';//下载后文件名
document.body.appendChild(link);
link.click();//点击下载
link.remove();//下载完成移除元素
window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放;
} else {
console.error('文件下载失败,请重试!');
}
}).catch(function (error) {
console.log(error);
}).finally(() => {
//请求结束回调
})
};
- 案例2,文件名自定义
const downloadReport = (reportName, reportPath) => {
console.log("下载报告reportName===1》", reportName)
console.log("下载报告reportPath===1》", reportPath)
reportName = "Java开发手册(黄山版).pdf";
reportPath = "D:/aa/files/"
axios.get(ctxPath + '/wechat/downloadReport', {
params: {
reportName,
reportPath
},
responseType: 'blob',//响应类型为流,这里可以指定为blob或arraybuffer
onDownloadProgress: (ProgressEvent) => {//用来计算下载量(实际项目中可以用来显示下载进度)
let load = ProgressEvent.loaded;
console.log(load);
}
}).then(function (resp) {
console.log("resp",resp);
//响应回来后其实还是使用的a标签进行下载的
if (resp) {
let blob = new Blob([resp.data]);
let url = window.URL.createObjectURL(blob);
let link = document.createElement('a');
link.href = url
link.download = reportName || '下载文件';//下载后文件名
document.body.appendChild(link);
link.click();//点击下载
link.remove();//下载完成移除元素
window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放;
} else {
console.error('文件下载失败,请重试!');
}
}).catch(function (error) {
console.log(error);
}).finally(() => {
//请求结束回调
})
};
4. 使用fileDownload插件
fileDownload插件git地址:FileDownload
const downloadReport = (reportName, reportPath) => {
console.log("下载报告reportName===1》", reportName)
console.log("下载报告reportPath===1》", reportPath)
reportName = "Java开发手册(黄山版).pdf";
reportPath = "D:/aa/files/"
axios.get(ctxPath + '/wechat/downloadReport', {
params: {
reportName,
reportPath
},
responseType: 'blob',
}).then(res => {
fileDownload(res.data, reportName);
});
};