文件下载
下载文件能够通过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可以看出,对文件下载处理方法中的编码进行修改后,同样可以成功下载中文名文件。