1. 程式人生 > >axios實現下載功能,伺服器之間進行檔案傳輸

axios實現下載功能,伺服器之間進行檔案傳輸

在這裡插入圖片描述

需求描述:

需求其實很簡單就是檔案下載。

前端以下簡稱為:client
後端伺服器簡稱:oneServer
檔案所在伺服器簡稱:fileServer

解決方案

  1. 運用jcifs包中的SmbFile方法,oneServer只需要知道fileServer的使用者名稱密碼,就可以直接訪問到fileServer中的檔案。
    SmbFile file = new SmbFile(“smb://guest:[email protected]/uplo/test.txt”);
    此方法詳細實現可以百度哈。

    沒采用該方案的原因:

    • 因為我們公司的伺服器密碼是時常更新的,每次都到伺服器密碼系統申請才能登入。
    • 這種方法會存在一定的安全問題。
  2. 將fileServer做成FTP伺服器,這樣oneServer訪問fileServer就也很方便。

    沒采用該方案的原因:

    • 公司已經有檔案伺服器了,只是我們專案特殊,沒有接入而已
    • 由於我之前沒有做過FTP伺服器,怕耗時過長,影響專案進度。
    • 即使做出了FTP伺服器,後續架構評審也會非常耗時。
  3. 寫一個JavaWeb專案到fileServer,讓其提供檔案下載介面,oneServer通過請求該介面下載檔案併發送給client。

    採用該方案的原因

    • 無需公司架構評審。只需要寫一個javaWeb程式提供服務即可。
    • 只需要操作流,fileServer讀取檔案資訊流傳送給oneServer,oneServer直接把流傳輸給前端,只需要考慮資訊流的高效即可。

以上這三種方案都是可以實現的,肯定不只侷限於這三種方案。才疏學淺,只能想到這三種,有好的方法還請告知。

實現過程

1.前端需要用axios傳送請求,因為後臺需要做校驗,如果直接用window.location.href,無法向後端傳遞使用者資訊(sessionId),因為我們的前端用的vue,前後端連線會跨域,所以axios請求裡面需要自己設定sessionId。

前端程式碼如下:

 downloadfile(){
            if(this.systemFolderName == null){
                this.$Message.error({
                    content:"請選擇系統",
                    duration:2
                });
                return;
            }
            if(this.fileName == null){
                this.$Message.error({
                    content:"請選擇檔案",
                    duration:2
                });
                return;
            }
             var postData = this.$qs.stringify({
                path: this.systemFolderName + "/" + this.fileName 
            });

            this.$axios({
                method: 'post',
                url: 'downloadfile/remotefile',
                data: postData,
                responseType: 'arraybuffer'
            }).then(response => {
                if (response.headers['content-type'].indexOf('json') === -1) {// 返回的資料不是
                    this.download(response.data);
                }else{
                    if (response.request.responseType === 'arraybuffer' && response.data.toString() === '[object ArrayBuffer]') {
                        // 返回的資料是 arraybuffer,內容是 json
                        var text = Buffer.from(response.data).toString('utf8');
                        var json = JSON.parse(text);
                        if("N" == json.code){
                            this.$Message.error({
                                content:json.message,
                                duration:2
                            });
                        } 
                    }
                }
            }).catch((error) => {

            })

        },
        download (data) {
            if (!data) {
                return;
            }
            let url = window.URL.createObjectURL(new Blob([data]))
            let link = document.createElement('a')
            link.style.display = 'none'
            link.href = url
            link.setAttribute('download', this.fileName)
            document.body.appendChild(link)
            link.click()
        }

此方法借鑑和參考以下兩位博主的部落格:
1、http://www.cnblogs.com/yulj/p/8494465.html
2、http://blog.tubumu.com/2017/12/27/axios-extension-01/
**注意:**如果只用部落格一的方法,後端下載如果報錯,那麼前端依舊會顯示成功,需要再前後端做溝通,統一報錯資訊,以便前端判斷。

{"code":"N","body":null,"message":"Required String parameter 'path' is not present","status":null}

這是我們專案統一的返回格式,所以需要如程式碼中所寫,在下載失敗時做提示。

2.oneServer接收client傳輸的引數,向fileServer傳送請求,並接收fileServer返回的資訊流,然後返回給client,其實就是充當中轉站。

oneServer實現程式碼如下:

public void remoteFile(@NotNull(message = "路徑不能為空") @RequestParam("path") String path, HttpServletResponse response,
			HttpServletRequest request) throws IOException, ServletException {
		String url = REMOTE_URL + "?selectPath=" + path;
		HttpClient httpclient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(url);
		HttpResponse res = httpclient.execute(httpGet);
		byte[] datas=null;
		if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			HttpEntity entity = res.getEntity();
			datas = EntityUtils.toByteArray(entity);
		}
		response.setContentType("multipart/form-data");
		response.setCharacterEncoding("UTF-8");
		try (	ByteArrayInputStream in = new ByteArrayInputStream(datas);  
				OutputStream out = response.getOutputStream()) {
			int b = 0;
			byte[] buffer = new byte[1024];
			while (b != -1) {
				b = in.read(buffer);
				out.write(buffer, 0, b);
			}
			out.flush();
		} catch (IOException e) {
			logger.error("前端取消下載", e);
		}
	}

此處應該可以改進,我本身對IO並不熟悉,這些方法這是可以實現需求,我還沒有深入瞭解,如果錯誤還請留言之處,謝謝。

3.fileServer接收oneServer的請求後,去讀取檔案,並將檔案返回給oneServer。

fileServer實現程式碼如下:

public void downloadFile(String selectPath, HttpServletResponse response) throws IOException {
		response.setContentType("multipart/form-data");
		response.setCharacterEncoding("UTF-8");
		File file = new File(LogsFileConfigure.LOGS_ROOT_PATH + selectPath);
		try (
				OutputStream out = response.getOutputStream();
				FileInputStream inputStream = new FileInputStream(file)) {
			int b = 0;
			byte[] buffer = new byte[1024];
			while (b != -1) {//不能一次性讀完,大檔案會記憶體溢位(不能直接fis.read(buffer);
				b = inputStream.read(buffer);
				out.write(buffer, 0, b);
			}
			out.flush();
		} catch (IOException e) {
			logger.error("讀取檔案失敗", e);
		}
}