11、文件上传和下载
11.1、文件上传
回顾:Java Web文件上传
-
浏览器处理上传文件,将文件以流的形式提交到服务器端
-
commons-fileupload
:Apache 的文件上传组件,取代原生的文件上传流。 -
commons-io
:commons-fileupload 组件依赖于该组件。
-
-
前端表单
-
提交方式:
method=“post”
-
编码类型:
enctype="multipart/form-data"
-
提交方式:
SpringMVC 文件上传
- 提供了更简单的封装;
- 提供了即插即用的支持,通过 MultipartResolver 实现:
- 需要 Apache 的
commons-fileupload
组件支持; - 实现类:CommonsMultipartResolver 类
- 需要 Apache 的
11.1.1、实用类
- 服务器端收到请求时,DispatcherServlet 的
checkMultipart()
方法会调用 MultipartResolver 的isMultiPart()
方法来判断请求中是否包含文件上传控件; - 如果请求数据中包含文件,调用 MultipartResolver 的
resolveMultipart()
方法来解析请求数据,将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest 对象中,再传递给 Controller。 - MultipartFile 封装了请求数据中的文件,此时这个文件存储在内存中或临时的磁盘文件中,需要将其转存到一个合适的位置,因为请求结束后临时存储将被清空。
MultipartResolver 类
- 类似原来的 ServletFileUpload 类
-
isMultipart()
:ServletFileUpload 类的isMultipartContent()
; -
resolveMultipart()
:ServletFileUpload 类的parseRequest()
; -
cleanupMultipart()
:DiskFileItem 类的delete()
;
-
// 判断请求是否包含文件上传控件
boolean isMultipart(HttpServletRequest request);
// 解析请求
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request);
// 清除主题内容
void cleanupMultipart(MultipartHttpServletRequest request);
MultipartFile 类
类似原来的 FileItem 类
- getName ():
- getOriginalFilename ():
- getContentType ():
// 获取参数的名称
String getName();
// 获取上传文件名
String getOriginalFilename();
// 获取文件内容的类型
String getContentType();
// 判断文件是否为空
boolean isEmpty();
// 获取文件大小
long getSize();
// 将文件内容以字节数组的形式返回
byte[] getBytes();
// 获取文件输入流:将文件内容以输入流的形式返回
InputStream getInputStream();
// 将上传文件内容保存到指定目录文件中
void transferTo(File dest);
11.1.2、环境搭建
-
导入
commons-fileupload
的依赖,Maven 会自动导入它的依赖包commons-io
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
-
新建 module,添加 web 框架支持:在项目结构中手动添加 lib 目录;
-
web.xml
- DispatcherServlet
- 字符编码过滤器
-
applicationContext.xml
- 添加注解支持
- 静态资源过滤
- 添加注解驱动
- 视图解析器
-
配置 bean:MultipartResolver
- id 必须为 multipartResolver
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"> <!-- 请求的编码格式,需与JSP的页面编码格式相同 --> <property name="defaultEncoding" value="utf-8"/> <!-- 上传文件大小的最大值,单位为byte --> <property name="maxUploadSize" value="10485760"/> <!-- 缓存文件的最大值,单位为byte --> <property name="maxInMemorySize" value="40960"/> </bean>
11.1.3、编写代码
Controller
- 获取上传文件名
- 设置上传文件的保存路径
- 文件传输
使用 IO 流传输
- 获取文件输入流
- 获取文件输出流
- 读取写出文件
@Controller
@RequestMapping("/file")
public class FileController {
/**
* @param file 封装了请求数据中的文件,如果有多个则声明为数组
*/
@RequestMapping("/upload1")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
// 获取上传文件名
String originalFilename = file.getOriginalFilename();
System.out.println("上传文件名 : " + originalFilename);
// 如果没有上传文件,直接返回首页
if ("".equals(originalFilename)) {
return "redirect:/index.jsp";
}
// 设置上传文件保存路径
String path = request.getServletContext().getRealPath("/upload");
// 如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件保存地址:" + realPath);
// 文件传输
// 获取文件输入流
InputStream is = file.getInputStream();
// 文件输出流
OutputStream os = new FileOutputStream(new File(realPath, originalFilename));
// 读取写出
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
os.flush();
}
os.close();
is.close();
return "success";
}
}
使用 TransferTo 方法
除了使用流,还可以使用 MultipartFile 类的 TransferTo 方法来读取写出文件。
/**
* @param file 封装了请求数据中的文件,如果有多个则声明为数组
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
// 获取上传文件名
String originalFilename = file.getOriginalFilename();
System.out.println("上传文件名 : " + originalFilename);
// 如果没有上传文件,直接返回首页
if ("".equals(originalFilename)) {
return "redirect:/index.jsp";
}
// 设置上传文件保存路径
String path = request.getServletContext().getRealPath("/upload");
// 如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件保存地址:" + realPath);
// 文件传输
file.transferTo(new File(realPath + "/" + originalFilename));
return "success";
}
相比原生的 Servlet 实现文件上传,省去了以下的手动操作:
- 判断表单是否包含文件上传控件;
- 创建临时文件的保存路径;
- 创建 DiskFileItemFactory 、ServletFileUpload 对象;
- 解析请求。
前端页面
<form action="${pageContext.request.contextPath}/file/upload1"
enctype="multipart/form-data" method="post">
<input type="file" name="file"><br>
<input type="submit">
</form>
<form action="${pageContext.request.contextPath}/file/upload2"
enctype="multipart/form-data" method="post">
<input type="file" name="file"><br>
<input type="submit">
</form>