需求其实很简单就是文件下载。
前端以下简称为:client
后端服务器简称:oneServer
文件所在服务器简称:fileServer
没采用该方案的原因:
- 因为我们公司的服务器密码是时常更新的,每次都到服务器密码系统申请才能登录。
- 这种方法会存在一定的安全问题。
没采用该方案的原因:
- 公司已经有文件服务器了,只是我们项目特殊,没有接入而已
- 由于我之前没有做过FTP服务器,怕耗时过长,影响项目进度。
- 即使做出了FTP服务器,后续架构评审也会非常耗时。
采用该方案的原因
- 无需公司架构评审。只需要写一个javaWeb程序提供服务即可。
- 只需要操作流,fileServer读取文件信息流传送给oneServer,oneServer直接把流传输给前端,只需要考虑信息流的高效即可。
以上这三种方案都是可以实现的,肯定不只局限于这三种方案。才疏学浅,只能想到这三种,有好的方法还请告知。
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}
这是我们项目统一的返回格式,所以需要如代码中所写,在下载失败时做提示。
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并不熟悉,这些方法这是可以实现需求,我还没有深入了解,如果错误还请留言之处,谢谢。
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);
}
}
本人程序媛一枚,因为离港澳较近,周末兼职港澳人肉代购。
欢迎各位大佬添加本人微信,还会经常有点赞活动送价值不菲的小礼品哦。
即使现在不需要代购,等以后有了女(男)朋友、有了宝宝就肯定会需要的喽。
动动手指头,扫码一下,就当是对本博文的支持嘛,也是对一个平凡、勤劳、勇敢、秀外慧中等等优点的程序媛莫大的支持哈。