java - @RestControllerAdvice 在 Spring Boot 响应式 Java 应用程序中不起作用

标签 java spring-boot exception

我目前正在抛出自定义异常 - 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;
    }
}

当抛出异常时,我想要以下响应:

 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。它只是记录这个错误:

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

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

最佳答案

我只能让它与 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 查看更多详细信息.

关于java - @RestControllerAdvice 在 Spring Boot 响应式 Java 应用程序中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69725835/

相关文章:

java - 为 Eclipse 本身(平台)启用控制台日志记录

java - Android OnClickListener 更新同一 ListView 行中的文本

java - 毕加索 - 目标不能为空

java - 如何使用 Mockito 监视具有注释的类?

java - ServletRegistrationBean 是否为每个注册的子 WebApplicationContext 使用不同的类加载器

java - 将 Spring Cloud 负载均衡与 KeycloakRestTemplate 集成

java - 关闭 Spring Boot 应用程序时无法取消注册 DataSource JMX MBean

java - Java/Android 中的 Firebase : The transaction was overridden by a subsequent set

c# - 集合被修改;枚举操作不能在 ArrayList 中执行

swift - “ fatal error :在展开可选值时意外发现nil”是什么意思?