4

寻找更好的解决方案来处理 micronaut 中的全局异常https://docs.micronaut.io/latest/guide/index.html#errorHandling

控制器

@Controller("/category")
public class CategoryController {
@Delete(uri = "/{id}")
public Maybe<HttpResponse> delete(@NotBlank String id) {
            LOG.info(String.format("API --> Deleting the specified category"));
            return iCategoryManager.Count(id).flatMap(item -> {
                if (item > 0) {
                    iCategoryManager.Delete(id).subscribe();
                    return Maybe.just(HttpResponse.noContent());
                } else
                    return Maybe.just(HttpResponse.notFound());
            });
    }
}

iCategoryManager.Count(id)导致如下异常,如何在GlobalExceptionHandler上捕获异常

io.micronaut.core.serialize.exceptions.SerializationException: Incorrect message body size to deserialize to a Long
    at io.micronaut.rabbitmq.serdes.JavaLangRabbitMessageSerDes$LongSerDes.deserialize(JavaLangRabbitMessageSerDes.java:314)
    at io.micronaut.rabbitmq.serdes.JavaLangRabbitMessageSerDes$LongSerDes.deserialize(JavaLangRabbitMessageSerDes.java:306)
    at io.micronaut.rabbitmq.serdes.JavaLangRabbitMessageSerDes.deserialize(JavaLangRabbitMessageSerDes.java:81)
    at io.micronaut.rabbitmq.intercept.RabbitMQIntroductionAdvice.deserialize(RabbitMQIntroductionAdvice.java:323)
    at io.micronaut.rabbitmq.intercept.RabbitMQIntroductionAdvice.lambda$intercept$22(RabbitMQIntroductionAdvice.java:268)
    at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:132)
    at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
    at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutSubscriber.onNext(FlowableTimeoutTimed.java:101)
    at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
    at io.reactivex.internal.subscriptions.DeferredScalarSubscription.complete(DeferredScalarSubscription.java:132)
    at io.reactivex.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onSuccess(SingleToFlowable.java:62)
    at io.micronaut.reactive.rxjava2.RxInstrumentedSingleObserver.onSuccess(RxInstrumentedSingleObserver.java:65)
    at io.reactivex.internal.operators.single.SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver.onSuccess(SingleFlatMap.java:111)
    at io.micronaut.reactive.rxjava2.RxInstrumentedSingleObserver.onSuccess(RxInstrumentedSingleObserver.java:65)
    at io.reactivex.internal.operators.single.SingleDoFinally$DoFinallyObserver.onSuccess(SingleDoFinally.java:73)
    at io.micronaut.reactive.rxjava2.RxInstrumentedSingleObserver.onSuccess(RxInstrumentedSingleObserver.java:65)
    at io.reactivex.internal.operators.single.SingleCreate$Emitter.onSuccess(SingleCreate.java:67)
    at io.micronaut.rabbitmq.reactive.RxJavaReactivePublisher$3.handleDelivery(RxJavaReactivePublisher.java:324)
    at com.rabbitmq.client.impl.ConsumerDispatcher$5.run(ConsumerDispatcher.java:149)
    at com.rabbitmq.client.impl.ConsumerWorkService$WorkPoolRunnable.run(ConsumerWorkService.java:104)

全局异常处理

@Produces
@Singleton
@Requires(classes = {GlobalException.class, ExceptionHandler.class})
public class GlobalExceptionHandler implements ExceptionHandler<GlobalException, HttpResponse> {

    @Override
    public HttpResponse handle(HttpRequest request, GlobalException exception) {
        return HttpResponse.ok(0);
    }
}

public class GlobalException extends RuntimeException{
}

如何挂钩 GlobalExceptionHandler。应用程序上发生的任何异常都应在GlobalExceptionHandler中捕获

4

3 回答 3

2

当服务器上发生异常时,会ExceptionHandler在 bean 上下文中查找与抛出的异常最匹配的(通过处理程序的类型参数)。要处理所有异常,需要替换所有提供的异常处理程序。大约有十几个。

一种选择是替换默认的错误响应处理器。例如,这就是身体成为 HATEOS 的原因。有关详细信息,请参阅有关错误处理的文档。

于 2021-07-12T14:21:29.267 回答
1

我们可以import io.micronaut.http.server.exceptions.ExceptionHandler 用于全局错误处理。

创建错误消息:

public class ErrorMessage {

    private String message;
    private Boolean status;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

}

创建自定义异常:

import java.io.Serializable;

public class CustomException extends RuntimeException 
    implements Serializable {

    private static final long serialVersionUID = 1L;

    public CustomException() {
    }

    public CustomException(String message) {
        super(message);
    }

    public CustomException(String message, Throwable cause) {
        super(message, cause);
    }

    public CustomException(Throwable cause) {
        super(cause);
    }

    public CustomException(String message, Throwable cause, 
    boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

创建自定义异常处理程序:

import io.micronaut.context.annotation.Requires;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.server.exceptions.ExceptionHandler;
import jakarta.inject.Singleton;

@Produces
@Singleton
@Requires(classes = { CustomException.class, ExceptionHandler.class })

public class CustomExceptionHandler 
    implements ExceptionHandler<CustomException, HttpResponse<ErrorMessage>> {

    @Override
    public HttpResponse<ErrorMessage> 
        handle(HttpRequest request, CustomException exception) {

        ErrorMessage message = new ErrorMessage();
        message.setMessage(exception.getMessage());
        message.setStatus(false);
        return HttpResponse.serverError(message).
                status(HttpStatus.BAD_REQUEST);
    }

}

演示控制器:

import com.knf.dev.demo.data.UserData;
import com.knf.dev.demo.exception.CustomException;
import com.knf.dev.demo.model.User;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller
public class UserController {

    protected final UserData userData;

    public UserController(UserData userData) {
        this.userData = userData;
    }

    @Get("/users/{id}")
    public User findUserById(String id) throws CustomException {
        Long user_id = null;
        try {
            user_id = Long.parseLong(id);
        } catch (NumberFormatException e) {
            throw new CustomException("User Id must be numeric");
        }
        User user = userData.getUserById(user_id);
        if (user == null) {
            throw new CustomException("Entity Not Found");
        }
        return user;
    }
}

验证 REST API

案例 1:无效请求(未找到实体): 在此处输入图像描述

案例 2:无效请求(用户 ID 必须为数字):

在此处输入图像描述

案例3:有效请求: 在此处输入图像描述

于 2021-10-30T09:16:48.250 回答
1

这个解决方案对我有用

@Produces
@Singleton
@Requires(classes = {GlobalException.class, ExceptionHandler.class})
public class GlobalExceptionHandler implements ExceptionHandler<GlobalException, HttpResponse> {
    private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Override
    public HttpResponse handle(HttpRequest request, GlobalException exception) {
        LOG.error(exception.getLocalizedMessage());
        LOG.error(exception.getCause().getMessage());
        Arrays.stream(exception.getStackTrace()).forEach(item ->  LOG.error(item.toString()));
        return HttpResponse.serverError(exception.getLocalizedMessage());
    }
}

public class GlobalException extends RuntimeException{
    public GlobalException(Throwable throwable){super(throwable);}
}

控制器

  public Maybe<FindProductCommand> get(ProductSearchCriteriaCommand searchCriteria) {
        LOG.info("Controller --> Finding all the products");
        return iProductManager.find(searchCriteria)
                .onErrorResumeNext(throwable ->  { return Maybe.error(new GlobalException(throwable));});
    }

使用 Micronaut 3 和项目反应堆进行更新

@Override
@SingleResult
public Flux<List<FindProductCommand>> freeTextSearch(String text) {
    LOG.info("Controller --> Finding all the products");
    return iProductManager.findFreeText(text)
            .onErrorMap(throwable -> {
                throw new GlobalException(throwable);
            });
}
于 2021-07-13T17:55:45.250 回答