前台 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);
} }

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

最新文章

  1. erlang 健壮性
  2. SQLServer数据库还原提示 数据库正在使用,无法获得独占访问权
  3. logging模块使用示例
  4. HDU 5046 Airport(dlx)
  5. Good Bye 2015 C. New Year and Domino 二维前缀
  6. Tiny210v2( S5PV210 )平台下创建基本根文件系统
  7. UOJ222 NOI2016 区间 线段树+FIFO队列
  8. 2014.8.30.ref,out,params,enum,递归
  9. 为什么要在onNewIntent的时候要显示的去调用setIntent
  10. noip普及组2005 陶陶摘苹果
  11. MATCH_PARENT和FILL_PARENT之间的区别?
  12. Linux删除文件夹和修改文件名
  13. K3CLOUD常用数据表
  14. websocket简单理解
  15. Ubuntu14.04安装PyMuPDF
  16. 9.12 翻译系列:数据注解特性之ConcurrencyCheck【EF 6 Code-First系列】
  17. python 进程锁
  18. 【WebForm】知识笔记
  19. .NET中那些所谓的新语法
  20. vim:过一个字符

热门文章

  1. pandas的离散化,面元划分
  2. [转][C#]手写 Socket 服务端
  3. mariadb semi plugin遇到的坑
  4. C语言强化——文件
  5. JDK、JRE与JVM的关系
  6. Tom与Jerry谁先死?
  7. [UE4]函数分组
  8. 0000 - Spring MVC 原理以及helloworld
  9. 初始Golang
  10. U3D学习003——编辑器使用