简体   繁体   English

如何将 CustomException 从响应式服务抛出到 controller?

[英]How throws CustomException from reactive service to controller?

I am receiving a request in a 0. RestController and give it to the service for processing.我在RestController中收到一个请求并将其交给服务进行处理。 If service doesnt throw exception , i just return HttpStatus.200 , but if an exception occurs in the service, i need catch it in controller and return the status depending on the exception.如果服务没有抛出exception ,我只返回HttpStatus.200 ,但是如果服务中发生异常,我需要在 controller 中捕获它并根据异常返回状态。 Inside service, i need to use Mono.fromCallable for repo access.在服务内部,我需要使用Mono.fromCallable进行回购访问。 Well, if user not found, i try throw my CustomException , but i cant cach it in controller.好吧,如果找不到用户,我尝试抛出我的CustomException ,但我无法在 controller 中缓存它。 What am I doing wrong?我究竟做错了什么?

Controller: Controller:

@RestController
@RequiredArgsConstructor
@Slf4j
public class CardStatusController {

    private final CardStatusService cardStatusService;

    @PostMapping(value = "api/{user_id}/confirm", produces = {MediaType.APPLICATION_JSON_VALUE})
  
    public Mono<ResponseEntity<HttpStatus>> confirmStatus(
            @PathVariable("user_id") String userId,
            @RequestBody CardStatusRequest statusRequest) {
        
        statusRequest.setUserId(userId);
        
        cardStatusService.checkCardStatus(statusRequest);

        return Mono.just(new ResponseEntity<>(HttpStatus.OK));
    }

    @ExceptionHandler({ CheckCardStatusException.class })
    public void handleException() {
        log.error("error!");
    }

My service:我的服务:

    public Mono<Void> checkCardStatus(CardStatusRequest statusRequest) throws CheckCardStatusException {
        if (statusRequest.getCardEmissionStatus().equals(CardEmissionStatus.ACCEPTED)) {
            String reference = statusRequest.getReference();
            return Mono.fromCallable(() -> userRepository.findById(statusRequest.getUserId()))
                    .subscribeOn(Schedulers.boundedElastic())
                    .switchIfEmpty(Mono.error(new CheckCardStatusException(HttpStatus.NOT_FOUND)))
                    .flatMap(user -> Mono.fromCallable(() -> cardRepository.findFireCardByUserId(user.getId()))
                            .flatMap(optionalCard -> {
                                if (optionalCard.isPresent()) {
                                    if (optionalCard.get().getExtId().isEmpty()) {
                                        Card card = optionalCard.get();
                                        card.setExtId(reference);
                                        try {
                                            cardRepository.save(card);
                                        } catch (Exception e) {
                                            return Mono.error(new CheckCardStatusException(HttpStatus.INTERNAL_SERVER_ERROR));
                                        }
                                    } else {
                                        if (!optionalCard.get().getExtId().equals(reference)) {
                                                return Mono.error(new CheckCardStatusException(HttpStatus.CONFLICT));
                                            }
                                    }
                                } else {
                                    Card card = new Card();
                                    //set card params
                                    try {
                                        cardRepository.save(card);
                                    } catch (Exception e) {
                                        return Mono.error(new CheckCardStatusException(HttpStatus.INTERNAL_SERVER_ERROR));
                                    }
                                }
                                return Mono.error(new CheckCardStatusException(HttpStatus.OK));
                            })).then();
        }
        else {
            return Mono.error(new CheckCardStatusException(HttpStatus.OK));
        }
    }
}

My CustomException:我的自定义异常:

@AllArgsConstructor
@Getter
public class CheckCardStatusException extends RuntimeException {
    private HttpStatus httpStatus;
}

The Mono returned by checkCardStatus is never subscribed, so the error signal is ignored. Mono返回的checkCardStatus从未订阅过,因此忽略错误信号。 You have to return the whole chain to the Webflux framework as follows:您必须将整个链返回到 Webflux 框架,如下所示:

public Mono<ResponseEntity<HttpStatus>> confirmStatus(
        @PathVariable("user_id") String userId,
        @RequestBody CardStatusRequest statusRequest) {
    
    statusRequest.setUserId(userId);
    
    return cardStatusService.checkCardStatus(statusRequest)
            .then(Mono.just(new ResponseEntity<>(HttpStatus.OK)));
}

In case of an error, the corresponding ExceptionHandler will be executed.如果发生错误,将执行相应的ExceptionHandler

Since you are using Mono.error(Throwable t) , the exception is not actually thrown.由于您使用的是Mono.error(Throwable t) ,因此实际上并未引发异常。 Because of that, your Error Handler will never be called.因此,您的错误处理程序将永远不会被调用。 Instead, an onError signal is emitted, which can be handled as part of your cardStatusService.checkCardStatus(statusRequest);相反,会发出一个onError信号,该信号可以作为cardStatusService.checkCardStatus(statusRequest);的一部分进行处理。 call in the RequestMapping .调用RequestMapping In order to do that, you actually need to subscribe to the Mono:为此,您实际上需要订阅 Mono:

cardStatusService.checkCardStatus(statusRequest).subscribe(
  successValue -> System.out.println("success");
  error -> // your error handling here
);

See: https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#subscribe-java.util.function.Consumer-java.util.function.Consumer- See: https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#subscribe-java.util.function.Consumer-java.util.function.Consumer-

For that reason, when using Mono in your service, you should never return null.因此,在您的服务中使用 Mono 时,您永远不应返回 null。 That defeats the purpose of using Mono, since you can not subscribe to null.这违背了使用 Mono 的目的,因为您不能订阅 null。 Maybe reconsider, if a publisher pattern is necessary here.也许重新考虑,如果这里需要发布者模式。

If you do not want to use Mono, and instead use the exception handler, explicitly throw the Exception either directly in the service or in your error handling subscription.如果您不想使用 Mono,而是使用异常处理程序,请直接在服务中或在您的错误处理订阅中显式抛出异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM