在前端页面使用window.open只会自动跳转但不会自动下载的问题
项目场景:在最近一直忙着做毕设,跟着b站程序员青戈敲代码,视频里面使用window.open(url)
可以正常制动下载,但是到我这里就却发现只是打开页面但不能自动下载。
问题描述
在后端使用hutool工具准备好了一个Excel导出接口
@GetMapping("/export")
public void exportExcel(HttpServletResponse response) throws IOException {
// 从数据库查询出所有的数据
List<User> list = userLogin.list();
// 通过工具类创建writer 写出到磁盘路径
// ExcelWriter writer = ExcelUtil.getWriter(filesUploadPath + "/用户信息.xlsx");
// 在内存操作,写出到浏览器
ExcelWriter writer = ExcelUtil.getWriter(true);
// 一次性写出list内的对象到excel,使用默认样式,强制输出标题
writer.write(list, true);
// 设置浏览器响应的格式
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
String fileName = URLEncoder.encode("用户信息", "UTF-8");
// 在controller层中的二进制流文件下载方法下配置放行属性:
response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
ServletOutputStream out = response.getOutputStream();
writer.flush(out, true);
out.close();
writer.close();
}
前段vue代码
//前端模版
<template>
<el-button type="primary" @click="handleExportExcel">导出 <i class="el-icon-top"></i></el-button>
</template>
//js控制逻辑
handleExportExcel() {
window.open(url)
this.load();
}
原因分析:
结果页面不能自动跳转,查了一下原因是因为协议的问题,把http改成https就成功了,Chrome这些浏览器不允许不安全的下载行行为自动下载,htttp协议是不安全的。但是我们开发一般都用http做测试,这个问题的解决办法可以采用如下方法。原文在这
解决方案:
// 以之前的post请求举例
axios.post(url, {...someparams}, {responseType: 'blob'})
.then((res) => {
const { data, headers } = res
//要在后端响应体自行设置content-disposition属性,否则可能无法获取到文件名,导致无法下载。(ps嫌麻烦直接删除这个步骤)
const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
// 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
//const blob = new Blob([JSON.stringify(data)], ...)
const blob = new Blob([data], {type: headers['content-type']})
let dom = document.createElement('a')
let url = window.URL.createObjectURL(blob)
dom.href = url
dom.download = decodeURI(fileName)
dom.style.display = 'none'
document.body.appendChild(dom)
dom.click()
dom.parentNode.removeChild(dom)
window.URL.revokeObjectURL(url)
}).catch((err) => {})
本质借助生成虚拟dom的方法,通过调用a标签上的属性触发事件,完成下载。
附:hutool工具下如何导入导出文件
导入pom依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
编写实体类
//开启了swagger配置
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("sh_user")
@ToString
public class User {
@Alias("用户ID")//一定要设置导出导入的别名,否则会将数据库中的英文列名导出
@ApiModelProperty("用户ID")
@TableId(type=IdType.AUTO)
private Integer id;
@ApiModelProperty("账户号码")
@Alias("账户号码")
private String accountNumber;
@JsonIgnore
@Alias("用户密码")
private String userPassword;
@ApiModelProperty("用户头像路径")
@Alias("用户头像路径")
private String avatar;
@ApiModelProperty("用户状态")
@Alias("用户状态")
private Integer userStatus;
@ApiModelProperty("昵称")
@Alias("昵称")
private String nickname;
@Alias("注册时间")
@ApiModelProperty("注册时间")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date signInTime;
}
编写mapper和service时,由于业务逻辑不负责,直接在controller中写逻辑
//导入代码
@PostMapping("/import")
public void importExcel(MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
ExcelReader reader = ExcelUtil.getReader(inputStream);
List<User> list = reader.readAll(User.class);
userLogin.saveBatch(list);
}
//导出代码上面已经有,所以不在重复
前端页面
<el-upload
style="display: inline-block;padding:5px"
class="upload-demo"
:show-file-list="false"
action="http://localhost:8081/user/import" accept="xlsx"
:on-success="handleExcelImportSuccess"
:on-error="handleExcelImportError">
<el-button type="primary">点击上传<i class="el-icon-bottom"></i></el-button>
</el-upload>
//js
//处理导入成功和失败对应的事件
handleExcelImportSuccess(){
this.$message.success("导入成功")
this.load()
},
handleExcelImportError(){
this.$message.success("导入失败!文件不合格");
}
总结
至此代码业务逻辑完毕,算做一个小小的学习经验吧!