通过实现HandlerExceptionResolver接口可以实现对处理的除理,但是还是会留掉一些异常如:RequestParam参数没有传导致的MissingServletRequestParameterException,http的方法有误导致的HttpRequestMethodNotSupportedException等等,这些异常不对被自己定义的HandlerExceptionResolver扑捉。
异常扑捉的关键点:
在DispatcherServlet.initHandlerExceptionResolvers()对异常处理类进行初始化并且排序
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// 从Spring容器中查找HandlerExceptionResolver的实现类
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
// 根据HandlerExceptionResolvers实现类的order排序,order越小排在越上面
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
...
}
默认的实现有三个类:ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver,对应的order分别0、1、2 我们自己实现HandlerExceptionResolver类对异常处理,如类名为GlobalExceptionResolver,如果不指定order,默认排序就排在最后,即:ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver、GlobalExceptionResolver。所以MissingServletRequestParameterException、HttpRequestMethodNotSupportedException等异常会被DefaultHandlerExceptionResolver扑捉。
重写DefaultHandlerExceptionResolver的异常处理方法
DefaultHandlerExceptionResolver默认实现了一些异常处理如:HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException等,详见:org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver的doResolveException方法,我们可以继承DefaultHandlerExceptionResolver并重写它的方法。
public class SampleDefaultHandlerExceptionResolver extends DefaultHandlerExceptionResolver {
/**
* 重写默认的MissingServletRequestParameterException异常的处理方法
*
* @return
* @throws IOException
*/
@Override
protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
HttpServletRequest request,
HttpServletResponse response,
@Nullable Object handler) throws IOException {
if (handler instanceof HandlerMethod) {
return buildJsonResponse(request, response, (HandlerMethod) handler, ex);
}
return super.handleMissingServletRequestParameter(ex, request, response, handler);
}
/**
* 构建JSON数据
*
* @return
*/
private ModelAndView buildJsonResponse(HttpServletRequest request,
HttpServletResponse response,
HandlerMethod handlerMethod,
Exception ex) {
BaseResponse baseResponse = new BaseResponse().setCode("10").setMessage(ex.getMessage());
// 使用jackson,也可以换成fastjson
ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
modelAndView.addObject("result", baseResponse);
return modelAndView;
}
}
被Spring管理并且设置它的order
<bean id="sampleDefaultHandlerExceptionResolver" class="com.zmx.SampleDefaultHandlerExceptionResolver">
<property name="order" value="0"/>
</bean>
也可以让自定义的异常处理类GlobalExceptionResolver继承DefaultHandlerExceptionResolver,重写需要处理的异常,并且设置order属性
public class GlobalExceptionResolver extends DefaultHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object o,
Exception e) {
if (o instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) o;
log.error("异常#Controller={},Method={}", handlerMethod.getBean(), handlerMethod.getMethod().getName(), e);
// todo 判断属于Ajax的请求还是普通的页面请求
if (isAsyncRequest(request, handlerMethod)) {
// 返回JSON格式数据
return buildJsonResponse(request, response, handlerMethod, e);
} else {
// 返回重定向页面
return buildViewResponse(request, response, handlerMethod, e);
}
}
return null;
}
....
/**
* 重写默认的MissingServletRequestParameterException异常的处理方法
*
* @return
* @throws IOException
*/
@Override
protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
HttpServletRequest request,
HttpServletResponse response,
@Nullable Object handler) throws IOException {
return this.resolveException(request, response, handler, ex);
}
}
<bean id="globalExceptionResolver" class="com.zmx.GlobalExceptionResolver">
<property name="order" value="0"></property>
</bean>
这样也可以被我们自己的异常处理类扑捉
网友评论