简介: 全栈开发实战|Spring Boot 文件上传与下载
01、Spring Boot 文件上传与下载
在实际的 Web 应用开发中,为了成功上传文件,必须将表单的 method 设置为 post,并将 enctype 设置为 multipart/form-data。只有这种设置,浏览器才能将所选文件的二进制数据发送给服务器。
从 Servlet 3.0 开始,就提供了处理文件上传的方法,但这种文件上传需要在 Java Servlet 中完成,而 Spring MVC 提供了更简单的封装。Spring MVC 是通过 Apache Commons FileUpload 技术实现一个 MultipartResolver 的实现类 CommonsMultipartResolver 完成文件上传的。因此,Spring MVC 的文件上传需要依赖 Apache Commons FileUpload 组件。
Spring MVC 将上传文件自动绑定到 MultipartFile 对象中,MultipartFile 提供了获取上传文件内容、文件名等方法,并通过 transferTo 方法将文件上传到服务器的磁盘中,MultipartFile 的常用方法如下:
● byte[] getBytes():获取文件数据。
● String getContentType():获取文件 MIME 类型,如 image/jpeg 等。
● InputStream getInputStream():获取文件流。
● String getName():获取表单中文件组件的名字。
● String getOriginalFilename():获取上传文件的原名。
● long getSize():获取文件的字节大小,单位为 byte。
● boolean isEmpty():是否有(选择)上传文件。
● void transferTo(File dest):将上传文件保存到一个目标文件中。
Spring Boot 的 spring-boot-starter-web 已经集成了 Spring MVC,所以使用 Spring Boot 实现文件上传,更加便捷,只需要引入 Apache Commons FileUpload 组件依赖即可。
02、举例说明
下面通过一个实例讲解 Spring Boot 文件上传与下载的实现过程。
【例 7】Spring Boot 文件上传与下载。
具体实现步骤如下。
1●引入 Apache Commons FileUpload 组件依赖
在 Web 应用 ch7_2 的 pom.xml 文件中,添加 Apache Commons FileUpload 组件依赖,具体代码如下:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<!-- 由于commons-fileupload组件不属于Spring Boot,所以需要加上版本 -->
<version>1.4</version>
</dependency>
复制代码
2●设置上传文件大小限制
在 Web 应用 ch7_2 的配置文件 application.properties 中,添加如下配置进行限制上传文件大小。
#上传文件时,默认单个上传文件大小是1MB,max-file-size设置单个上传文件大小
spring.servlet.multipart.max-file-size=50MB
#默认总文件大小是10MB,max-request-size设置总上传文件大小
spring.servlet.multipart.max-request-size=500MB
复制代码
3●创建选择文件视图页面
在 ch7_2 应用的 src/main/resources/templates 目录下,创建选择文件视图页面 uploadFile.html。该页面中有个 enctype 属性值为 multipart/form-data 的 form 表单,具体代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
<!-- 默认访问 src/main/resources/static下的css文件夹-->
<link rel="stylesheet" th:href="@{css/bootstrap-theme.min.css}" />
</head>
<body>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">文件上传示例</h3>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6 col-sm-6">
<form class="form-horizontal" action="upload"
method="post" enctype="multipart/form-data">
<div class="form-group">
<div class="input-group col-md-6">
<span class="input-group-addon">
<i class="glyphicon glyphicon-pencil"></i>
</span>
<input class="form-control" type="text"
name="description" th:placeholder="文件描述"/>
</div>
</div>
<div class="form-group">
<div class="input-group col-md-6">
<span class="input-group-addon">
<i class="glyphicon glyphicon-search"></i>
</span>
<input class="form-control" type="file"
name="myfile" th:placeholder="请选择文件"/>
</div>
</div>
<div class="form-group">
<div class="col-md-6">
<div class="btn-group btn-group-justified">
<div class="btn-group">
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-share"></span>
上传文件
</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
复制代码
4●创建控制器
在 ch7_2 应用的 com.ch.ch7_2.controller 包中,创建控制器类 TestFileUpload。在该类中有 4 个处理方法,一个是界面导航方法 uploadFile,一个是实现文件上传的 upload 方法,一个是显示将要被下载文件的 showDownLoad 方法,一个是实现下载功能的 download 方法。核心代码如下:
@Controller
public class TestFileUpload {
@RequestMapping("/uploadFile")
public String uploadFile() {
return "uploadFile";
}
/**
* 上传文件自动绑定到MultipartFile对象中,
* 在这里使用处理方法的形参接收请求参数。
*/
@RequestMapping("/upload")
public String upload(
HttpServletRequest request,
@RequestParam("description") String description,
@RequestParam("myfile") MultipartFile myfile)
throws IllegalStateException, IOException {
System.out.println("文件描述:" + description);
//如果选择了上传文件,将文件上传到指定的目录uploadFiles
if(!myfile.isEmpty()) {
//上传文件路径
String path = request.getServletContext().getRealPath("/uploadFiles/");
//获得上传文件原名
String fileName = myfile.getOriginalFilename();
File filePath = new File(path + File.separator + fileName);
//如果文件目录不存在,创建目录
if(!filePath.getParentFile().exists()) {
filePath.getParentFile().mkdirs();
}
//将上传文件保存到一个目标文件中
myfile.transferTo(filePath);
}
//转发到一个请求处理方法,查询将要下载的文件
return "forward:/showDownLoad";
}
/**
* 显示要下载的文件
*/
@RequestMapping("/showDownLoad")
public String showDownLoad(HttpServletRequest request, Model model) {
String path = request.getServletContext().getRealPath("/uploadFiles/");
File fileDir = new File(path);
//从指定目录获得文件列表
File filesList[] = fileDir.listFiles();
model.addAttribute("filesList", filesList);
return "showFile";
}
/**
* 实现下载功能
*/
@RequestMapping("/download")
public ResponseEntity<byte[]> download(
HttpServletRequest request,
@RequestParam("filename") String filename,
@RequestHeader("User-Agent") String userAgent) throws IOException {
//下载文件路径
String path = request.getServletContext().getRealPath("/uploadFiles/");
//构建将要下载的文件对象
File downFile = new File(path + File.separator + filename);
//ok表示HTTP中的状态是200
BodyBuilder builder = ResponseEntity.ok();
//内容长度
builder.contentLength(downFile.length());
//application/octet-stream:二进制流数据(最常见的文件下载)
builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
//使用URLEncoder.encode对文件名进行编码
filename = URLEncoder.encode(filename,"UTF-8");
/**
* 设置实际的响应文件名,告诉浏览器文件要用于“下载”和“保存”。
* 不同的浏览器,处理方式不同,根据浏览器的实际情况区别对待。
*/
if(userAgent.indexOf("MSIE") > 0) {
//IE浏览器,只需要用UTF-8字符集进行URL编码
builder.header("Content-Disposition", "attachment; filename=" + filename);
}else {
/**非IE浏览器,如FireFox、Chrome等浏览器,则需要说明编码的字符集
* filename后面有个*号,在UTF-8后面有两个单引号
*/
builder.header("Content-Disposition", "attachment; filename*=UTF-8''" + filename);
}
return builder.body(FileUtils.readFileToByteArray(downFile));
}
}
复制代码
5●创建文件下载视图页面
在 ch7_2 应用的 src/main/resources/templates 目录下,创建文件下载视图页面 showFile.html。核心代码如下:
<body>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">文件下载示例</h3>
</div>
</div>
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">文件列表</h3>
</div>
<div class="panel-body">
<div class="table table-responsive">
<table class="table table-bordered table-hover">
<tbody class="text-center">
<tr th:each="file,fileStat:${filesList}">
<td>
<span th:text="${fileStat.count}"></span>
</td>
<td>
<!--file.name相当于调用getName()方法获得文件名称 -->
<a th:href="@{download(filename=${file.name})}">
<span th:text="${file.name}"></span>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</body>
复制代码
6●运行
首先,运行 Ch72Application 主类。然后,访问 http://localhost:8080/ch7_2/uploadFile 测试文件上传与下载。
评论 (1 条评论)