问题:
已经自定义了异常处理类(如:MyExceptionResolver),但是程序出错后没有进入自定义的异常处理,而是显示其他错误(如:http 400)。
原因:
默认情况下,Spring MVC会事前注入3个HandlerExceptionResolver如下:
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
这时会按顺序调用HandlerExceptionResolver处理能够处理的异常,如果没有处理就返回null,这时会继续调用下一个,如果其中一个返回了ModelAndView则后面的将不会再调用:
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
解决方法:
调整HandlerExceptionResolver执行顺序,可以通过实现接口org.springframework.core.Ordered 来解决。
默认的三个Order为Integer.MAX_VALUE,所以我们只有比它小就可以了如Integer.MIN_VALUE。springMVC中有三种自定义处理异常方式,参见我的博客《springMVC三种异常处理方式》,下面针对三种情况分别给出方案。
(1)SimpleMappingExceptionResolver方式<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<property name="defaultErrorView" value="error">
</property>
<property name="order" value="0" />
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 -->
<property name="exceptionMappings">
<props>
<prop key="etc.exception.MyException">error-my</prop>
<!-- 这里还可以继续扩展对不同异常类型的处理 -->
</props>
</property>
</bean>
(2)@ExceptionHandler方式
//使用@ExceptionHandler进行处理有一个缺点就是进行异常处理的方法必须与出错的方法在同一个Controller里面
@ExceptionHandler(Exception.class)
@Order(value=1)
public ModelAndView resolveException(Exception ex){
Map<String,Exception> map = new HashMap<String,Exception>();
map.put("ex", ex);
//根据获取的Exception参数进行不同View的跳转
if (ex instanceof MyException) {
return new ModelAndView("error-my",map);
}else{
return new ModelAndView("error",map);
}
}
(3)HandlerExceptionResolver方式
public class MyExceptionHandler implements HandlerExceptionResolver,Ordered{
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
Map<String,Exception> map = new HashMap<String,Exception>();
map.put("ex", ex);
//根据获取的Exception参数进行不同View的跳转
if (ex instanceof MyException) {
return new ModelAndView("error-my",map);
}else{
return new ModelAndView("error",map);
}
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return Ordered.HIGHEST_PRECEDENCE;
}
}