15、文件上传
-
Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。Spring 用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResovler
-
Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需先在上下文中配置 MultipartResolver
(1)配置 MultipartResolver
-
defaultEncoding: 必须和用户 JSP 的 pageEncoding 属性一致,以便正确解析表单的内容
-
为了让 CommonsMultipartResovler 正确工作,必须先将 Jakarta Commons FileUpload 及 Jakarta Commons io 的类包添加到类路径下。
<!-- 配置 MultipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>
(2)文件上传示例
index.jsp
<form action="testFileUpload" method="post" enctype="multipart/form-data">
File:<input type="file" name="file"/>
Desc:<input type="text" name="desc"/>
<input type="submit" value="Submit"/>
</form>
SpringMVCTest.java
@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desc") String desc,
@RequestParam("file") MultipartFile file) throws IOException {
System.out.println("desc:" + desc);
System.out.println("OriginalFilename" + file.getOriginalFilename());
System.out.println("InputStream : " + file.getInputStream());
return "success";
}
16、拦截器
16.1 自定义拦截器
Spring MVC 也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口
-
preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
-
postHandle():这个方法在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求 request 进行处理。
-
afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
拦截器方法执行顺序:
16.2 配置自定义拦截器
<mvc:interceptors>
<!-- 配置自定义的拦截器 -->
<bean class="com.mycode.springmvc.interceptors.FirstInterceptor"></bean>
<!-- 配置拦截器作用(不作用)的路径 -->
<mvc:interceptor>
<!--<mvc:exclude-mapping path=""/>-->
<mvc:mapping path="/emps"/>
<bean class="com.mycode.springmvc.interceptors.SecondInterceptor"></bean>
</mvc:interceptor>
<!-- 配置 LocaleChangeInterceptor -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
17、异常处理
-
Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
-
SpringMVC 提供的 HandlerExceptionResolver 的实现类
17.1 HandlerExceptionResolver
DispatcherServlet 默认装配的 HandlerExceptionResolver :(Spring5 中 AnnotationMethodHandlerExceptionResolver 已经去掉)
①没有使用 <mvc:annotation-driven/> 配置:
②使用了 <mvc:annotation-driven/> 配置:
17.2 ExceptionHandlerExceptionResolver
-
主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
-
@ExceptionHandler 注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有 RuntimeException 和 Exception,此时会根据异常的最近继承关系找到继承深度最浅的那个 @ExceptionHandler 注解方法,即标记了 RuntimeException 的方法
-
ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 中的 @ExceptionHandler 注解方法
(1)在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数,该参数即对应发生的异常对象
(2)@ExceptionHandler 方法的入参中不能传入 Map,若希望把异常信息传到页面上,需要使用 ModelAndView 作为返回值
(3)@ExceptionHandler 方法标记的异常有优先级的问题
会选择更加符合的异常处理方法
@ExceptionHandler({
RuntimeException.class})
public ModelAndView handlerArithmeticException2(Exception ex){
System.out.println("[出异常了]:" + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception",ex);
return mv;
}
@ExceptionHandler({
ArithmeticException.class})
public ModelAndView handlerArithmeticException(Exception ex){
System.out.println("出异常了:" + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception",ex);
return mv;
}
(4)@ControllerAdvice:如果在当前 Handler 中找不到 @ExceptionHandler 方法来处理当前方法出现的异常,则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常。
@ControllerAdvice
public class HandleException {
@ExceptionHandler({
ArithmeticException.class})
public ModelAndView handlerArithmeticException(Exception ex){
System.out.println("---->出异常了:" + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception",ex);
return mv;
}
}
17.3 ResponseStatusExceptionResolver
-
在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。
-
定义一个 @ResponseStatus 注解修饰的异常类
@ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException{
static final long serialVersionUID = -7034897190745766945L;
}
-
若在处理器方法中抛出了上述异常:
若ExceptionHandlerExceptionResolver 不解析述异常。由于触发的异常 UnauthorizedException 带有 @ResponseStatus 注解。因此会被 ResponseStatusExceptionResolver 解析到。最后响应 HttpStatus.UNAUTHORIZED 代码给客户端。HttpStatus.UNAUTHORIZED 代表响应码 401,无权限。关于其他的响应码请参考 HttpStatus 枚举类型源码。 -
@ResponseStatus 既可以修饰异常类,也可以修饰方法,修饰方法时,只要是访问该地址都会出现页面异常。修饰异常类时,方法中抛出该异常则会出发异常页面。
@ResponseStatus(reason = "测试", value = HttpStatus.NOT_FOUND)
@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
if (i == 13){
throw new UserNameNotMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver...");
return "success";
}
17.4 DefaultHandlerExceptionResolver
产生特殊异常时默认调用的异常解析器。
对一些特殊的异常进行处理,比如 HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException、
MissingPathVariableException、MissingServletRequestParameterException、ServletRequestBindingException 等。
17.5 SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
springmvc.xml
<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
其中,<property name=“exceptionAttribute” value=“ex”></property> 表示将设置异常的属性名,可在响应页面进行调用 ${requestScope.ex}
<property name="exceptionMappings">
<props>
<prop key="对应异常的全类名">转到的视图名</prop>
</props>
</property>