前后台交互实现点击超链接通过指定的 url 去网络或者文件服务器下载文件

前台 VUE 界面:

<el-table-column prop="attachment" align="center" label="附件详情">
<template slot-scope="scope">
<!--<el-button @click="downloadFile(scope.row.fileName,scope.row.fileUrl)">{{scope.row.fileName}}</el-button>-->
<a @click="downloadFile(scope.row.fileName,scope.row.fileUrl)">{{scope.row.fileName}}</a>
</template>
</el-table-column>
//window.open打开一个新的浏览器窗口,通过 url 对后台的 rest 接口进行调用
downloadFile(fileName,fileUrl){
let param = {"fileUrl": fileUrl, "fileName": fileName};
  window.open(
  downloadManage.downloadFile(param),
  this.openType
);
},
/* 下载文件,对参数 url 和 fileName 进行拼接处理,然后通过 window.open 对后台的 rest 接口进行调用 */
export const downloadManage = {
downloadFile: (query) => requestGetUrl('/process/downloadFile.do_', query, 'post'),
};

后台java代码:(rest接口,供前台进行调用)

  /**
* 下载文件
*
* @return
*/
@RequestMapping("/downloadFile.do_")
@ResponseBody
public void downloadFile(
HttpServletResponse response,
@RequestParam String fileUrl,
@RequestParam String fileName
) {
downLoadFromUrl(fileUrl,fileName,response);
} /**
* 从网络Url中下载文件
* @param urlStr 指定的url
* @param fileName 下载文件完成要叫的名字
* @param response
*/
public static void downLoadFromUrl(String urlStr,String fileName,HttpServletResponse response){ try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    
     //增加头部,说明该文件为附件,只能进行下载,不直接读
response.setContentType("application/x-msdownload; charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName); //得到输入流
InputStream inputStream = conn.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream);
OutputStream os = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
/* ContentLength必须设置,否则文件下载不全
* 或者调用 BufferedOutputStream#write(byte[] b, int off, int len) 方法输出
*/
response.setContentLength(bis.available());
byte[] b = new byte[1024];
while(bis.read(b) != -1) {
bos.write(b);
}
bos.flush(); LOGGER.info("info:"+fileName+" download success");
} catch (IOException e) {
LOGGER.error("uploadFile failed", e);
} }

注意:上面的方法有一个小问题:用过url去网络获取 inputStream 是一点一点不断获取,获取的过程中就去写这个 inputStream  ,则 inputStream  还没有获取完就写了,导致文件最后有缺失,所以可以给 inputStream 加一个同步锁synchronized,就能使 inputStream  全部获取完并写,这样就能获取完整的 inputStream 并写下来,就能下载一个完整的文件

public static void  downLoadFromUrl(String urlStr,String fileName,HttpServletResponse response){

        URL url = null;
HttpURLConnection conn = null;
try {
url = new URL(urlStr);
conn = (HttpURLConnection)url.openConnection();
}catch (Exception e) {
LOGGER.error("HttpURLConnection failed", e);
}
try (
InputStream inputStream = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(inputStream);
OutputStream os = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
) {
//未知上传的文件类型设置ContentType 和 Header
response.setContentType("application/octet-stream; charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(),"ISO8859-1")); //同步块,同步 inputStream ,边获取 inputStream 边写,一直到全部获取完 inputStream
synchronized (inputStream) {
byte[] b = new byte[1024];
int count = 0;
int len;
while((len = bis.read(b)) != -1) {
bos.write(b, 0, len);
count++;
}
bos.flush();
//多少 Kb 大小的文件,则循环多少次,为count值
LOGGER.info("write BufferedOutputStream:" + count);
LOGGER.info("info:" + fileName + " download success");
}
} catch (Exception e) {
LOGGER.error("uploadFile failed", e);
} }

会出现如下通常我们网上点击某超链接下载文件的效果:(下载完成出现在浏览器页面左下角)

前后台交互实现点击超链接通过指定的 url 去网络或者文件服务器下载文件

上一篇:9个Linux系统常用监控命令


下一篇:通过指定的 url 去网络或者文件服务器下载文件到本地某个文件夹