上篇文章写到了文件上传,这次就谈谈文件下载:
其实文件上传下载无非就是通过io流与http协议request和response来传输文件

而文件下载就是将文件io放到response的body(也就是http响应体)中从而返回给客户端,要注意的是需要对响应头进行设置:

httpheader的Content-disposition :

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型
是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。当浏览器接收到头时,它会激活文件下载对话框;
注意:必须添加一个attachment(附件)字符串参数,可以询问是否下载文件;
而且可以传一个文件名过去,它的文件名框自动填充了头中指定的文件名。

httpheader的Content-Type:

Content-Type 用于指示资源的MIME类型
  • 在响应头中,告诉客户端实际返回内容的类型
  • 在请求头中,告诉服务器实际发送的数据类型


servlet下载的方法:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //通过路径得到一个输入流
        String path = this.getServletContext().getRealPath("/WEB-INF/classes/111.jpg");
        FileInputStream fis = new FileInputStream(path);
        //创建字节输出流
        ServletOutputStream sos = response.getOutputStream();
        
        //得到要下载的文件名
        String fileName = path.substring(path.lastIndexOf("\\")+1);
        //设置文件名的编码,将不安全的文件名改为UTF-8
        fileName = URLEncoder.encode(fileName,"UTF-8");
        
        //告知客户端要下载文件
        response.setHeader("content-disposition","attachment;filename="+fileName);
        response.setHeader("content-type","image/jpeg");
        
        //执行输出操作
        int len = 1;
        byte[] buff = new byte[1024];
        while((len=fis.read(buff))!=-1){
            sos.write(buff,0,len);
        }
        //关闭资源
        sos.close();
        fis.close();
    }


在SpringMVC和SpringBoot中:

由于用到了框架,所以可以不要去直接操作response,而是通过返回一个ResponseEntity<byte[]>(也就是相应实体),通过设置实体的相应头和响应体来实现下载:
在把文件转化成字节数组的时候有两种方法,一种是原生的:
注:
inputStream的available是用来获取io的字节数的,一般从本地读取时可以用,如果是从网络传输的io流则不太准确,因为网络传输是分段传的。具体可网上查找。
org.springframework.http.MediaType:声明了content-type的各种类型。
org.springframework.http.HttpStatus:提供了一些状态码,不一定非要写CREATED(201),只是标识一下请求成功时的状态码而已,可以自行选择。

@GetMapping
public ResponseEntity<byte[]> download() throws IOException {
    byte[] body=null;

    String path="F:/photo/avatar.png";
    File file=new File(path);

    HttpHeaders headers=new HttpHeaders();
    // 通知浏览器以下载文件方式打开
    headers.setContentDispositionFormData("attachment","FILENAME.jpg");
    headers.setContentType(MediaType.IMAGE_JPEG);

    FileInputStream fis=new FileInputStream(file);
    body=new byte[fis.available()];
    fis.read(body);

    return  new ResponseEntity<byte[]>(body,headers, HttpStatus.CREATED);
}
还有一种是利用commons-io工具包来从输入流中来读取出文件的字节数组:
使用前需导包:
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
使用代码:
@GetMapping
    public ResponseEntity<byte[]> download() throws IOException {
        String path="F:/photo/avatar.png";
        File file=new File(path);

        HttpHeaders headers=new HttpHeaders();
        headers.setContentDispositionFormData("attachment","FILENAME.jpg");
        headers.setContentType(MediaType.IMAGE_JPEG);

        return  new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
    }


参考: