上篇文章给大家介绍过,今天继续vue点击按钮下载文件的话题。

最近项目中需要实现点击按钮下载文件的需求,前端用的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点击按钮下载文件内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!