最近項目中需要實現點擊按鈕下載文件的需求,前端用的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)的更多相關文章

  1. vue 如何點擊按鈕返回上一頁

    1,vue 如何點擊按鈕返回上一頁呢? 這是vue掛載的範圍html代碼 <div @click="goOff()">返回</div> 下面是點擊返回的方法 ...

  2. vue+element 點擊按鈕後 導致 刷新頁面 致url中拼接 ? 或者拼接參數

    https://blog.csdn.net/sinat_37255207/article/details/88917162 element 自己的<el-form></el-form ...

  3. webapp項目vue框架點擊按鈕實現微信好友分享,朋友圈分享

    當時做這個這個效果真把人給*了,網上能搜到的基本是微信頁面的分享,特征是方法是wx.**開頭,不適用於app內.思路都是一樣的,先調取服務(這裏使用plus的內置方法),再發送分享請求 <tem ...

  4. 解决關於 vue項目中 點擊按鈕路由多了個問號

    問題描述: 在vue項目開發過程中,點擊按鈕結果頁面刷新了一遍 後來發現路徑變成了 localhost:8080/?#/login 原因: 這裏是 form 錶單,點擊了button 按鈕,觸發了他的 ...

  5. vue踩坑之路--點擊按鈕改變div樣式

    有時候,我們在做項目的時候,想通過某個按鈕來改變某個div樣式,那麼可以通過以下代碼實現: <!DOCTYPE html> <html> <head> <me ...

  6. 21、解决關於 vue項目中 點擊按鈕路由多了個問號

    在vue項目開發過程中,點擊按鈕結果頁面刷新了一遍 後來發現路徑變成了 localhost:8080/?#/login 原因: 這裏是 form 錶單,點擊了button 按鈕,觸發了他的默認事件,就 ...

  7. 微信公眾號使用vue,安卓端點擊按鈕404,ios訪問正常問題

    情景:微信公眾號使用vue開發的單頁面,在安卓端點擊按鈕訪問顯示404,ios訪問正常問題,能正常顯示. 解决:將微信公眾號菜單按鈕設置的路徑中把WWW去掉後,安卓.ios都能正常訪問. 問題路徑ww ...

  8. vue自己寫了一個div菜單,點擊按鈕展開,點擊其他地方關閉這個div菜單

    需求是通過點擊body頁面,在其他地方就關閉這個<div>菜單,給這個div一個id:problemList,但是點擊我打開的按鈕,不關閉. created () { document.o ...

  9. vue+element下拉框樣式的點擊按鈕

    項目中點擊按鈕實在太多了,怎麼辦呢?我們就可以將它們制作成像下拉框那樣的類似操作 1.HTML樣式部分:關鍵點在於command 方法和屬性 1 <el-dropdown 2 size=&quo ...

  10. 使用js實現點擊按鈕下載文件

    有時候我們在網頁上需要增加一個下載按鈕,讓用戶能够點擊後下載頁面上的資料,那麼怎樣才能實現功能呢?這裏有兩種方法: 現在需要在頁面上添加一個下載按鈕,點擊按鈕下載文件. 題外話,這個下載圖標是引用的 ...

隨機推薦

  1. iOS工作筆記(十四)

    1.scrollview的frame指的是其可視範圍,contentSize指的是其滾動範圍,分別是在水平方向和豎直方向上的 所以要讓scrollview在水平方向不能滾動,那麼需要如下設置 _scr ...

  2. C#性能優化的一些技巧

    博客搬到了fresky.github.io - Dawei XU,請各比特看官挪步.最新的一篇是:C#性能優化的一些技巧.

  3. POJ 3277 City Horizon

    標題效果: 每間房子的長度給出陰影(在間隔代錶)而高度,求陰影總面積. 解題思路:矩形面積並. 以下是代碼: #include <set> #include <map> #in ...

  4. java基礎之操作符

    一:賦值 1.對基本數據類型的賦值,int a=b:   //把b的值複制給a,如果修改了a的值,b 的值不會受到影響. 2.對引用類型的賦值, public class Text { public ...

  5. dropzone.js使用實踐

    官網地址:http://www.dropzonejs.com/ 一,它是什麼: DropzoneJS is an open source library that provides drag'n'dr ...

  6. Node.js 8 中的 util.promisify的詳解

    Node.js 8帶來了 很多新特性 .其中比較值得注意的,便有 util.promisify() 這個方法. util.promisify() 雖然 Promise 已經普及,但是 Node.js ...

  7. eclipse中的項目為什麼無法添加到tomcat中?

    1.右鍵點擊項目,選擇properties 2.點擊Project facets 3.在右側的Runtimes中選中apache tomcat 4.勾選Dynamic Web Module 最終改為下 ...

  8. tarjan算法總結

    部分內容引自https://www.cnblogs.com/stxy-ferryman/p/7779347.html Tarjan算法不是一個算法而是一類算法 1.求取强連通分量 强連通分量————有 ...

  9. InetAddress and InetSocketAddress

    1.InetAddress(包含IP地址及主機名) InetAddress is = InetAddress.getLocalHost(); /* 通過靜態方法獲得本機的對象 */ System.ou ...

  10. 在VS中為C/C++源代碼文件生成對應的匯編代碼文件(.asm)

    以VS2017為例 然後重新生成工程,在工程目錄中就會有對應的匯編代碼文件.