需求
之前實(shí)現(xiàn)的導(dǎo)出都是各自的業(yè)務(wù)層,調(diào)用接口,使用blob對象轉(zhuǎn)換,最終a標(biāo)簽導(dǎo)出,需要自定義文件名跟文件后綴。
現(xiàn)在統(tǒng)一在攔截器配置,根據(jù)后端返回的response.headers解析是否是文件流,統(tǒng)一做配置處理,然后對后端返回的filename進(jìn)行轉(zhuǎn)碼,后端統(tǒng)一配置文件名及類型。前端只管a標(biāo)簽下載即可。
以往實(shí)現(xiàn)的方法(各自的業(yè)務(wù)層寫方法)
//數(shù)據(jù)導(dǎo)出
indexExport() {
let statYear = {
statDate: this.form.statDate,
dataType: "1",
};
let infoMsg = this.$notify.info({
title: "消息",
message: "正在下載文件,勿退出,請稍后",
duration: 0,
});
gljyjcDataExport(statYear).then((res) => {
infoMsg.close(); //下載成功,等待下載提示框關(guān)閉
this.$notify({
title: "成功",
message: "下載完成",
type: "success",
});
let blob = new Blob([res], {
type: "",
});
let url = window.URL.createObjectURL(blob);
const link = document.createElement("a"); // 創(chuàng)建a標(biāo)簽
link.href = url;
link.download = "數(shù)據(jù)清單(" + this.form.statDate + ").xlsx"; // 重命名文件
link.click();
URL.revokeObjectURL(url); // 釋放內(nèi)存
});
},
現(xiàn)在實(shí)現(xiàn)的方法(axios里攔截器統(tǒng)一配置處理)
主要看注釋行“文件下載”,因?yàn)楹蠖朔祷亓魑募r候攜帶的response.headers會多Content-Disposition這個字段。然后拿到里邊的filename后,對filename包含的信息進(jìn)行轉(zhuǎn)碼就可
decodeURIComponent、decodeURI都可進(jìn)行轉(zhuǎn)碼,具體二者有啥區(qū)別,水平有限沒大看懂,可自行百度查閱符合選項(xiàng)
//攔截器里肯定有請求攔截代碼axios.interceptors.request。怕展示代碼冗余就不多貼了
...
axios.interceptors.response.use(
response => {
const res = response.data;
const config = response.config;
console.log(response.headers,"response.headers")//這塊可以看一下response.headers究竟是什么
// 文件下載(主要看這塊)
if (response.headers['content-disposition']) {
let downLoadMark = response.headers['content-disposition'].split(';');
if (downLoadMark[0] === 'attachment') {
// 執(zhí)行下載
let fileName = downLoadMark[1].split('filename=')[1];
if (fileName) {
//fileName = decodeURIComponent(filename);//對filename進(jìn)行轉(zhuǎn)碼
fileName = decodeURI(fileName);
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(new Blob([res]), fileName);
} else {
let url = window.URL.createObjectURL(new Blob([res]));
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
return;
}
} else {
return res;
}
}
}
// 全局異常處理(獲取code做正常的攔截操作,根據(jù)自己的業(yè)務(wù)層code寫符合的就可)
if (res.code !== CODE_SUCCESS) {
if (res.code == '205') {
Message.error({ message: res.data || "登錄失敗" });
store.dispatch("user/logout").then(() => {
window.location.reload();
});
return
}
if (res.code === WARN_TIP) {
Message.warning({
message: res.message
});
}
if (res.code === LOGIN_FAIL) {
Message.error({ message: res.message || "登錄失敗" });
}
// 其他狀態(tài)碼特殊處理
return Promise.reject(new Error(res.message || "Error"));
}
return res;
}, error => {
// 防重復(fù)提交
if (error.message) {
allowRequest(reqList, error.message.url);
}
if (error.response) {
if (error.response.data.code == 600 && !tipCode) {
tipCode = true;
Message.error({ message: '系統(tǒng)登錄身份令牌失效,請重新登錄!' });
} else if (error.response.status == 500) {
Message.error({ message: '系統(tǒng)異常' });
}
}
return Promise.reject(error);
}
);
以上是未解析之前瀏覽器看到的文件夾名
經(jīng)過decodeURIComponent或decodeURI解析后,前端就能獲取到后端返回的中文文件名了。
把文章鏈接復(fù)制粘貼給后端,讓大佬自己賞閱。
截止目前,前端能干的活就到此為止了。
那么有人就想問了,那后端response.headers里沒返回我想要的Content-Disposition,前端怎么捕獲。
對此呢,我又找我們后端大佬要了一下后端實(shí)現(xiàn)的代碼,我就原封不動貼出來了,因?yàn)槲腋究床欢f的是什么意思文章來源:http://www.zghlxwxcb.cn/news/detail-660395.html
Controller端代碼(啥是Controller,根本不懂)
@PostMapping(value="/exportAddresses")
public Result exportAddresses(HttpServletResponse response){
String[] titles = new String[] {"id","tableCode","columnName"};
List<Map<String,Object>> objList = new ArrayList<>();
DownLoadFileController addressService;
List<NpColumns> npColumnsList = npColumnsService.findByTableCode("APP_TASK_CASE_INFO");
for(NpColumns item : npColumnsList){
Map<String,Object> tempMap = new HashMap<>();
tempMap.put("id", item.getId());
tempMap.put("tableCode", item.getTableCode());
tempMap.put("columnName", item.getColumnName());
objList.add(tempMap);
}
try {
FileUtils.exportExcel(response,"地址樹",titles,objList);
return ResultGenerator.genSuccessResult("導(dǎo)出成功!");
}catch (Exception e){
e.printStackTrace();
return ResultGenerator.genFailResult("導(dǎo)出失??!");
}
}
工具類方法(啥是工具類,也不懂)
public static void exportExcel(HttpServletResponse response,String fileName,String[] titles,List<Map<String,Object>> result){
HSSFWorkbook wb;
OutputStream output = null;
String tempName = fileName;
try {
Date date = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
fileName +="_"+df.format(date)+".xls";
String encodedFilename = URLEncoder.encode(fileName, "UTF-8");
wb= new HSSFWorkbook();
HSSFSheet sh = wb.createSheet();
// 設(shè)置列寬
for(int i = 0; i < titles.length-1; i++){
sh.setColumnWidth( i, 256*15+184);
}
// 第一行表頭標(biāo)題,CellRangeAddress 參數(shù):行 ,行, 列,列
HSSFRow row = sh.createRow(0);
HSSFCell cell = row.createCell(0);
cell.setCellValue(new HSSFRichTextString(tempName));
//cell.setCellStyle(fontStyle(wb));
sh.addMergedRegion(new CellRangeAddress(0, 0, 0,titles.length-1));
// 第二行
HSSFRow row3 = sh.createRow(1);
// 第二行的列
for(int i=0; i < titles.length; i++){
cell = row3.createCell(i);
cell.setCellValue(new HSSFRichTextString(titles[i]));
//cell.setCellStyle(fontStyle(wb));
}
//填充數(shù)據(jù)的內(nèi)容 i表示行,z表示數(shù)據(jù)庫某表的數(shù)據(jù)大小,這里使用它作為遍歷條件
int i = 2, z = 0;
while (z < result.size()) {
row = sh.createRow(i);
Map<String,Object> map = result.get(z);
for(int j=0;j < titles.length;j++) {
cell = row.createCell(j);
if(map.get(titles[j]) !=null) {
cell.setCellValue(map.get(titles[j]).toString());
}else {
cell.setCellValue("");
}
}
i++;
z++;
}
output = response.getOutputStream();
response.reset();
response.addHeader("Content-Type","application/octet-stream;charset=utf-8");
response.setHeader("Content-disposition", "attachment; filename="+encodedFilename);
response.setContentType("application/msexcel");
wb.write(output);
output.flush();
output.close();
}catch (Exception e){
e.printStackTrace();
}
}
最后還有個中文處理亂碼那塊(這都是啥啥啥,還是不懂)
String encodedFilename = URLEncoder.encode(fileName, "UTF-8");設(shè)置文件名的中文編碼
response.addHeader("Content-Type","application/octet-stream;charset=utf-8");//這里也設(shè)置了相同的編碼格式
response.setHeader("Content-disposition", "attachment; filename="+encodedFilename);
大家有更好的實(shí)現(xiàn)方案話歡迎多交流文章來源地址http://www.zghlxwxcb.cn/news/detail-660395.html
到了這里,關(guān)于vue導(dǎo)出文件流獲取附件名稱并下載(在response.headers里解析filename導(dǎo)出)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!