Spring 5 реактивная обработка исключений - PullRequest
0 голосов
/ 23 февраля 2019

Я пишу сложное приложение в качестве эксперимента с Spring 5 Webflux.Я планирую использовать много методов в этом приложении.Я знаком со «старым стилем» @RestController, но сейчас я пишу функциональные конечные точки.Например, бэкэнд службы регистрации компаний. Я был похож на @ControllerAdvice в «старом мире».Но я не смог найти ничего похожего в качестве реактивного эквивалента.(Или что-нибудь, что сработало для меня.)

У меня очень простая настройка.Функция маршрутизации, реактивный репозиторий Cassandra, обработчик и тестовый класс.Операция репозитория может вызвать исключение IllegalArgumentException, и я хотел бы обработать его, возвращая HTTP Status BadRequest клиенту.Просто в качестве примера я способен это сделать.:-) Об исключении заботится класс обработчика.Вот мой код.

RouterConfig

@Slf4j
@Configuration
@EnableWebFlux
public class RouterConfig {

@Bean
public RouterFunction<ServerResponse> route(@Autowired CompanyHandler handler) {
    return RouterFunctions.route()
            .nest(path("/company"), bc -> bc
                    .GET("/{id}", handler::handleGetCompanyDataRequest)                     
                    .before(request -> {
                        log.info("Request={} has been received.", request.toString());
                        return request;
                    })
            .after((request, response) -> {
                log.info("Response={} has been sent.", response.toString());
                return response;
            }))
            .build();       
    }
}

CompanyHandler

@Slf4j
@Component
public class CompanyHandler {

    @Autowired
    private ReactiveCompanyRepository repository;

    // Handle get single company data request
    public Mono<ServerResponse> handleGetCompanyDataRequest(ServerRequest request) {
        //Some validation ges here

        return repository.findById(Mono.just(uuid))
            .flatMap(this::ok)
            .onErrorResume(IllegalArgumentException.class, e -> ServerResponse.badRequest().build())
            .switchIfEmpty(ServerResponse.notFound().build());
    }

    private Mono<ServerResponse> ok (Company c) {
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromPublisher(Mono.just(c), Company.class));
    }
}

ReactiveCompanyRepository

@Component
public interface ReactiveCompanyRepository extends ReactiveCassandraRepository<Company, UUID>{

    Mono<Company> findByName(String name);

    Mono<Company> findByEmail(String email);
}

Моя проблема в том, что .onErrorResume (IllegalArgumentException.class, e -> ServerResponse.badRequest (). Build ()) никогда не вызывается и в тестовом примере:

@SuppressWarnings("unchecked")
@Test
public void testGetCompanyExceptionDuringFind() {

    Mockito.when(repository.findById(Mockito.any(Mono.class))).thenThrow(new IllegalArgumentException("Hahaha"));       

    WebTestClient.bindToRouterFunction(routerConfig.route(companyHandler))
        .build()
        .get().uri("/company/2b851f10-356e-11e9-a847-0f89e1aa5554")
        .accept(MediaType.APPLICATION_JSON_UTF8)
        .exchange()
        .expectStatus().isBadRequest()
        .returnResult(Company.class)
        .getResponseBody();
}

Я всегда получаю HttpStatus 500 вместо 400. Так что это не помогает. Любая помощь будет оценена!

1 Ответ

0 голосов
/ 25 февраля 2019

Ваш тест не отражает поведение реактивного API.Если такой репозиторий генерирует исключение напрямую, я бы посчитал, что ошибка - это отчет для сопровождающих.

Когда реактивный API возвращает реактивный тип, такой как Mono или Flux, ожидается, чтовсе ошибки не генерируются напрямую, а фактически отправляются в виде сообщений в реактивном конвейере.

В этом случае ваш тестовый пример, вероятно, должен выглядеть примерно так:

Mockito.when(repository.findById(Mockito.any(Mono.class)))
   .thenReturn(Mono.error(new IllegalArgumentException("Hahaha")));

При этом onError... операторы в Reactor будут обрабатывать эти сообщения об ошибках.

...