
Poprzedni wpis był jedynie wprowadzeniem do Spring Boot’a 2.0. Pojawiło się tam pojęcie WebFlux. Jest to element, który w sposób reaktywny pozwala współpracować z warstwą webową. Ponadto, funkcjonalość ta dostarcza nam nowy sposób tworzenia endpointów poprzez użycie Router Functions. Zapraszam do wpisu!
Router Functions
Jak pisałem we wstępie, w nowym Spring Boot’cie możemy tworzyć naszą część serwerową na dwa sposoby (aktualnie nie można ich mieszać w jednej aplikacji):
- “Po staremu” - korzystając z adnotacji
@Controlleri innych związanych z Web’em - “Po nowemu” - korzystając z programowania funkcyjnego przy użyciu Router Functions

Dziś przedstawię wam nowy sposób (stary wszyscy bardzo dobrze znamy). Zaczynamy od dodania zależności dla WebFlux’a:
Tworzymy konfigurację @Configuration dla @Bean typu RouterFunction:
@Bean
public RouterFunction
return route(GET(“/code-couple”), handler::get);
}
Pod endpointem /code-couple, na metodzie GET zostanie wywołana metoda z HandlerFunction (u nas ReactiveHandler), czyli klasy, która trzyma logikę endpointów. Kolejne mapowania możemy dodawać w łatwy sposób dopisując kolejne wywołania:
@Bean
public RouterFunction
return route(GET(“/code-couple”), handler::get)
.andRoute(POST(“/code-couple”), handler::post);
}
Wszystkie przydatne metody, których możemy używać przy tworzeniu route znajdują się w klasie RequestPredicate:
RequestPredicate.method(HttpMethod)- jaka metoda z Http nas interesujeRequestPredicate.path(String)- ścieżka endpointuRequestPredicate.contentType- typ treściRequestPredicate.GET(String)- jest połączeniemRequestPredicate.method(HttpMethod)iRequestPredicate.path(String)- warunki logiczne - do łączenia predykatów
RequestPredicate.*- więcej
Po utworzeniu interesujących nas Router Functions pora na stworzenie HandlerFunction, czyli w naszym przypadku klasy ReactiveHandler:
@Component
class ReactiveHandler {
Mono<ServerResponse> get(ServerRequest request) {
Mono<String> slogan = Mono.just("CodeCouple roxx!");
return ServerResponse.ok()
.contentType(APPLICATION\_JSON)
.body(slogan, String.class);
}
Mono<ServerResponse> post(ServerRequest request) {
Mono<String> value = request.bodyToMono(String.class);
//do something with value
return ServerResponse.created(URI.create("/code-couple/1")).body(value, String.class);
}
}
Każda metoda w HandlerFunction przyjmuje ServerRequest, natomiast zwraca Mono<ServerResponse>. Klasa ServerRequest dostarcza informacje o aktualnym żądaniu. Możemy z niej uzyskać takie informacje jak nagłówki czy parametry żądania. W odpowiedzi musimy natomiast zwrócić ServerResponse, który dostarcza przyjazne API do tworzenia odpowiedzi:
Mono
String path = request.path();
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).build();
}
Podsumowanie
Bardzo lubiłem wykorzystywać mapowanie “po staremu”, jednakże ostatnio coraz częściej korzystam z Router Functions. Jak dla mnie krótkie mapowania sprawdzają się dużo lepiej z Router Functions niż z klasycznym @RequestMapping. Jaka jest wasza opinia na ten temat? Mieliście już przyjemność pracować z Router Functions?
GitHub
Całość jak zawsze na GitHub’ie.