【问题标题】:Spring Boot custom exception within an Rest ServiceRest Service 中的 Spring Boot 自定义异常
【发布时间】:2014-12-16 11:51:31
【问题描述】:

我在基于 Spring Boot 的 Rest 服务中定义了一个全局异常处理:

@ControllerAdvice
public class GlobalExceptionController {

    private final Logger LOG = LoggerFactory.getLogger(getClass());

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Internal application error")
    @ExceptionHandler({ServiceException.class})
    @ResponseBody
    public ServiceException serviceError(ServiceException e) {
        LOG.error("{}: {}", e.getErrorCode(), e.getMessage());
        return e;
    }
}

还有一个自定义的 ServiceException:

public class ServiceException extends RuntimeException {

    private static final long serialVersionUID = -6502596312985405760L;

    private String errorCode;

    public ServiceException(String message, String errorCode, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }

    // other constructors, getter and setters omitted
}

到目前为止一切顺利,当触发异常时,控制器会正常工作并响应:

{
   "timestamp": 1413883870237,
   "status": 500,
   "error": "Internal Server Error",
   "exception": "org.example.ServiceException",
   "message": "somthing goes wrong",
   "path": "/index"
}

errorCode 字段未显示在 JSON 响应中。

那么如何在我的应用程序中定义自定义异常响应。

【问题讨论】:

    标签: java rest exception-handling spring-boot


    【解决方案1】:

    Spring Boot 使用 ErrorAttributes 的实现来填充呈现为 JSON 的 Map。默认情况下,使用DefaultErrorAttributes 的实例。要包含您的自定义errorCode,您需要提供一个自定义ErrorAttributes 实现,该实现知道ServiceException 及其错误代码。此自定义实现应为您的配置中的 @Bean

    一种方法是子类DefaultErrorAttributes

    @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);
                Throwable error = getError(requestAttributes);
                if (error instanceof ServiceException) {
                    errorAttributes.put("errorCode", ((ServiceException)error).getErrorCode());
                }
                return errorAttributes;
            }
    
        };
    }
    

    【讨论】:

    • 嗨,Andy,这里如果自定义异常类扩展为 Exception 或 Throwable 那么错误实例将是 UnhandledThrowException 为什么会发生。
    • @KSK 我不清楚这与这个问题的答案有什么关系。我认为您最好提出一个新问题,并提供更多详细信息
    【解决方案2】:

    @Alex 可以使用注解@ExceptionHandler(YourExceptionClass.class) 来处理特定RestController 中的特定异常。我认为这是处理业务应用程序中复杂场景的更好方法。此外,我建议您使用自定义异常翻译器来处理不同类型的异常。您可以将spring oauth2 exception translator 视为异常翻译器的参考代码。

    注意:以下代码仅用于理解此解决方案的概念。它不是生产就绪的代码。随意讨论更多关于它的信息。

    import org.springframework.http.MediaType;
    import org.springframework.web.bind.annotation.*;
    
    /**
    * @author Harpreet
    * @since 16-Aug-17.
    */
    @RestController
    public class RestTestController {
    
    @RequestMapping(value = "name", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public ResponseObject name(@RequestParam(value="name") String value){
        //your custom logic 
        if (value == null || value.length() < 2) {
            //throwing exception to invoke customExceptionHandler
            throw new NullPointerException("value of request_param:name is invalid");
        }
        ResponseObject responseObject = new ResponseObject();
        responseObject.setMessage(value)
                .setErrorCode(1);
        return responseObject;
    }
    
    // to handle null pointer exception
    @ExceptionHandler(NullPointerException.class)
    public ResponseObject customExceptionHandler
            (NullPointerException e) {
        ResponseObject responseObject = new ResponseObject();
        responseObject.setMessage(e.getMessage())
                .setErrorCode(-1);
        return responseObject;
    }
    
    // response data transfer class
    static class ResponseObject{
        String message;
        Integer errorCode;
    
        public String getMessage() {
            return message;
        }
    
        public ResponseObject setMessage(String message) {
            this.message = message;
            return this;
        }
    
        public Integer getErrorCode() {
            return errorCode;
        }
    
        public ResponseObject setErrorCode(Integer errorCode) {
            this.errorCode = errorCode;
            return this;
        }
      }
     }
    

    【讨论】:

    • 我认为我更喜欢这种方法,而不是在全球范围内重新定义ErrorAttributes。虽然我认为理想情况下还是应该利用全局ErrorAttributes来获取默认属性,然后再放入额外的值。
    • @M.普罗霍罗夫同意,这将使它更强大的方法
    • @HarpreetSandhu-TheCoder 当我尝试从 java 程序访问它时,它返回错误代码,但不返回错误消息。即,它返回错误代码为 404,但在响应对象中的任何位置都找不到该消息。
    • @kingkari 你想用java程序访问什么?你能详细说明你的问题吗?
    猜你喜欢
    • 2019-12-12
    • 2016-10-31
    • 2019-12-10
    • 1970-01-01
    • 2021-07-10
    • 2016-07-11
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    相关资源
    最近更新 更多