spring-mvc如何优雅的处理异常

目前正在学习spring mvc,遇到两个问题,在此请教各位大神:

1、异常处理部分一般通过实现 org.springframework.web.servlet.HandlerExceptionResolver 来统一处理,但是:

  • NoSuchRequestHandlingMethodException

  • HttpRequestMethodNotSupportedException

  • HttpMediaTypeNotSupportedException

  • HttpMediaTypeNotAcceptableException

  • MissingServletRequestParameterException

  • ServletRequestBindingException

  • ConversionNotSupportedException

  • TypeMismatchException

  • HttpMessageNotReadableException

  • HttpMessageNotWritableException

  • MethodArgumentNotValidException

  • MissingServletRequestPartException

  • BindException

  • NoHandlerFoundException

以上类型的异常会被 org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver 处理掉,但是返回了我不希望的结果。

clipboard.png

如图:由于 order 不够优先,提前弹出结果了!

请教下各位,这类问题是如何统一所有类型的异常的?目前我的理解是

  • 覆盖org.springframework.web.servlet.DispatcherServletprocessHandlerException

@Override
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
        throws Exception {

    int statusCode = 0;
    boolean found = true;

    try {
        if (ex instanceof NoSuchRequestHandlingMethodException) {
            statusCode = HttpServletResponse.SC_NOT_FOUND;
        } else if (ex instanceof HttpRequestMethodNotSupportedException) {
            statusCode = HttpServletResponse.SC_METHOD_NOT_ALLOWED;
        } else if (ex instanceof HttpMediaTypeNotSupportedException) {
            statusCode = HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
        } else if (ex instanceof HttpMediaTypeNotAcceptableException) {
            statusCode = HttpServletResponse.SC_NOT_ACCEPTABLE;
        } else if (ex instanceof MissingServletRequestParameterException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof ServletRequestBindingException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof ConversionNotSupportedException) {
            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
        } else if (ex instanceof TypeMismatchException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof HttpMessageNotReadableException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof HttpMessageNotWritableException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof MethodArgumentNotValidException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof MissingServletRequestPartException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof BindException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
        } else if (ex instanceof NoHandlerFoundException) {
            statusCode = HttpServletResponse.SC_NOT_FOUND;
        } else {
            found = false;
        }

        if (found) {
            ServiceException error = new ServiceException(statusCode, "Forbidden");
            error.setException(ex);

            ex = error;
        }
    } catch (Exception e) {

    }
    return super.processHandlerException(request, response, handler, ex);
}
  • 另一种方案是想办法提高自定义 HandlerExceptionResolver 的优先级,但是目前没有找到办法!

求助!


2、第二个问题,我希望对 JSON 请求返回JSON错误,例如:

{
    "status": 500,
    "statusInfo": "Internal Server Error",
    "data": {
        "type": "Exception",
        "message": "UserException"
    }
}

但是异常处理方法 resolveException(HttpServletRequest request, HttpServletResponse response, Object obj, Exception ex) 中无法确定该请求到底该由哪个 View 渲染啊

我的理解:

  • 通过 拦截器preHandle(HttpServletRequest, HttpServletResponse, Object) 将应该由哪个View渲染页面的实例,注入给 request 中,不知道各位大神觉得这个方法是否靠谱?


PS:Java初学者,大神勿喷

阅读 12.2k
2 个回答

@ControllerAdvice+@ExceptionHandler 解决你的第二个问题,第一个问题是代码设计上的问题,跟spring关系不大。

第一个问题找到方法了:

  • servlet-spring.xml 文件配置如下:

<bean class="org.springframework.web.servlet.handler.HandlerExceptionResolverComposite">
    <property name="order" value="0" />
    <property name="exceptionResolvers">
        <list>
            <bean class="io.conf.DefaultExceptionResolver">
                <property name="errorView" value="/common/error" />
                <property name="showErrorState" value="false" />
            </bean>
        </list>
    </property>
</bean>
  • 实现类核心代码如下

@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    if (ex == null) {
        return null;
    }
    ModelAndView mv;
    try {

        // 判断是不是异步请求
        if (WebUtils.hasResponseAnnotation(handler)) {
            mv = new ModelAndView(new JsonView());
            if (showErrorState) {
                response.sendError(500);
            }
        } else {
            mv = new ModelAndView(errorView);
        }

        int statusCode = 500;

        try {
            if (ex instanceof NoSuchRequestHandlingMethodException) {
                statusCode = HttpServletResponse.SC_NOT_FOUND;
            } else if (ex instanceof HttpRequestMethodNotSupportedException) {
                statusCode = HttpServletResponse.SC_METHOD_NOT_ALLOWED;
            } else if (ex instanceof HttpMediaTypeNotSupportedException) {
                statusCode = HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
            } else if (ex instanceof HttpMediaTypeNotAcceptableException) {
                statusCode = HttpServletResponse.SC_NOT_ACCEPTABLE;
            } else if (ex instanceof MissingServletRequestParameterException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof ServletRequestBindingException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof ConversionNotSupportedException) {
                statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
            } else if (ex instanceof TypeMismatchException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof HttpMessageNotReadableException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof HttpMessageNotWritableException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof MethodArgumentNotValidException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof MissingServletRequestPartException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof BindException) {
                statusCode = HttpServletResponse.SC_BAD_REQUEST;
            } else if (ex instanceof NoHandlerFoundException) {
                statusCode = HttpServletResponse.SC_NOT_FOUND;
            }
        } catch (Exception e) {

        }

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("message", ex.getMessage());
        data.put("type", ex.getClass().getSimpleName());

        mv.addObject("status", statusCode);
        mv.addObject("data", data);
        mv.addObject("statusInfo", ex.getLocalizedMessage());

        return mv;

    } catch (Exception e) {

    }

    return null;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进