休息服务中的 Spring Boot 自定义异常

2022-09-04 07:32:30

我已经在基于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;
    }
}

和自定义服务例外情况:

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"
}

但字段错误代码未显示在 JSON 响应中。

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


答案 1

Spring Boot 使用 ErrorAttributes 的实现来填充呈现为 JSON 的。默认情况下,使用 DefaultErrorAttributes 的实例。若要包含自定义,需要提供了解其错误代码的自定义实现。此自定义实现应为配置中的 a。MaperrorCodeErrorAttributesServiceException@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;
        }

    };
}

答案 2

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

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

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;
    }
  }
 }

推荐