跳到主要内容

12. 文件上传和下载

文件上传:

文件上传是项目开发中比较常用的功能之一,SpringMVC可以很好的支持文件上传,但是,SpringMVC上下文中默认是没有装配MultipartResolve,因此默认情况下其不能处理文件上传工作。

如果要使用文件上传功能,则需要在上下文中配置MultipartResolve。

前端表单要求:为了能上传文件,必须将表单的method设置为post,并设置enctype设置为multipart/form-data。只有在这种情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。

enctypre属性:

描述
application/x-www-form-urlencoded在发送前编码所有字符(默认)
multipart/form-data不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain空格转换为 "+" 加号,但不对特殊字符编码。

表单代码:

<form method="POST" action="" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>

一旦设置了enctype属性为multipart/form-data,浏览器会采用二进制流的方式处理表单的数据,而对于文件上传的处理涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快陈伟Servlet/Jsp程序员上传文件的最佳选择。

Maven依赖:

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
  • Servlet3.0规范已经提供方法来处理文件上传,但是这种上传功能只能在Servlet中完成
  • SpringMVC提供了更简单的封装
  • SpringMVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolve实现的
  • SpringMVC使用Apache Commons FileUpload技术实现了一个MultipartResolve实现类:
    • CommonsMultipartResolve类,因此SpringMVC的文件上传功能是需要依赖Apache的该组件的。

注册Bean:

CommonsMultipartResolve注册到容器中:

<!-- 定义文件上传解析器 -->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 设定文件上传的最大值为10MB,1024*1024*10 -->
<property name="maxUploadSize" value="10485760"/>
<!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240 -->
<property name="maxInMemorySize" value="40960"/>
</bean>

Controller处理:

方式一:

@Controller
public class FileController {
/**
* @RequestParam("file")将name=file控件得到的文件封装成CommonsMultipartFile对象
* 批量上传CommonsMultipartFile为数组即可
*/
@RequestMapping("/upload")
public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//获取上传文件的文件名
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,则跳转到首页
if("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传的文件名:"+uploadFileName);

//上传路径保存位置
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,uploadFileName));

//读进写出(读进内存、数组,再写出到本地磁盘)
int len = 0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}

说明:

  • InputStream is = file.getInputStream();,获取上传文件输入流
  • OutputStream os = new FileOutputStream(new File(realPath,uploadFileName));
    • 定义一个输出流对象,用于将上传的文件输入流写出到本地
    • new File(realPath,uploadFileName),定义一个File实例,指定文件保存的路径和文件名
  • is.read(buffer),将字节输入流读进字节数组(缓冲区),返回一个整型,如果返回-1,说明读取到字节流末尾,无字节可读。
  • os.write(buffer);os.flush();,从字节数组中将数据写出到本地磁盘

方式二:

@RequestMapping("/upload")
public String upload1(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件保存位置:" + realPath);
//通过CommonsMultipartFile的方法直接把上传的文件保存到本地
file.transferTo(new File(realPath + "/" + file.getOriginalFilename()));
return "redirect:/index.jsp";
}

使用transferTo()方法将上传的文件保存到本地磁盘

文件下载:

@RequestMapping("/download")
public String download(HttpServletRequest request, HttpServletResponse response) throws IOException {
//获取文件的路径
String path = request.getServletContext().getRealPath("/upload");
//文件名称
String fileName = "2020-04-12_大洼东湖向海大道_IMG_0471.jpeg";

//1. 设置响应头
response.reset();//设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8");
response.setContentType("multipart/form-data");//以二进制传输
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));

File file = new File(path, fileName);
//2. 读取文件--输入流
InputStream is = new FileInputStream(file);
//3. 写出文件--输出流
ServletOutputStream os = response.getOutputStream();

int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
os.write(buffer);
os.flush();
}
os.close();
is.close();
return "redirect:index.jsp";
}