学科分类
目录
Spring Boot开发

文件下载

下载文件能够通过IO流实现,所以多数框架并没有对文件下载进行封装处理。文件下载时涉及到不同浏览器的解析处理,可能会出现中文乱码的情况。接下来,分别针对下载英文名文件和中文名文件进行讲解。

1. 英文名文件下载

(1)添加文件下载工具依赖。在pom.xml文件中这引入文件下载的一个工具类依赖commons-io,示例代码如下。

<!-- 文件下载的工具依赖 -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

(2)定制文件下载页面。在chapter05项目类路径下的templates文件夹下创建一个演示文件下载的download.html模板页面,内容如文件1所示。

文件1 download.html

 1    <!DOCTYPE html>
 2    <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3    <head>
 4        <meta charset="UTF-8">
 5        <title>文件下载</title>
 6    </head>
 7    <body>
 8        <div style="margin-bottom: 10px">文件下载列表:</div>
 9        <table>
 10            <tr>
 11                <td>bloglogo.jpg</td>
 12                <td><a th:href="@{/download(filename='bloglogo.jpg')}">下载文件</a></td>
 13            </tr>
 14            <tr>
 15                <td>Spring Boot应用级开发教程.pdf</td>
 16                <td><a th:href="@{/download(filename='Spring Boot应用级开发教程.pdf')}">
 17                                                                          下载文件</a></td>
 18            </tr>
 19        </table>
 20    </body>
 21    </html>

文件1通过列表展示了要下载的两个文件名及其下载链接,需要注意的是,在文件下载之前,需要在文件下载目录(本示例中的“F:/file/”目录)中保证存在文件bloglogo.jpg和Spring Boot应用级开发教程.pdf(这只是两个测试文件而已,读者演示时可以自行存放,只要保持文件名统一即可)。

(3)编写文件下载处理方法。在之前创建的文件管理控制类FileController中编写文件下载的处理方法,示例代码如下。

// 向文件下载页面跳转
@GetMapping("/toDownload")
public String toDownload(){
    return "download";
}
// 文件下载管理
@GetMapping("/download")
public ResponseEntity<byte[]> fileDownload(String filename){
    // 指定要下载的文件根路径
    String dirPath = "F:/file/";
    // 创建该文件对象
    File file = new File(dirPath + File.separator + filename);
    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    // 通知浏览器以下载方式打开
    headers.setContentDispositionFormData("attachment",filename);
    // 定义以流的形式下载返回文件数据
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    try {
        return new ResponseEntity<>(FileUtils.readFileToByteArray(file), 
headers, HttpStatus.OK);
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<byte[]>(e.getMessage().getBytes(),
HttpStatus.EXPECTATION_FAILED);
    }
}

上述代码中,toDownload()方法用来处理路径为“/toDownload”的Get请求,向文件下载页面download.html跳转;fileDownload(String filename)方法用来处理路径为“/download”的Get请求,并进行文件下载处理。其中,在fileDownload(String filename)方法中,设定了文件下载的存储路径为“F:/file/”、文件下载的打开方式和返回形式;在获取下载结果时,使用了FileUtils的readFileToByteArray()方法快速下载文件,并以ResponseEntity<byte[]>类型数据返回。

(4)效果测试。完成上述文件下载功能的实现后,启动项目,项目启动成功后,在浏览器上访问“http://localhost:8080/toDownload”进入下载页面,效果如图1所示。

图1 文件下载页面效果

这里,先选择下载第一个英文名文件“bloglogo.jpg”。单击后面的“下载文件”链接后,效果如图2所示(以谷歌浏览器为例)。

图2 英文名文件下载效果

从图2可以看出,成功下载了英文名的文件。读者在学习演示过程中,还可以使用其他浏览器进行效果演示,同时还可以进入到下载保存的目录打开文件查看效果。

2. 中文名文件下载

在上一步所示的文件下载页面中,单击第二个中文名文件“Spring Boot应用级开发教程.pdf”后面的“下载文件”链接进行下载,效果如图3所示。

图3 中文件名文件下载效果

从图3可以看出,对中文名文件进行下载时,虽然可以成功下载,但是下载后的文件中文名称统一变成了“_”,这显然是不理想的,因此还需要对中文名文件下载进行额外处理。

在FileController类的fileDownload()方法中添加中文的编码处理代码,修改后的代码如下所示。

// 所有类型文件下载管理
@GetMapping("/download")
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
String filename) throws Exception{
    // 指定要下载的文件根路径
    String dirPath = "F:/file/";
    // 创建该文件对象
    File file = new File(dirPath + File.separator + filename);
    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    // 通知浏览器以下载方式打开(下载前对文件名进行转码)
    filename=getFilename(request,filename);
    headers.setContentDispositionFormData("attachment",filename);
    // 定义以流的形式下载返回文件数据
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    try {
        return new ResponseEntity<>(FileUtils.readFileToByteArray(file), 
headers, HttpStatus.OK);
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<byte[]>(e.getMessage().getBytes(),
HttpStatus.EXPECTATION_FAILED);
    }
}
// 根据浏览器的不同进行编码设置,返回编码后的文件名
private 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").replace("+"," ");
        }
    }
    //火狐等其它浏览器统一为ISO-8859-1编码显示
    return new String(filename.getBytes("UTF-8"), "ISO-8859-1");
}

上述代码中,getFilename(HttpServletRequest request,String filename)方法用来根据不同浏览器对下载的中文名进行转码。其中,通过HttpServletRequest中的“User-Agent”用于获取用户下载文件的浏览器内核信息(不同版本的IE浏览器内核可能不同,需要特别查看),如果内核信息是IE则转码为UTF-8,其他浏览器转码为ISO-8859-1即可。

重新启动项目,在浏览器上访问“http://localhost:8080/toDownload”进入下载页面,下载中文名文件 “Spring Boot应用级开发教程.pdf”,效果如图4所示。

图4 中文名文件下载效果

从图4可以看出,对文件下载处理方法中的编码进行修改后,同样可以成功下载中文名文件。

点击此处
隐藏目录