通常SpringMVC对异常的配置都是返回某个jsp视图给用户,但是通过ajax方式发起请求,即使发生异常,前台也无法获得任何异常提示信息。因此需要对异常进行统一的处理,对于普通请求以及ajax请求的异常都有效。
1.Spring MVC的异常处理机制
Spring MVC 通过HandlerExceptionResolver处理程序的异常,包括处理器映射,数据绑定以及处理器执行时发生的异常。HandlerExceptionResolver仅有一个接口方法:
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
当发生异常时,Spring MVC将调用resolveException()方法,并转到ModelAndView对应的视图,作为一个异常报告页面反馈给用户。
HandlerExceptionResolver拥有4个实现类,分别是
DefaultHandlerExceptionResolver,
AnnotationMethodExceptionResolver,
ResponseStatusExceptionResolver,
SimpleMappingExceptionResolver.
(1)DefaultHandlerExceptionResolver
Spring MVC默认装配了DefaultHandlerExceptionResolver,它会将Spring MVC框架的异常转换为相应的响应状态码。响应状态码如下:
500:Web服务内部错误
406:无和请求accept匹配的MIME类型
415:不支持的MIME类型
400:坏的请求
405:不支持的请求方法
404:找不到匹配的资源。
可以在web.xml中通过如下配置为响应状态码配置一个对应的页面:
1: <error>
2: <error-code>404</error-code>
3: <location>/404.htm</location>
4: <error-page>
(2)AnnotationMethodHandlerExceptionResolver
Spring MVC已经默认注册了AnnotationMethodHandlerExceptionResolver,它允许通过@ExceptionHandler的注解支持处理特定异常的方法。
1: @Controller
2: public class UserController{
3:
4: @RequestMapping("/throwException")
5: public String throwException(){
6: if (2 > 1) {
7: throw new RuntimeException("ddd")
8: }
9: return "/success";
10: }
11:
12: @ExceptionHandler(RuntimeException.class)
13: public String handlerException(RuntimeException ex,HttpServletRequest request){
14: return "forward:/error.jsp";
15: }
16: }
当调用throwException方法时,会抛出RuntimeException,它会被出于同一个处理器类中的handlerException()方法捕获。@ExceptionHandler可以指定多个异常,但是标注@ExceptionHandler的异常处理方法只能对同一个处理器类中的其他方法进行异常响应处理。
(3)ResponseStatusHandlerExceptionResolver
ResponseStatusHandlerExceptionResolver和AnnotationMethodHandlerExceptionResolver类似,可以通过@ResponseStatus注解标注一个方法,用于处理特定类型的响应状态码。
(4)SimpleMappingHandlerExceptionResolver
SimpleMappingHandlerExceptionResolver将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
1: <bean id="exceptionResolver"
2: class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
3: <property name="exceptionMappings">
4: <props>
5: <prop key="com.wbl.modal.exception.NoPermissionException">/error</prop>
6: <prop key="com.wbl.modal.exception.NotLoginException">/login</prop>
7: </props>
8: </property>
9: <property name="exceptionAttribute" value="ex"></property>
10: </bean>
我们指定当发生NotLoginException异常,使用login视图进行显示,即用户未登陆时,让用户到登陆页面进行登陆。
2.Spring MVC 的异常统一处理
为了能够对异常进行统一的处理,包括普通请求发生异常以及ajax请求发生异常时,我们可以覆写SimpleMappingHandlerExceptionResolver中的doResolveException()方法,判断是普通请求还是ajax请求。
1: package com.wbl.modal.exception;
2:
3: import org.springframework.web.servlet.ModelAndView;
4: import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
5:
6: import javax.servlet.http.HttpServletRequest;
7: import javax.servlet.http.HttpServletResponse;
8: import java.io.IOException;
9: import java.io.PrintWriter;
10:
11: /**
12: * Created by Simple_love on 2015/9/10.
13: */
14: public class GlobalExceptionResolver extends SimpleMappingExceptionResolver {
15:
16: @Override
17: protected ModelAndView doResolveException(HttpServletRequest request,
18: HttpServletResponse response, Object handler, Exception ex){
19: String viewName = determineViewName(ex,request);
20: response.setCharacterEncoding("UTF-8");
21: if (viewName != null) {// JSP格式返回
22: if (!(request.getHeader("accept").contains("application/json") || (request.getHeader("X-Requested-With")!= null && request
23: .getHeader("X-Requested-With").contains("XMLHttpRequest") ))) {
24: // 如果不是异步请求
25: // Apply HTTP status code for error views, if specified.
26: // Only apply it if we‘re processing a top-level request.
27: Integer statusCode = determineStatusCode(request, viewName);
28: if (statusCode != null) {
29: applyStatusCodeIfPossible(request, response, statusCode);
30: }
31: System.out.println("JSP格式返回" + viewName);
32: return getModelAndView(viewName, ex, request);
33: } else {// JSON格式返回
34: try {
35: PrintWriter writer = response.getWriter();
36: writer.write(ex.getMessage());
37: writer.flush();
38: } catch (IOException e) {
39: e.printStackTrace();
40: }
41: System.out.println("JSON格式返回" + viewName);
42: return null;
43: }
44: } else {
45: return null;
46: }
47: }
48: }
如果是普通请求则返回对应的视图,如果是ajax请求,则返回抛出的异常信息。