Spring MVC通过HandlerExceptionResolver处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。
Spring MVC提供HandlerExceptionResolver的实现类。
DispatcherServlet默认装配HandlerExceptionResolver。没有使用<mvc:annotation-driven/>配置:
- AnnotationMethodHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
使用了<mvc:annotation-driven/>配置
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
ExceptionHandlerExceptionResolver
主要处理Handler中用@ExceptionHandler注解定义的方法。@ExceptionHandler方法的入参中可以加入Exception类型的参数,该参数即对应发生的异常对象。
示例
- 首先我们要先写页面
<a href="testExceptionHandlerExceptionResolver?i=0">
Test ExceptionHandlerExceptionResolver
</a>
- 之后是Java代码
@RequestMapping("testExceptionHandlerExceptionResolver")
public String testExceptionHandlerExceptionResolver(@RequestParam("i")
int i){
System.out.println("Number " + (10/i));
return "success";
}
- 我们知道0是不能作为除数的,因此该程序必然抛出异常。之后我们就要捕获这个异常就需要用到ExceptionHandler。
@ExceptionHandler({ArithmeticException.class})
public String handleArithmeticException(Exception ex){
System.out.println("Exception: " + ex);
return "error";
}
- 此时又有一个问题,我们如何将该异常显示在页面上。@ExceptionHandler方法的入参中不能传入Map,若希望将异常信息传导到页面上,需要使用ModelAndView作为返回值。
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex){
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
- 之后是修改异常页面
<body>
<h4>Error Page</h4>
<br><br>
${exception }
</body>
@ExceptionHandler标记的方法有优先级的问题。假设@ExceptionHandler中定义了两个异常。程序一旦发现异常,则程序会寻找最为接近的异常并将其抛出。
@ControllerAdvice:如果在当前Handler中找不到@ExceptionHandler方法来处理当前方法出现的异常,则将去@ControllerAdvice的类中查找@ExceptionHandler标记的方法来处理异常。例如:
@ControllerAdvice
public class HandleException {
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex){
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
}
ResponseStatusExceptionResolver
- 首先我们先自定义一个异常类:
@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="Username does not match password.")
public class UsernameMatchPasswordException extends RuntimeException{
private static final long serialVersionUID = 1L;
}
注意:这里我们使用了@ResponseStatus注解,其中有两个参数。value代表Http返回码,reason注明请求失败的原因。
- 之后我们编写测试代码:
@RequestMapping("testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
if(i == 13){
throw new UsernameMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver...");
return "success";
}
在i等于13的时候抛出我们刚刚定义的异常。并返回请求失败的页面。
- 我们也可以在测试方法上定义@ResponseStatus注解。这样不论i等于多少最后都会返回注解指定的状态。
@ResponseStatus(reason="Testing...", value=HttpStatus.NOT_FOUND)
@RequestMapping("testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
if(i == 13){
throw new UsernameMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver...");
return "success";
}
DefaultHandlerExceptionResolver
对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException, HttpRequestMethodNotSupportedException, HttpMediaTypeNotSupportedException, HttpMediaTypeNotAcceptableException等。
SimpleMappingExceptionResolver
如果希望对所有的异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
我们现在要创建一个异常的请求,如下代码所示:
@RequestMapping("testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
String [] vals = new String[10];
System.out.println(vals[i]);
return "success";
}
我们发出如下的请求
<a href="testSimpleMappingExceptionResolver?i=10">Test SimpleMappingExceptionResolver</a>
由于数组的上限是9,,10肯定是越界的了。此时后台必然发出java.lang.ArrayIndexOutOfBoundsException异常。
此时我们需要在配置文件中进行配置,跳转到我们希望显示的错误界面中。
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
此时异常会抛出到error界面。
网友评论