2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								= Functional Endpoints
							 
						 
					
						
							
								
									
										
										
										
											2022-12-17 20:39:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[.small]#<<web-reactive.adoc#webflux-fn, See equivalent in the Reactive stack>>#
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Spring Web MVC includes WebMvc.fn, a lightweight functional programming model in which functions
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								are used to route and handle requests and contracts are designed for immutability.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								It is an alternative to the annotation-based programming model but otherwise runs on
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								the same xref:web/webmvc/mvc-servlet.adoc[DispatcherServlet].
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-overview]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								== Overview
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[.small]#xref:web/webflux-functional.adoc#webflux-fn-overview[See equivalent in the Reactive stack]#
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								In WebMvc.fn, an HTTP request is handled with a `HandlerFunction`: a function that takes
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`ServerRequest` and returns a `ServerResponse`.
							 
						 
					
						
							
								
									
										
										
										
											2020-04-25 15:24:15 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								Both the request and the response object have immutable contracts that offer JDK 8-friendly
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								access to the HTTP request and response.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`HandlerFunction` is the equivalent of the body of a `@RequestMapping` method in the
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								annotation-based programming model.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Incoming requests are routed to a handler function with a `RouterFunction`: a function that
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								takes `ServerRequest` and returns an optional `HandlerFunction` (i.e. `Optional<HandlerFunction>`).
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								When the router function matches, a handler function is returned; otherwise an empty Optional.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RouterFunction` is the equivalent of a `@RequestMapping` annotation, but with the major
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								difference that router functions provide not just data, but also behavior.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RouterFunctions.route()` provides a router builder that facilitates the creation of routers,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								as the following example shows:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									import static org.springframework.http.MediaType.APPLICATION_JSON;
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import static org.springframework.web.servlet.function.RequestPredicates.*;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									import static org.springframework.web.servlet.function.RouterFunctions.route;
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									PersonRepository repository = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									PersonHandler handler = new PersonHandler(repository);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 20:52:26 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> route = route() // <1>
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										.GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.GET("/person", accept(APPLICATION_JSON), handler::listPeople)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.POST("/person", handler::createPerson)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public class PersonHandler {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-23 22:08:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										public ServerResponse listPeople(ServerRequest request) {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-23 22:08:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										public ServerResponse createPerson(ServerRequest request) {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-23 22:08:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										public ServerResponse getPerson(ServerRequest request) {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 20:52:26 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								<1> Create router using `route()`.
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val repository: PersonRepository = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val handler = PersonHandler(repository)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val route = router { // <1>
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										accept(APPLICATION_JSON).nest {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											GET("/person/{id}", handler::getPerson)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											GET("/person", handler::listPeople)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										POST("/person", handler::createPerson)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									class PersonHandler(private val repository: PersonRepository) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										fun listPeople(request: ServerRequest): ServerResponse {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										fun createPerson(request: ServerRequest): ServerResponse {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										fun getPerson(request: ServerRequest): ServerResponse {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								<1> Create router using the router DSL.
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								If you register the `RouterFunction` as a bean, for instance by exposing it in a
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								`@Configuration` class, it will be auto-detected by the servlet, as explained in xref:web/webmvc-functional.adoc#webmvc-fn-running[Running a Server].
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-handler-functions]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								== HandlerFunction
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[.small]#xref:web/webflux-functional.adoc#webflux-fn-handler-functions[See equivalent in the Reactive stack]#
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK 8-friendly
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								access to the HTTP request and response, including headers, body, method, and status code.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-request]]
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								=== ServerRequest
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`ServerRequest` provides access to the HTTP method, URI, headers, and query parameters,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								while access to the body is provided through the `body` methods.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example extracts the request body to a `String`:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								String string = request.body(String.class);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val string = request.body<String>()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example extracts the body to a `List<Person>`,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								where `Person` objects are decoded from a serialized form, such as JSON or XML:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								List<Person> people = request.body(new ParameterizedTypeReference<List<Person>>() {});
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val people = request.body<Person>()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example shows how to access parameters:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MultiValueMap<String, String> params = request.params();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val map = request.params()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-response]]
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								=== ServerResponse
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`ServerResponse` provides access to the HTTP response and, since it is immutable, you can use
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								a `build` method to create it. You can use the builder to set the response status, to add response
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								headers, or to provide a body. The following example creates a 200 (OK) response with JSON
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								content:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Person person = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val person: Person = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example shows how to build a 201 (CREATED) response with a `Location` header and no body:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								URI location = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.created(location).build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val location: URI = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.created(location).build()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								You can also use an asynchronous result as the body, in the form of a `CompletableFuture`,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`Publisher`, or any other type supported by the `ReactiveAdapterRegistry`. For instance:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Mono<Person> person = webClient.get().retrieve().bodyToMono(Person.class);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val person = webClient.get().retrieve().awaitBody<Person>()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								If not just the body, but also the status or headers are based on an asynchronous type,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								you can use the static `async` method on `ServerResponse`, which
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								accepts `CompletableFuture<ServerResponse>`, `Publisher<ServerResponse>`, or
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								any other asynchronous type supported by the `ReactiveAdapterRegistry`. For instance:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Mono<ServerResponse> asyncResponse = webClient.get().retrieve().bodyToMono(Person.class)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  .map(p -> ServerResponse.ok().header("Name", p.name()).body(p));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ServerResponse.async(asyncResponse);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2020-10-02 21:04:25 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								https://www.w3.org/TR/eventsource/[Server-Sent Events] can be provided via the
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static `sse` method on `ServerResponse`. The builder provided by that method
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								allows you to send Strings, or other objects as JSON. For example:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public RouterFunction<ServerResponse> sse() {
							 
						 
					
						
							
								
									
										
										
										
											2022-12-18 17:47:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return route(GET("/sse"), request -> ServerResponse.sse(sseBuilder -> {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													// Save the sseBuilder object somewhere..
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}));
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// In some other thread, sending a String
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sseBuilder.send("Hello world");
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Or an object, which will be transformed into JSON
							 
						 
					
						
							
								
									
										
										
										
											2022-12-18 17:47:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									Person person = ...
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									sseBuilder.send(person);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-18 17:47:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Customize the event by using the other methods
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sseBuilder.id("42")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.event("sse event")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.data(person);
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// and done at some point
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sseBuilder.complete();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2022-12-18 17:47:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									fun sse(): RouterFunction<ServerResponse> = router {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										GET("/sse") { request -> ServerResponse.sse { sseBuilder ->
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Save the sseBuilder object somewhere..
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// In some other thread, sending a String
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sseBuilder.send("Hello world")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Or an object, which will be transformed into JSON
							 
						 
					
						
							
								
									
										
										
										
											2022-12-18 17:47:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val person = ...
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									sseBuilder.send(person)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-18 17:47:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Customize the event by using the other methods
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sseBuilder.id("42")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.event("sse event")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.data(person)
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// and done at some point
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sseBuilder.complete()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:51:27 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-handler-classes]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								=== Handler Classes
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								We can write a handler function as a lambda, as the following example shows:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 20:54:10 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								--
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								HandlerFunction<ServerResponse> helloWorld =
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  request -> ServerResponse.ok().body("Hello World");
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								val helloWorld: (ServerRequest) -> ServerResponse =
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { ServerResponse.ok().body("Hello World") }
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 20:54:10 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								--
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								That is convenient, but in an application we need multiple functions, and multiple inline
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								lambda's can get messy.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Therefore, it is useful to group related handler functions together into a handler class, which
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								has a similar role as  `@Controller` in an annotation-based application.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								For example, the following class exposes a reactive `Person` repository:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 20:54:10 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								--
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import static org.springframework.http.MediaType.APPLICATION_JSON;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import static org.springframework.web.reactive.function.server.ServerResponse.ok;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								public class PersonHandler {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									private final PersonRepository repository;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public PersonHandler(PersonRepository repository) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										this.repository = repository;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									public ServerResponse listPeople(ServerRequest request) { // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										List<Person> people = repository.allPeople();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ok().contentType(APPLICATION_JSON).body(people);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public ServerResponse createPerson(ServerRequest request) throws Exception { // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Person person = request.body(Person.class);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										repository.savePerson(person);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ok().build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public ServerResponse getPerson(ServerRequest request) { // <3>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										int personId = Integer.parseInt(request.pathVariable("id"));
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Person person = repository.getPerson(personId);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if (person != null) {
							 
						 
					
						
							
								
									
										
										
										
											2020-06-23 16:26:43 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											return ok().contentType(APPLICATION_JSON).body(person);
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										else {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return ServerResponse.notFound().build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> `listPeople` is a handler function that returns all `Person` objects found in the repository as
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								JSON.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> `createPerson` is a handler function that stores a new `Person` contained in the request body.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<3> `getPerson` is a handler function that returns a single person, identified by the `id` path
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								variable. We retrieve that `Person` from the repository and create a JSON response, if it is
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								found. If it is not found, we return a 404 Not Found response.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									class PersonHandler(private val repository: PersonRepository) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fun listPeople(request: ServerRequest): ServerResponse { // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											val people: List<Person> = repository.allPeople()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return ok().contentType(APPLICATION_JSON).body(people);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fun createPerson(request: ServerRequest): ServerResponse { // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											val person = request.body<Person>()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											repository.savePerson(person)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return ok().build()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fun getPerson(request: ServerRequest): ServerResponse { // <3>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											val personId = request.pathVariable("id").toInt()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return repository.getPerson(personId)?.let { ok().contentType(APPLICATION_JSON).body(it) }
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													?: ServerResponse.notFound().build()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> `listPeople` is a handler function that returns all `Person` objects found in the repository as
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								JSON.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> `createPerson` is a handler function that stores a new `Person` contained in the request body.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<3> `getPerson` is a handler function that returns a single person, identified by the `id` path
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								variable. We retrieve that `Person` from the repository and create a JSON response, if it is
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								found. If it is not found, we return a 404 Not Found response.
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 20:54:10 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								--
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-handler-validation]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								=== Validation
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								A functional endpoint can use Spring's xref:web/webmvc/mvc-config/validation.adoc[validation facilities] to
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								apply validation to the request body. For example, given a custom Spring
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								xref:web/webmvc/mvc-config/validation.adoc[Validator] implementation for a `Person`:
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public class PersonHandler {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										private final Validator validator = new PersonValidator(); // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										public ServerResponse createPerson(ServerRequest request) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Person person = request.body(Person.class);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											validate(person); // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											repository.savePerson(person);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return ok().build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										private void validate(Person person) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Errors errors = new BeanPropertyBindingResult(person, "person");
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											validator.validate(person, errors);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if (errors.hasErrors()) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												throw new ServerWebInputException(errors.toString()); // <3>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> Create `Validator` instance.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> Apply validation.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<3> Raise exception for a 400 response.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									class PersonHandler(private val repository: PersonRepository) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										private val validator = PersonValidator() // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										fun createPerson(request: ServerRequest): ServerResponse {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											val person = request.body<Person>()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											validate(person) // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											repository.savePerson(person)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return ok().build()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										private fun validate(person: Person) {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											val errors: Errors = BeanPropertyBindingResult(person, "person")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											validator.validate(person, errors)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											if (errors.hasErrors()) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												throw ServerWebInputException(errors.toString()) // <3>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> Create `Validator` instance.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> Apply validation.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<3> Raise exception for a 400 response.
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Handlers can also use the standard bean validation API (JSR-303) by creating and injecting
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								a global `Validator` instance based on `LocalValidatorFactoryBean`.
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								See xref:core/validation/beanvalidation.adoc[Spring Validation].
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-router-functions]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								== `RouterFunction`
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[.small]#xref:web/webflux-functional.adoc#webflux-fn-router-functions[See equivalent in the Reactive stack]#
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Router functions are used to route the requests to the corresponding `HandlerFunction`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Typically, you do not write router functions yourself, but rather use a method on the
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RouterFunctions` utility class to create one.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RouterFunctions.route()` (no parameters) provides you with a fluent builder for creating a router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function, whereas `RouterFunctions.route(RequestPredicate, HandlerFunction)` offers a direct way
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								to create a router.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Generally, it is recommended to use the `route()` builder, as it provides
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								convenient short-cuts for typical mapping scenarios without requiring hard-to-discover
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static imports.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								For instance, the router function builder offers the method `GET(String, HandlerFunction)` to create a mapping for GET requests; and `POST(String, HandlerFunction)` for POSTs.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Besides HTTP method-based mapping, the route builder offers a way to introduce additional
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								predicates when mapping to requests.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								For each HTTP method there is an overloaded variant that takes a `RequestPredicate` as a
							 
						 
					
						
							
								
									
										
										
										
											2021-09-10 21:38:42 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								parameter, through which additional constraints can be expressed.
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-predicates]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								=== Predicates
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								You can write your own `RequestPredicate`, but the `RequestPredicates` utility class
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								offers commonly used implementations, based on the request path, HTTP method, content-type,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								and so on.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example uses a request predicate to create a constraint based on the `Accept`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								header:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> route = RouterFunctions.route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.GET("/hello-world", accept(MediaType.TEXT_PLAIN),
							 
						 
					
						
							
								
									
										
										
										
											2019-11-17 20:50:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											request -> ServerResponse.ok().body("Hello World")).build();
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val route = router {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										GET("/hello-world", accept(TEXT_PLAIN)) {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ServerResponse.ok().body("Hello World")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								You can compose multiple request predicates together by using:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* `RequestPredicate.and(RequestPredicate)` -- both must match.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* `RequestPredicate.or(RequestPredicate)` -- either can match.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Many of the predicates from `RequestPredicates` are composed.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								For example, `RequestPredicates.GET(String)` is composed from `RequestPredicates.method(HttpMethod)`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								and `RequestPredicates.path(String)`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The example shown above also uses two request predicates, as the builder uses
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RequestPredicates.GET` internally, and composes that with the `accept` predicate.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-routes]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								=== Routes
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Router functions are evaluated in order: if the first route does not match, the
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								second is evaluated, and so on.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Therefore, it makes sense to declare more specific routes before general ones.
							 
						 
					
						
							
								
									
										
										
										
											2021-01-14 23:18:22 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								This is also important when registering router functions as Spring beans, as will
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								be described later.
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								Note that this behavior is different from the annotation-based programming model, where the
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								"most specific" controller method is picked automatically.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								When using the router function builder, all defined routes are composed into one
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RouterFunction` that is returned from `build()`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								There are also other ways to compose multiple router functions together:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* `add(RouterFunction)` on the `RouterFunctions.route()` builder
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* `RouterFunction.and(RouterFunction)`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* `RouterFunction.andRoute(RequestPredicate, HandlerFunction)` -- shortcut for
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`RouterFunction.and()` with nested `RouterFunctions.route()`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example shows the composition of four routes:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import static org.springframework.http.MediaType.APPLICATION_JSON;
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									import static org.springframework.web.servlet.function.RequestPredicates.*;
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									PersonRepository repository = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									PersonHandler handler = new PersonHandler(repository);
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> otherRoute = ...
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> route = route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.GET("/person", accept(APPLICATION_JSON), handler::listPeople) // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.POST("/person", handler::createPerson) // <3>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.add(otherRoute) // <4>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.build();
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2020-01-24 04:01:58 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								<1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								`PersonHandler.getPerson`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> `GET /person` with an `Accept` header that matches JSON is routed to
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`PersonHandler.listPeople`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<3> `POST /person` with no additional predicates is mapped to
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`PersonHandler.createPerson`, and
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									import org.springframework.http.MediaType.APPLICATION_JSON
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val repository: PersonRepository = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val handler = PersonHandler(repository);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val otherRoute = router {  }
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val route = router {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										GET("/person", accept(APPLICATION_JSON), handler::listPeople) // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										POST("/person", handler::createPerson) // <3>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}.and(otherRoute) // <4>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2020-01-24 04:01:58 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								<1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								`PersonHandler.getPerson`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> `GET /person` with an `Accept` header that matches JSON is routed to
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`PersonHandler.listPeople`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<3> `POST /person` with no additional predicates is mapped to
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								`PersonHandler.createPerson`, and
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:23:59 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[[nested-routes]]
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								=== Nested Routes
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								It is common for a group of router functions to have a shared predicate, for instance a shared
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								path.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								In the example above, the shared predicate would be a path predicate that matches `/person`,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								used by three of the routes.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								When using annotations, you would remove this duplication by using a type-level `@RequestMapping`
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 annotation that maps to `/person`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								In WebMvc.fn, path predicates can be shared through the `path` method on the router function builder.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								For instance, the last few lines of the example above can be improved in the following way by using nested routes:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								RouterFunction<ServerResponse> route = route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									.path("/person", builder -> builder // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
							 
						 
					
						
							
								
									
										
										
										
											2020-10-06 17:00:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										.GET(accept(APPLICATION_JSON), handler::listPeople)
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										.POST(handler::createPerson))
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									.build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> Note that second parameter of `path` is a consumer that takes the router builder.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val route = router {
							 
						 
					
						
							
								
									
										
										
										
											2022-11-17 22:49:58 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										"/person".nest { // <1>
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
							 
						 
					
						
							
								
									
										
										
										
											2020-10-06 17:00:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											GET(accept(APPLICATION_JSON), handler::listPeople)
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											POST(handler::createPerson)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2022-11-17 22:49:58 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								<1> Using `nest` DSL.
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Though path-based nesting is the most common, you can nest on any kind of predicate by using
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								the `nest` method on the builder.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The above still contains some duplication in the form of the shared `Accept`-header predicate.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								We can further improve by using the `nest` method together with `accept`:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> route = route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.path("/person", b1 -> b1
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.nest(accept(APPLICATION_JSON), b2 -> b2
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												.GET("/{id}", handler::getPerson)
							 
						 
					
						
							
								
									
										
										
										
											2020-10-06 17:00:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												.GET(handler::listPeople))
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											.POST(handler::createPerson))
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										.build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val route = router {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										"/person".nest {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											accept(APPLICATION_JSON).nest {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												GET("/{id}", handler::getPerson)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												GET("", handler::listPeople)
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												POST(handler::createPerson)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-13 20:20:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[[webmvc-fn-serving-resources]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								== Serving Resources
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								WebMvc.fn provides built-in support for serving resources.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								NOTE: In addition to the capabilities described below, it is possible to implement an even more flexible resource handling thanks to
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{spring-framework-api}++/web/servlet/function/RouterFunctions.html#resources(java.util.function.Function)++[`RouterFunctions#resource(java.util.function.Function)`].
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-resource]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								=== Redirecting to a resource
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								It is possible to redirect requests matching a specified predicate to a resource. This can be useful, for example,
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								for handling redirects in Single Page Applications.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ClassPathResource index = new ClassPathResource("static/index.html");
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								List<String> extensions = List.of("js", "css", "ico", "png", "jpg", "gif");
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								RequestPredicate spaPredicate = path("/api/**").or(path("/error")).or(pathExtension(extensions::contains)).negate();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								RouterFunction<ServerResponse> redirectToIndex = route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    .resource(spaPredicate, index)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    .build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val redirectToIndex = router {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    val index = ClassPathResource("static/index.html")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    val extensions = listOf("js", "css", "ico", "png", "jpg", "gif")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    val spaPredicate = !(path("/api/**") or path("/error") or
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        pathExtension(extensions::contains))
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    resource(spaPredicate, index)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-resources]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								=== Serving resources from a root location
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								It is also possible to route requests that match a given pattern to resources relative to a given root location.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Resource location = new FileSystemResource("public-resources/");
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val location = FileSystemResource("public-resources/")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								val resources = router { resources("/resources/**", location) }
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-running]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								== Running a Server
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[.small]#xref:web/webflux-functional.adoc#webflux-fn-running[See equivalent in the Reactive stack]#
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								You typically run router functions in a xref:web/webmvc/mvc-servlet.adoc[`DispatcherHandler`]-based setup through the
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								xref:web/webmvc/mvc-config.adoc[MVC Config], which uses Spring configuration to declare the
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								components required to process requests. The MVC Java configuration declares the following
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								infrastructure components to support functional endpoints:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* `RouterFunctionMapping`: Detects one or more `RouterFunction<?>` beans in the Spring
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								configuration, xref:core/beans/annotation-config/autowired.adoc#beans-factory-ordered[orders them], combines them through
							 
						 
					
						
							
								
									
										
										
										
											2021-01-14 23:18:22 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								`RouterFunction.andOther`, and routes requests to the resulting composed `RouterFunction`.
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								* `HandlerFunctionAdapter`: Simple adapter that lets `DispatcherHandler` invoke
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								a `HandlerFunction` that was mapped to a request.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The preceding components let functional endpoints fit within the `DispatcherServlet` request
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								processing lifecycle and also (potentially) run side by side with annotated controllers, if
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								any are declared. It is also how functional endpoints are enabled by the Spring Boot Web
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								starter.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example shows a WebFlux Java configuration:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									@Configuration
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									@EnableMvc
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									public class WebConfig implements WebMvcConfigurer {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Bean
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										public RouterFunction<?> routerFunctionA() {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Bean
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										public RouterFunction<?> routerFunctionB() {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Override
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// configure message conversion...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Override
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										public void addCorsMappings(CorsRegistry registry) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// configure CORS...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Override
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										public void configureViewResolvers(ViewResolverRegistry registry) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// configure view resolution for HTML rendering...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									@Configuration
							 
						 
					
						
							
								
									
										
										
										
											2019-09-23 22:08:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									@EnableMvc
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									class WebConfig : WebMvcConfigurer {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Bean
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fun routerFunctionA(): RouterFunction<*> {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										@Bean
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fun routerFunctionB(): RouterFunction<*> {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										override fun configureMessageConverters(converters: List<HttpMessageConverter<*>>) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// configure message conversion...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										override fun addCorsMappings(registry: CorsRegistry) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// configure CORS...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										override fun configureViewResolvers(registry: ViewResolverRegistry) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// configure view resolution for HTML rendering...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								[[webmvc-fn-handler-filter-function]]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								== Filtering Handler Functions
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[.small]#xref:web/webflux-functional.adoc#webflux-fn-handler-filter-function[See equivalent in the Reactive stack]#
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								You can filter handler functions by using the `before`, `after`, or `filter` methods on the routing
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function builder.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								With annotations, you can achieve similar functionality by using `@ControllerAdvice`, a `ServletFilter`, or both.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The filter will apply to all routes that are built by the builder.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								This means that filters defined in nested routes do not apply to "top-level" routes.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								For instance, consider the following example:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> route = route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.path("/person", b1 -> b1
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.nest(accept(APPLICATION_JSON), b2 -> b2
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												.GET("/{id}", handler::getPerson)
							 
						 
					
						
							
								
									
										
										
										
											2020-10-06 17:00:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												.GET(handler::listPeople)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												.before(request -> ServerRequest.from(request) // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													.header("X-RequestHeader", "Value")
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													.build()))
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											.POST(handler::createPerson))
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										.after((request, response) -> logResponse(response)) // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> The `before` filter that adds a custom request header is only applied to the two GET routes.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> The `after` filter that logs the response is applied to all routes, including the nested ones.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val route = router {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"/person".nest {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											GET("/{id}", handler::getPerson)
							 
						 
					
						
							
								
									
										
										
										
											2020-10-06 17:00:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											GET(handler::listPeople)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											before { // <1>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ServerRequest.from(it)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														.header("X-RequestHeader", "Value").build()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
									
										
										
										
											2021-08-30 22:47:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										POST(handler::createPerson)
							 
						 
					
						
							
								
									
										
										
										
											2021-08-30 22:47:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										after { _, response -> // <2>
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logResponse(response)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<1> The `before` filter that adds a custom request header is only applied to the two GET routes.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								<2> The `after` filter that logs the response is applied to all routes, including the nested ones.
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 09:19:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The `filter` method on the router builder takes a `HandlerFilterFunction`: a
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function that takes a `ServerRequest` and `HandlerFunction` and returns a `ServerResponse`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The handler function parameter represents the next element in the chain.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								This is typically the handler that is routed to, but it can also be another
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								filter if multiple are applied.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Now we can add a simple security filter to our route, assuming that we have a `SecurityManager` that
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								can determine whether a particular path is allowed.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The following example shows how to do so:
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								[tabs]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Java::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,java,indent=0,subs="verbatim,quotes",role="primary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SecurityManager securityManager = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RouterFunction<ServerResponse> route = route()
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.path("/person", b1 -> b1
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											.nest(accept(APPLICATION_JSON), b2 -> b2
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												.GET("/{id}", handler::getPerson)
							 
						 
					
						
							
								
									
										
										
										
											2020-10-06 17:00:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												.GET(handler::listPeople))
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											.POST(handler::createPerson))
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										.filter((request, next) -> {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if (securityManager.allowAccessTo(request.path())) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return next.handle(request);
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											else {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return ServerResponse.status(UNAUTHORIZED).build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										})
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										.build();
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Kotlin::
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								+
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									import org.springframework.web.servlet.function.router
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									val securityManager: SecurityManager = ...
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									val route = router {
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										("/person" and accept(APPLICATION_JSON)).nest {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											GET("/{id}", handler::getPerson)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											GET("", handler::listPeople)
							 
						 
					
						
							
								
									
										
										
										
											2022-06-10 19:36:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											POST(handler::createPerson)
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											filter { request, next ->
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if (securityManager.allowAccessTo(request.path())) {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													next(request)
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												else {
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													status(UNAUTHORIZED).build();
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}
							 
						 
					
						
							
								
									
										
										
										
											2019-09-24 16:12:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								----
							 
						 
					
						
							
								
									
										
										
										
											2023-04-21 05:21:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								======
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								The preceding example demonstrates that invoking the `next.handle(ServerRequest)` is optional.
							 
						 
					
						
							
								
									
										
										
										
											2020-06-25 01:40:05 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								We only let the handler function be run when access is allowed.
							 
						 
					
						
							
								
									
										
										
										
											2019-09-18 21:57:00 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Besides using the `filter` method on the router function builder, it is possible to apply a
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								filter to an existing router function via `RouterFunction.filter(HandlerFilterFunction)`.
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								NOTE: CORS support for functional endpoints is provided through a dedicated
							 
						 
					
						
							
								
									
										
										
										
											2023-04-19 23:26:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								xref:web/webmvc-cors.adoc#mvc-cors-filter[`CorsFilter`].