1、vue代码
<template>
<el-button slot="append" @click="Down()">测试下载</el-button>
</template>
<script>
import {doGetBlob} from "@/api/httpRequest";
export default {
name: "downView",
data() {
},
created() {
},
methods: {
Down() {
doGetBlob("/down/eFile?id=1").then(response => {
const fileName = decodeURI(response.headers['content-disposition'].split('=')[1]);
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
}).catch(err => {
console.log("异常" + err);
console.log(err);
})
}
}
}
</script>
<style scoped>
</style>
2、doGetBlob代码
import axios from "axios";
axios.defaults.baseURL = "http://127.0.0.1:8008";
axios.defaults.timeout = 30000
/**
* 封装get请求
* @param url
*/
function doGet(url, params) {
return axios({
url: url,
method: 'get',
params: params,
withCredentials: true
});
}
function doGetBlob(url){
return axios({
method:'get',
url: url,
responseType:'blob',
withCredentials: true
})
}
export {doGetBlob, doGet};
3、后端下载接口(使用easyExcel创建的excel文件)
@RestController
@RequestMapping("/down")
public class DownController {
@RequestMapping("eFile")
public void downEFile(int id, HttpServletResponse response) {
try {
String fileName = "";
if (id>0){
fileName = "文件1.xlsx";
}else {
fileName = "文件2.xlsx";
}
List<Book> list = new ArrayList<>();
Book book = new Book();
book.setBookName("语文");
BigDecimal abp = new BigDecimal(10.0);
book.setBookPrice(abp);
list.add(book);
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
OutputStream out = response.getOutputStream();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
ExcelWriter excelWriter = EasyExcelFactory.write(out).build();
EasyExcel.write(response.getOutputStream(), Book.class)
.sheet("sheet")
.doWrite(list);
excelWriter.finish();
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、其中的Book类
@TableName("book")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
@TableId
private Integer bookId;
private String bookName;
private BigDecimal bookPrice;
private Date bookCreateTime;
private Date createTime;
private Date updateTime;
private String updateUserId;
}
5、一定要注意设置响应头允许携带Content-Disposition(否则axios请求中获取不到文件名称)
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
//设置允许Cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
//跨域请求,*代表允许全部类型
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
//用来指定本次预检请求的有效期,单位为秒,在此期间不用发出另一条预检请求
response.setHeader("Access-Control-Max-Age", "3600");
//请求包含的字段内容,如有多个可用哪个逗号分隔如下
response.setHeader("Access-Control-Allow-Headers", "uid,Authorization,content-type,x-requested-with,Authorization, x-ui-request,lang");
//访问控制允许凭据,true为允许
response.setHeader("Access-Control-Allow-Credentials", "true");
// 浏览器是会先发一次options请求,如果请求通过,则继续发送正式的post请求,配置options的请求返回
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(200);
response.getWriter().write("OPTIONS returns OK");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
6、至此完成