axios实现下载功能,服务器之间进行文件传输

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nihaoa50/article/details/84346880

在这里插入图片描述

需求描述:

需求其实很简单就是文件下载。

前端以下简称为: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);
		}
}

猜你喜欢

转载自blog.csdn.net/nihaoa50/article/details/84346880