Spring MVC 上传文件
Spring MVC的文件上传是通过MultipartResolver(Multipart解析器)处理的,对于MultipartResolver而言它只是一个接口,它有两个实现类。
•CommonsMultipartResolver:依赖于Apache下的jakartaCommon FileUpload项目解析Multipart请求,可以在Spring的各个版本中使用,只是它要依赖于第三方包才得以实现。
•StandardServletMultipartResolver:是Spring 3.1版本后的产物,它依赖于Servlet 3.0或者更高版本的实现,它不用依赖第三方包。
对于两者而言,笔者更倾向于StandardServletMultipartResolver,因为它无须引入任何第三方包,只是当项目使用Spring3.1以下的版本或者Servlet 3.0以下的版本时,只能选择CommonsMultipartResolver。本书会以StandardServletMultipartResolver为主,CommonsMultipartResolver为辅介绍文件上传方面的内容。无论在你的项目中使用的是CommonsMultipartResolver还是StandardServletMultipartResolver,都要配置一个MultipartResolver。
MultipartResolver概述
<!-- 配置DispatcherServlet --> <servlet> <!-- 注意:Spring MVC 框架会根据 servlet-name 配置,找到/WEB-INF/dispatcher-servlet.xml作为配置文件载入Web工程中 --> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 使得Dispatcher在服务器启动的时候就初始化 --> <load-on-startup>2</load-on-startup> <!--MultipartResolver参数--> <multipart-config> <location>d:/uploads/</location> <max-file-size>5242880</max-file-size> <max-request-size>10485760</max-request-size> <file-size-threshold>0</file-size-threshold> </multipart-config> </servlet>
在Spring MVC中,对于MultipartResolver解析的调度是通过DispatcherServlect进行的。它首先判定请求是否是一种enctype="multipart/*"请求,如果是并且存在一个名称为multi-partResolver的Bean定义,那么它将会把HttpServletRequest请求转换为MultipartHttp ServletRequest请求对象。
提交上传文件表单
代码清单15-53:定义文件上传表单
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>文件上传</title></head> <body> <form method="post" action="../file/uploadMultipartFile.do" enctype="multipart/form-data"> <input type="file" name="file" value="请选择上传的文件"/> <input type="submit" value="提交"/> </form> </body> </html>
要把enctype定义为"multipart/form-data",否则Spring MVC会解析失败。
代码清单15-54:控制器处理文件上传请求
package com.ssm.chapter15.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.json.MappingJackson2JsonView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Part; import java.io.File; import java.io.IOException; @Controller @RequestMapping("/file") public class FileController { @RequestMapping("/upload") public ModelAndView upload(HttpServletRequest request) { //进行转换 MultipartHttpServletRequest mhsr = (MultipartHttpServletRequest) request; // 获得请求上传的文件 MultipartFile file = mhsr.getFile("file"); // 设置视图为JSON视图 ModelAndView mv = new ModelAndView(); mv.setView(new MappingJackson2JsonView()); // 获取原始文件名 String fileName = file.getOriginalFilename(); // 目标文件 File dest = new File(fileName); try { //保存文件 file.transferTo(dest); // 保存成功 mv.addObject("success", true); mv.addObject("msg", "上传文件成功"); } catch (IllegalStateException | IOException e) { // 保存失败 mv.addObject("success", false); mv.addObject("msg", "上传文件失败"); e.printStackTrace(); } return mv; } // 使用MultipartFile @RequestMapping("/uploadMultipartFile") public ModelAndView uploadMultipartFile(MultipartFile file) { // 定义JSON视图 ModelAndView mv = new ModelAndView(); mv.setView(new MappingJackson2JsonView()); // 获取原始文件名 String fileName = file.getOriginalFilename(); file.getContentType(); // 目标文件 File dest = new File(fileName); try { // 保存文件 file.transferTo(dest); mv.addObject("success", true); mv.addObject("msg", "上传文件成功"); } catch (IllegalStateException | IOException e) { mv.addObject("success", false); mv.addObject("msg", "上传文件失败"); e.printStackTrace(); } return mv; } // 使用Part @RequestMapping("/uploadPart") public ModelAndView uploadPart(Part file) { ModelAndView mv = new ModelAndView(); mv.setView(new MappingJackson2JsonView()); // 获取原始文件名 String fileName = file.getName(); File dest = new File(fileName); try { // 保存文件 file.write("d:/uploads/" + fileName); mv.addObject("success", true); mv.addObject("msg", "上传文件成功"); } catch (IllegalStateException | IOException e) { mv.addObject("success", false); mv.addObject("msg", "上传文件失败"); e.printStackTrace(); } return mv; } }
上面使用了MultipartFile和Part,它们的好处是把代码从Servlet API中解放出来,这体现了Spring的思维,高度的解耦性。此外,它也简化了许多关于文件的操作,这样对文件上传的开发就更为便利了。