Vue实现点击按钮进行文件下载(后端Java)
最近项目中需要实现点击按钮下载文件的需求,前端用的vue,因为文件是各种类型的,比如图片、pdf、word之类的。这里后端是可以返回文件的地址给前端的,但我看了下网上各种五花八门的答案,感觉都不是我想要的。
因为不确定文件是哪种类型的,所以我们在保存文件到数据库的时候,应该把文件的Content-Type一起存入,这样从数据库取出返回前端的时候,带上Content-Type标识是哪种类型的文件,前端解析即可。
1、后端代码
这里我先写后端的接口,考虑一下后端需要什么东西。因为文件信息已经提前存入数据库,所以我们只需要传入主键id就可以拿到文件的信息。确定参数后,就需要确定一下返回值类型。这里可以使用ResponseEntity返回。ResponseEntity可以一次返回多个信息,包括状态码,响应头信息,响应内容等。
话不多说,看代码。
/**
* 下载附件
* @param attachmentId
* @return
*/
public ResponseEntity<byte[]> download(Long attachmentId) {
// 查询附件是否存在
SysAttachment sysAttachment = sysAttachmentMapper.selectSysAttachmentById(attachmentId);
if (StringUtils.isNull(sysAttachment)) {
return null;
}
ByteArrayOutputStream bos = null;
InputStream ins = null;
try {
String fileName = sysAttachment.getOrgFileName();
String ossFileName = sysAttachment.getUrl();
bos = new ByteArrayOutputStream();
ins = OssUtils.getInstance().getObject(ossFileName).getObjectContent();
// 取流中的数据
int len = 0;
byte[] buf = new byte[256];
while ((len = ins.read(buf, 0, 256)) > -1) {
bos.write(buf, 0, len);
}
// 防止中文乱码
fileName = URLEncoder.encode(fileName, "utf-8");
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=" + fileName);
headers.add("Content-Type", sysAttachment.getContentType());
// 设置响应吗
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(bos.toByteArray(), headers, statusCode);
return response;
} catch (Exception e) {
throw new CustomException("下载失败");
} finally {
try {
if (ins != null) {
ins.close();
}
if (bos != null) {
bos.close();
}
} catch (Exception e) {
throw new CustomException("下载失败");
}
}
}
这里我们从数据库拿出文件的url后,再通过阿里云oss拿到文件的输入流,接着把文件输出为二进制,封装到ResponseEntity中,并把文件的类型设置到Content-Type中,同时为了防止文件名带有中文名乱码,设置utf-8编码,至此后端接口完成。
通过上面的信息,我们在数据库保存文件信息时,至少应该保存下面几个字段:文件的url(一般在上传到oss后会给你一个)、文件的类型、原始文件名、文件大小等。
2、前端代码
有了后端接口,接下来就是前端了。这里可以把文件下载的方法封装成一个通用方法全局挂载,之后需要使用的地方直接使用即可。
我们需要标识不同的文件,所以我们需要一个键值对表示不同的文件。
const mimeMap = {
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xls: 'application/vnd.ms-excel',
zip: 'application/zip',
jpg: 'image/jpg',
jpeg: 'image/jpeg',
png: 'image/png',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
ppt: 'application/vnd.ms-powerpoint',
txt: 'text/plain',
pdf: 'application/pdf'
}
有需要的可以继续补充。接下来自然就是发请求了,这里的返回类型可以设置为blob,使用axios直接发送
/**
* 下载附件
* @param path 接口地址
* @param param 请求参数
*/
export function downloadAttachment(path, param) {
var url = baseUrl + path + param
axios({
method: 'get',
url: url,
responseType: 'blob',
headers: { 'Authorization': getToken() }
}).then(res => {
resolveBlob(res, res.data.type)
})
}
接口地址和请求参数从外部传入。同时需要携带token,不然会跨域访问。拿到后端返回的数据后,需要解析二进制文件,这里定义resolveBlob方法,该方法有两个参数,返回对象和文件的类型,文件的类型,我们在后端已经放入Content-Type中了,这里直接取。
/**
* 解析blob响应内容并下载
* @param {*} res blob响应内容
* @param {String} mimeType MIME类型
*/
export function resolveBlob(res, mimeType) {
const aLink = document.createElement('a')
var blob = new Blob([res.data], { type: mimeType })
// 从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
var contentDisposition = decodeURI(res.headers['content-disposition'])
var result = patt.exec(contentDisposition)
var fileName = result[1]
fileName = fileName.replace(/\"/g, '')
aLink.href = URL.createObjectURL(blob)
aLink.setAttribute('download', fileName) // 设置下载文件名称
document.body.appendChild(aLink)
aLink.click()
document.body.removeChild(aLink);
}
这代码不用多解释了吧,前端大佬们自然看得懂。OK了啊,到这里前后端代码都完成了。
3、使用
使用那就更简单啦。先挂载到全局
import { downloadAttachment } from "@/utils/download"
Vue.prototype.downloadAttac = downloadAttachment
在使用的地方直接调用即可
<el-button
type="text"
icon="el-icon-download"
size="mini"
@click="downloadAttachRow(scope.row.attachmentId)"
></el-button>
/** 下载附件 */
downloadAttachRow(attachId) {
this.$confirm('是否确认下载该文件?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.downloadAttac('/system/attachment/download/', attachId)
}).then(() => {
this.msgSuccess("下载成功")
}).catch(() => {})
}
到此结束。如果过程中遇到什么问题,可以在下方留言,我会回复的。
觉得好的可以帮忙点个赞啊,也可以关注我的公众号【秃头哥编程】
Vue实现点击按钮进行文件下载(后端Java)的更多相关文章
- vue 如何点击按钮返回上一页
1,vue 如何点击按钮返回上一页呢? 这是vue挂载的范围html代码 <div @click="goOff()">返回</div> 下面是点击返回的方法 ...
- vue+element 点击按钮后 导致 刷新页面 致url中拼接 ? 或者拼接参数
https://blog.csdn.net/sinat_37255207/article/details/88917162 element 自己的<el-form></el-form ...
- webapp项目vue框架点击按钮实现微信好友分享,朋友圈分享
当时做这个这个效果真把人给*了,网上能搜到的基本是微信页面的分享,特征是方法是wx.**开头,不适用于app内.思路都是一样的,先调取服务(这里使用plus的内置方法),再发送分享请求 <tem ...
- 解决关于 vue项目中 点击按钮路由多了个问号
问题描述: 在vue项目开发过程中,点击按钮结果页面刷新了一遍 后来发现路径变成了 localhost:8080/?#/login 原因: 这里是 form 表单,点击了button 按钮,触发了他的 ...
- vue踩坑之路--点击按钮改变div样式
有时候,我们在做项目的时候,想通过某个按钮来改变某个div样式,那么可以通过以下代码实现: <!DOCTYPE html> <html> <head> <me ...
- 21、解决关于 vue项目中 点击按钮路由多了个问号
在vue项目开发过程中,点击按钮结果页面刷新了一遍 后来发现路径变成了 localhost:8080/?#/login 原因: 这里是 form 表单,点击了button 按钮,触发了他的默认事件,就 ...
- 微信公众号使用vue,安卓端点击按钮404,ios访问正常问题
情景:微信公众号使用vue开发的单页面,在安卓端点击按钮访问显示404,ios访问正常问题,能正常显示. 解决:将微信公众号菜单按钮设置的路径中把WWW去掉后,安卓.ios都能正常访问. 问题路径ww ...
- vue自己写了一个div菜单,点击按钮展开,点击其他地方关闭这个div菜单
需求是通过点击body页面,在其他地方就关闭这个<div>菜单,给这个div一个id:problemList,但是点击我打开的按钮,不关闭. created () { document.o ...
- vue+element下拉框样式的点击按钮
项目中点击按钮实在太多了,怎么办呢?我们就可以将它们制作成像下拉框那样的类似操作 1.HTML样式部分:关键点在于command 方法和属性 1 <el-dropdown 2 size=&quo ...
随机推荐
- hdu 2159 二维完全背包
Problem Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级.现 ...
- Java:Java的<<<移位运算符详解
1) 左移运算(<<) 左移就是把所有位向左移动几位 如: 12 << 2 意思就是12向左移动两位 12的二进制是: 0000 1100 通过这个图我们 ...
- Android常用开源库(转)
一 .基本控件 TextView HTextView 一款支持TextView文字动画效果的Android组件库. ScrollNumber 滚动数字控件 ticker 滚动数字控件 ReadMore ...
- 物理机连接虚拟机中的数据库及Windows添加防火墙允许端口详细操作步骤
公司项目中因为会使用到SQL server数据库,但是自己电脑无论安装2008R2或者2014版本都不成功,我想可能是和之前安装的一些Windows的软件存在冲突. 于是便单独创建了一台虚拟机,在虚拟 ...
- 关闭火狐浏览器中的Pocket功能
在火狐(Firefox)浏览器中,默认右键菜单和菜单栏都会有 Pocket按钮 .但是大部分国内用户都不会使用Pocket服务,看着还十分碍眼. 在工具栏的图标还可以通过定制工具栏修改,但是右键菜单中 ...
- WIN10技巧
1.快速打开"开始---自动启动"文件夹:开始--支行--shell:startup 2
- SyntaxError: unexpected EOF while parsing成功解决
报错在eval()函数: 我加了个 if 判断是否为空,就可以正常运行了!
- 家庭账本开发day11
编写登录界面和个人信息查看界面 $.ajax({ url: "UserServlet?method=login",//url ...
- Collection集合工具类
Ⅷ.Collections 工具类 java.util.Collections Collections 集合工具类,用来对集合进行操作,部分重要方法如下: 1.public static <T& ...
- 如何热更新长缓存的 HTTP 资源
前言 HTTP 缓存时间一直让开发者头疼.时间太短,性能不够好:时间太长,更新不及时.当遇到严重问题需紧急修复时,尽管后端文件可快速替换,但前端文件仍从本地缓存加载,导致更新长时间无法生效. 对于这个 ...