美文网首页
Spring MVC异常处理中抛出新异常的处理

Spring MVC异常处理中抛出新异常的处理

作者: ilaoke | 来源:发表于2018-07-12 15:18 被阅读181次

    项目中使用了全局异常处理,如下

    @ControllerAdvice
    public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
    
        public static final String RESPONSE_ERROR = "Error";
    
        @Autowired
        MailPublisher mailPublisher;
    
        /**
         * Exception handler
         *
         * @param ex
         * @param request
         * @return
         */
        @ExceptionHandler(value = {Exception.class})
        public ResponseEntity<String> handleExceptions(Exception ex, WebRequest request) {
            logger.error("Exception", ex);
            // Send email to administrator 如果这里出现异常呢?
            mailPublisher.publishMailToAdministrator(ex);
            return handleExceptionInternal(ex, RESPONSE_ERROR, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
        }
    }
    
    

    但是如果异常处理中抛出了新的异常呢?这样就会导致返回的response不是我们定义的RESPONSE_ERROR字符串常量,而是默认的JSON格式:

    {
        "timestamp": 1531362962859,
        "status": 500,
        "error": "Internal Server Error",
        "message": "test exception",
        "path": "/app/test"
    }
    

    或者如果我们还保持这种格式,但是想添加一些字段呢

    这两个问题是相关的,解决了问题2也就解决了问题1,那先看问题2。默认的error处理在BasicErrorController,默认异常URL是“/error”,这里有针对html和json的处理,如果需要其他响应格式的,比如plain/text,可以自己写个ErrorController。

    /**
     * Basic global error {@link Controller}, rendering {@link ErrorAttributes}. More specific
     * errors can be handled either using Spring MVC abstractions (e.g.
     * {@code @ExceptionHandler}) or by adding servlet
     * {@link AbstractServletWebServerFactory#setErrorPages server error pages}.
     *
     * @author Dave Syer
     * @author Phillip Webb
     * @author Michael Stummvoll
     * @author Stephane Nicoll
     * @see ErrorAttributes
     * @see ErrorProperties
     */
    @Controller
    @RequestMapping("${server.error.path:${error.path:/error}}")
    public class BasicErrorController extends AbstractErrorController {
    
        @RequestMapping(produces = "text/html")
        public ModelAndView errorHtml(HttpServletRequest request,
                HttpServletResponse response) {
            HttpStatus status = getStatus(request);
            Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
                    request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
            response.setStatus(status.value());
            ModelAndView modelAndView = resolveErrorView(request, response, status, model);
            return (modelAndView != null ? modelAndView : new ModelAndView("error", model));
        }
    
        @RequestMapping
        @ResponseBody
        public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
            Map<String, Object> body = getErrorAttributes(request,
                    isIncludeStackTrace(request, MediaType.ALL));
            HttpStatus status = getStatus(request);
            return new ResponseEntity<>(body, status);
        }
    
    }
    
    

    我们可以自己写个ErrorController来替换默认BasicErrorController来自定义响应内容:

    @Controller
    public class AppErrorController implements ErrorController {
    
        @Override
        public String getErrorPath() {
            return "/error";
        }
    
        @RequestMapping("/error")
        public ResponseEntity<String> handleError(HttpServletRequest request) {
            Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
            HttpStatus httpStatus;
    
            if (status != null) {
                Integer statusCode = Integer.valueOf(status.toString());
                httpStatus = HttpStatus.valueOf(statusCode);
            } else {
                httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            }
            return new ResponseEntity<>(RESPONSE_ERROR, httpStatus);
        }
    }
    

    或者在配置类中自定义 ErrorAttributes ,添加自定义字段,默认返回的JSON中就会有自定义的字段。

        @Bean
        public ErrorAttributes errorAttributes() {
            return new DefaultErrorAttributes() {
                @Override
                public Map<String, Object> getErrorAttributes(
                        RequestAttributes requestAttributes,
                        boolean includeStackTrace) {
                    Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
                    Object errorMessage = requestAttributes.getAttribute(RequestDispatcher.ERROR_MESSAGE, RequestAttributes.SCOPE_REQUEST);
                    if (errorMessage != null) {
                        errorAttributes.put("message", errorMessage);
                    }
                    return errorAttributes;
                }
            };
        }
    

    针对问题1,除了自定义ErrorController外,还可以在异常处理中添加try-catch来处理。

    参考:

    https://blog.jdriven.com/2016/06/spicy-spring-custom-error-json-response-with-errorattributes/

    https://github.com/spring-projects/spring-boot/issues/1731

    相关文章

      网友评论

          本文标题:Spring MVC异常处理中抛出新异常的处理

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