首页 > 解决方案 > @RestControllerAdvice 在 Spring Boot 反应式 Java 应用程序中不起作用

问题描述

我目前正在抛出一个自定义异常 - RequestValidationException

ExceptionHandler

@RestControllerAdvice
@Slf4j
public class RestExceptionHandler {

    @ExceptionHandler(value = RequestValidationException.class)
    @ResponseStatus(HttpStatus.PRECONDITION_FAILED)
    public Mono<HttpValidationError> handleRequestValidationException(RequestValidationException exception) {
        log.error("Received exception: ", exception);
        List<String> loc = new ArrayList<>();
        loc.add(exception.getMessage());
        ValidationError validationError = ValidationError.builder()
            .loc(loc)
            .msg(exception.getMessage())
            .build();
        List<ValidationError> errorMessages = new ArrayList<>();
        errorMessages.add(validationError);
        return Mono.just(HttpValidationError.builder().detail(errorMessages).build());
}

RequestValidationException

public class RequestValidationException extends RuntimeException {
    public static final HttpStatus statusCode = HttpStatus.PRECONDITION_FAILED;

    public RequestValidationException(String text) {
        super(text);
    }

    public HttpStatus getStatusCode() {
        return statusCode;
    }
}

exception被抛出时,我想要以下内容response

 Code: 412
 {
    "detail": [
    {
       "loc": [
                "No ID found to update. Please add an ID"
       ],
       "msg": "No ID found to update. Please add an ID",
       "type": null
    }
  ]
}  

我收到的是:

{
  "error_code": 500,
  "message": "No ID found to update. Please add an ID"
}

我检查了应用程序日志,没有任何地方RestExceptionHandler被调用。它只是记录这个error

"level":"ERROR","logger":"c.a.c.c.c.AbstractController","thread":"boundedElastic-1","message":"Controller exception","stack":"<#384d845f> c.a.c.a.e.RequestValidationException

我似乎无法弄清楚这段代码有什么问题。有人可以指出我可能缺少什么吗?谢谢。

标签: javaspring-bootexception

解决方案


我只能通过以下实现来实现AbstractErrorWebExceptionHandler它(对于 kotlin 代码感到抱歉):

@Component
@Order(-2)
class GlobalExceptionHandler(errorAttributes: ErrorAttributes,
                             resources: WebProperties.Resources,
                             applicationContext: ApplicationContext,
                             serverCodecConfigurer: ServerCodecConfigurer) : AbstractErrorWebExceptionHandler(errorAttributes, resources, applicationContext) {

    companion object {
        private val logger = KotlinLogging.logger {}
        private const val HTTP_STATUS_KEY = "status"
        private const val MESSAGE_KEY = "message"
        private const val ERRORS_KEY = "errors"
    }

    init {
        setMessageWriters(serverCodecConfigurer.writers)
    }

    override fun setMessageWriters(messageWriters: MutableList<HttpMessageWriter<*>>?) {
        super.setMessageWriters(messageWriters)
    }

    override fun getRoutingFunction(errorAttributes: ErrorAttributes?): RouterFunction<ServerResponse> {
        return RouterFunctions.route({ true }) { request ->
            val error: Throwable = getError(request)
            logger.error("Handling: ", error)

            val errorProperties = getErrorAttributes(request, ErrorAttributeOptions.defaults())
            when (error) {
                is WebExchangeBindException -> {
                    ....
                }
                else -> {
                    ...
                }
            }

            ServerResponse.status(HttpStatus.valueOf(errorProperties[HTTP_STATUS_KEY] as Int))
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(errorProperties)
        }
    }
}

在 Java 中会是这样的:

@Component
@Order(-2)
public class GlobalExceptionHandler extends AbstractErrorWebExceptionHandler {

   private static final String HTTP_STATUS_KEY = "status";
   private static final String MESSAGE_KEY = "message";
   private static final String ERRORS_KEY = "errors"; 

   public GlobalExceptionHandler(ErrorAttributes errorAttributes, Resources resources, ApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer) {
      super(errorAttributes, resources, applicationContext);
      this.setMessageWriters(serverCodecConfigurer.getWriters());
   }

   public final void setMessageWriters(List messageWriters) {
      super.setMessageWriters(messageWriters);
   }

   protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
      return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
   }

   private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
       Map<String, Object> errorPropertiesMap = getErrorAttributes(request, 
         ErrorAttributeOptions.defaults());

       return ServerResponse.status(HttpStatus.BAD_REQUEST)
         .contentType(MediaType.APPLICATION_JSON)
         .body(BodyInserters.fromValue(errorPropertiesMap));
    }
}

您可以在https://www.baeldung.com/spring-webflux-errors#global查看更多详细信息。


推荐阅读