美文网首页
SpringMVC-异常处理(二)

SpringMVC-异常处理(二)

作者: 张明学 | 来源:发表于2020-08-03 22:58 被阅读0次

通过实现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>

这样也可以被我们自己的异常处理类扑捉

相关文章

网友评论

      本文标题:SpringMVC-异常处理(二)

      本文链接:https://www.haomeiwen.com/subject/wbvsrktx.html