Spring MVC 文件下载

文件下载就是将文件服务器中的文件下载到本机上。在 Spring MVC中,实现文件下载大致分为两步。

1 前端

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@page import="java.net.URLEncoder" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>下载页面</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/download?fileName=<%=URLEncoder.encode("spring开发文档.pdf", "UTF-8")%>">
    中文名称文件下载
</a><br/>
<a href="${pageContext.request.contextPath }/download1?fileName=<%=URLEncoder.encode("spring开发文档.pdf", "UTF-8")%>">
    断点下载
</a>
</body>
</html>

这里使用 URLEncoder.encode 将中文名转换了,防止中文传输问题。

2 后台

后台下载可以有两种方案,一种是使用 spring mvc 自带的 ResponseEnity 对象;一种是使用 ServletOutputStream 输出。

1 ResponseEnity 下载

@RequestMapping("/download")
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request, String fileName) throws Exception {
    // 指定要下载的文件所在路径
    String path = request.getServletContext().getRealPath("/upload/");
    // 创建该文件对象
    File file = new File(path + File.separator + fileName);
    // 对文件名编码,防止中文文件乱码
    fileName = this.getFilename(request, fileName);
    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    // 通知浏览器以下载的方式打开文件
    headers.setContentDispositionFormData("attachment", fileName);
    // 定义以流的形式下载返回文件数据
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    // 使用Sring MVC框架的ResponseEntity对象封装返回下载数据
    return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
}

/**
 * 根据浏览器的不同进行编码设置,返回编码后的文件名
 */
String getFilename(HttpServletRequest request, String filename) throws Exception {
    // IE不同版本User-Agent中出现的关键词
    String[] IEBrowserKeyWords = {"MSIE", "Trident", "Edge"};
    // 获取请求头代理信息
    String userAgent = request.getHeader("User-Agent");
    for (String keyWord : IEBrowserKeyWords) {
        if (userAgent.contains(keyWord)) {
            //IE内核浏览器,统一为UTF-8编码显示
            return URLEncoder.encode(filename, "UTF-8");
        }
    }
    //火狐等其它浏览器统一为ISO-8859-1编码显示
    return new String(filename.getBytes("UTF-8"), "ISO-8859-1");
}

使用 ResponseEntity,实现简单。一般的文件都可以使用它来完成。这里的中文乱码问题,我们使用 getFilename 方法解决。

2 ServletOutputStream 下载

@RequestMapping("/download1")
public ResponseEntity<String> downFile(HttpServletResponse response, HttpServletRequest request, String fileName)
        throws Exception {
    String path = request.getServletContext().getRealPath("/upload/");
    // 创建该文件对象
    File file = new File(path + File.separator + fileName);
    long fSize = file.length();
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/x-download");
    response.setHeader("Accept-Ranges", "bytes");
    response.setHeader("Content-Length", String.valueOf(fSize));
    response.setHeader("Content-Disposition", "attachment;fileName=" + this.getFilename(request, fileName));
    long pos = 0;
    if (null != request.getHeader("Range")) {
        // 断点续传
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        try {
            pos = Long.parseLong(request.getHeader("Range").replaceAll("bytes=", "").replaceAll("-", ""));
        } catch (NumberFormatException e) {
            pos = 0;
        }
    }
    String contentRange = "bytes " + pos + "-" + (fSize - 1) + "/" + fSize;
    response.setHeader("Content-Range", contentRange);
    InputStream inputStream = null;
    ServletOutputStream out = null;
    try {
        inputStream = new FileInputStream(file);
        inputStream.skip(pos);
        out = response.getOutputStream();
        byte[] buffer = new byte[1024 * 100];
        int length = 0;
        while ((length = inputStream.read(buffer, 0, buffer.length)) != -1) {
            out.write(buffer, 0, length);
            // Thread.sleep(100);
        }
    } finally {
        if (null != out) out.flush();
        if (null != out) out.close();
        if (null != inputStream) inputStream.close();
    }
    return new ResponseEntity(null, HttpStatus.OK);
}

使用 ServletOutputStream 稍微复杂一点。但是也有好处,我们可以更加精细的控制传输的过程,还能实现断点续传。如果响应头 Content-Length 无法设置,这是因为浏览器请求的时候默认使用了长连接,需要在服务器配置的时候关闭长连接的支持。

 


Appendix

Sample Code

Java

Revision History

时间描述
2017-09-28博文完成

CSDN:http://blog.csdn.net/y550918116j

GitHub:https://github.com/937447974

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值