001/* 002 * Copyright 2002-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.reactive.function.server; 018 019import java.util.List; 020import java.util.Map; 021import java.util.function.BiFunction; 022import java.util.function.Consumer; 023import java.util.function.Function; 024import java.util.function.Predicate; 025import java.util.function.Supplier; 026 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029import reactor.core.publisher.Flux; 030import reactor.core.publisher.Mono; 031 032import org.springframework.core.io.Resource; 033import org.springframework.http.codec.HttpMessageWriter; 034import org.springframework.http.server.reactive.HttpHandler; 035import org.springframework.util.Assert; 036import org.springframework.web.reactive.result.view.ViewResolver; 037import org.springframework.web.server.ServerWebExchange; 038import org.springframework.web.server.WebHandler; 039import org.springframework.web.server.adapter.WebHttpHandlerBuilder; 040 041/** 042 * <strong>Central entry point to Spring's functional web framework.</strong> 043 * Exposes routing functionality, such as to {@linkplain #route() create} a 044 * {@code RouterFunction} using a discoverable builder-style API, to 045 * {@linkplain #route(RequestPredicate, HandlerFunction) create} a {@code RouterFunction} 046 * given a {@code RequestPredicate} and {@code HandlerFunction}, and to do further 047 * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an existing routing 048 * function. 049 * 050 * <p>Additionally, this class can {@linkplain #toHttpHandler(RouterFunction) transform} a 051 * {@code RouterFunction} into an {@code HttpHandler}, which can be run in Servlet 3.1+, 052 * Reactor, or Undertow. 053 * 054 * @author Arjen Poutsma 055 * @since 5.0 056 */ 057public abstract class RouterFunctions { 058 059 private static final Log logger = LogFactory.getLog(RouterFunctions.class); 060 061 /** 062 * Name of the {@link ServerWebExchange} attribute that contains the {@link ServerRequest}. 063 */ 064 public static final String REQUEST_ATTRIBUTE = RouterFunctions.class.getName() + ".request"; 065 066 /** 067 * Name of the {@link ServerWebExchange} attribute that contains the URI 068 * templates map, mapping variable names to values. 069 */ 070 public static final String URI_TEMPLATE_VARIABLES_ATTRIBUTE = 071 RouterFunctions.class.getName() + ".uriTemplateVariables"; 072 073 /** 074 * Name of the {@link ServerWebExchange#getAttributes() attribute} that 075 * contains the matching pattern, as a {@link org.springframework.web.util.pattern.PathPattern}. 076 */ 077 public static final String MATCHING_PATTERN_ATTRIBUTE = 078 RouterFunctions.class.getName() + ".matchingPattern"; 079 080 081 082 083 /** 084 * Offers a discoverable way to create router functions through a builder-style interface. 085 * @return a router function builder 086 * @since 5.1 087 */ 088 public static Builder route() { 089 return new RouterFunctionBuilder(); 090 } 091 092 /** 093 * Route to the given handler function if the given request predicate applies. 094 * <p>For instance, the following example routes GET requests for "/user" to the 095 * {@code listUsers} method in {@code userController}: 096 * <pre class="code"> 097 * RouterFunction<ServerResponse> route = 098 * RouterFunctions.route(RequestPredicates.GET("/user"), userController::listUsers); 099 * </pre> 100 * @param predicate the predicate to test 101 * @param handlerFunction the handler function to route to if the predicate applies 102 * @param <T> the type of response returned by the handler function 103 * @return a router function that routes to {@code handlerFunction} if 104 * {@code predicate} evaluates to {@code true} 105 * @see RequestPredicates 106 */ 107 public static <T extends ServerResponse> RouterFunction<T> route( 108 RequestPredicate predicate, HandlerFunction<T> handlerFunction) { 109 110 return new DefaultRouterFunction<>(predicate, handlerFunction); 111 } 112 113 /** 114 * Route to the given router function if the given request predicate applies. This method can be 115 * used to create <strong>nested routes</strong>, where a group of routes share a common path 116 * (prefix), header, or other request predicate. 117 * <p>For instance, the following example first creates a composed route that resolves to 118 * {@code listUsers} for a GET, and {@code createUser} for a POST. This composed route then gets 119 * nested with a "/user" path predicate, so that GET requests for "/user" will list users, 120 * and POST request for "/user" will create a new user. 121 * <pre class="code"> 122 * RouterFunction<ServerResponse> userRoutes = 123 * RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers) 124 * .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser); 125 * RouterFunction<ServerResponse> nestedRoute = 126 * RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes); 127 * </pre> 128 * @param predicate the predicate to test 129 * @param routerFunction the nested router function to delegate to if the predicate applies 130 * @param <T> the type of response returned by the handler function 131 * @return a router function that routes to {@code routerFunction} if 132 * {@code predicate} evaluates to {@code true} 133 * @see RequestPredicates 134 */ 135 public static <T extends ServerResponse> RouterFunction<T> nest( 136 RequestPredicate predicate, RouterFunction<T> routerFunction) { 137 138 return new DefaultNestedRouterFunction<>(predicate, routerFunction); 139 } 140 141 /** 142 * Route requests that match the given pattern to resources relative to the given root location. 143 * For instance 144 * <pre class="code"> 145 * Resource location = new FileSystemResource("public-resources/"); 146 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location); 147 * </pre> 148 * @param pattern the pattern to match 149 * @param location the location directory relative to which resources should be resolved 150 * @return a router function that routes to resources 151 * @see #resourceLookupFunction(String, Resource) 152 */ 153 public static RouterFunction<ServerResponse> resources(String pattern, Resource location) { 154 return resources(resourceLookupFunction(pattern, location)); 155 } 156 157 /** 158 * Returns the resource lookup function used by {@link #resources(String, Resource)}. 159 * The returned function can be {@linkplain Function#andThen(Function) composed} on, for 160 * instance to return a default resource when the lookup function does not match: 161 * <pre class="code"> 162 * Mono<Resource> defaultResource = Mono.just(new ClassPathResource("index.html")); 163 * Function<ServerRequest, Mono<Resource>> lookupFunction = 164 * RouterFunctions.resourceLookupFunction("/resources/**", new FileSystemResource("public-resources/")) 165 * .andThen(resourceMono -> resourceMono.switchIfEmpty(defaultResource)); 166 * RouterFunction<ServerResponse> resources = RouterFunctions.resources(lookupFunction); 167 * </pre> 168 * @param pattern the pattern to match 169 * @param location the location directory relative to which resources should be resolved 170 * @return the default resource lookup function for the given parameters. 171 */ 172 public static Function<ServerRequest, Mono<Resource>> resourceLookupFunction(String pattern, Resource location) { 173 return new PathResourceLookupFunction(pattern, location); 174 } 175 176 /** 177 * Route to resources using the provided lookup function. If the lookup function provides a 178 * {@link Resource} for the given request, it will be it will be exposed using a 179 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests. 180 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest} 181 * @return a router function that routes to resources 182 */ 183 public static RouterFunction<ServerResponse> resources(Function<ServerRequest, Mono<Resource>> lookupFunction) { 184 return new ResourcesRouterFunction(lookupFunction); 185 } 186 187 /** 188 * Convert the given {@linkplain RouterFunction router function} into a {@link HttpHandler}. 189 * This conversion uses {@linkplain HandlerStrategies#builder() default strategies}. 190 * <p>The returned handler can be adapted to run in 191 * <ul> 192 * <li>Servlet 3.1+ using the 193 * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter},</li> 194 * <li>Reactor using the 195 * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter},</li> 196 * <li>Undertow using the 197 * {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li> 198 * </ul> 199 * <p>Note that {@code HttpWebHandlerAdapter} also implements {@link WebHandler}, allowing 200 * for additional filter and exception handler registration through 201 * {@link WebHttpHandlerBuilder}. 202 * @param routerFunction the router function to convert 203 * @return an http handler that handles HTTP request using the given router function 204 */ 205 public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction) { 206 return toHttpHandler(routerFunction, HandlerStrategies.withDefaults()); 207 } 208 209 /** 210 * Convert the given {@linkplain RouterFunction router function} into a {@link HttpHandler}, 211 * using the given strategies. 212 * <p>The returned {@code HttpHandler} can be adapted to run in 213 * <ul> 214 * <li>Servlet 3.1+ using the 215 * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter},</li> 216 * <li>Reactor using the 217 * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter},</li> 218 * <li>Undertow using the 219 * {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li> 220 * </ul> 221 * @param routerFunction the router function to convert 222 * @param strategies the strategies to use 223 * @return an http handler that handles HTTP request using the given router function 224 */ 225 public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction, HandlerStrategies strategies) { 226 WebHandler webHandler = toWebHandler(routerFunction, strategies); 227 return WebHttpHandlerBuilder.webHandler(webHandler) 228 .filters(filters -> filters.addAll(strategies.webFilters())) 229 .exceptionHandlers(handlers -> handlers.addAll(strategies.exceptionHandlers())) 230 .localeContextResolver(strategies.localeContextResolver()) 231 .build(); 232 } 233 234 /** 235 * Convert the given {@linkplain RouterFunction router function} into a {@link WebHandler}. 236 * This conversion uses {@linkplain HandlerStrategies#builder() default strategies}. 237 * @param routerFunction the router function to convert 238 * @return a web handler that handles web request using the given router function 239 */ 240 public static WebHandler toWebHandler(RouterFunction<?> routerFunction) { 241 return toWebHandler(routerFunction, HandlerStrategies.withDefaults()); 242 } 243 244 /** 245 * Convert the given {@linkplain RouterFunction router function} into a {@link WebHandler}, 246 * using the given strategies. 247 * @param routerFunction the router function to convert 248 * @param strategies the strategies to use 249 * @return a web handler that handles web request using the given router function 250 */ 251 public static WebHandler toWebHandler(RouterFunction<?> routerFunction, HandlerStrategies strategies) { 252 Assert.notNull(routerFunction, "RouterFunction must not be null"); 253 Assert.notNull(strategies, "HandlerStrategies must not be null"); 254 255 return new RouterFunctionWebHandler(strategies, routerFunction); 256 } 257 258 /** 259 * Represents a discoverable builder for router functions. 260 * Obtained via {@link RouterFunctions#route()}. 261 * @since 5.1 262 */ 263 public interface Builder { 264 265 /** 266 * Adds a route to the given handler function that handles all HTTP {@code GET} requests 267 * that match the given pattern. 268 * @param pattern the pattern to match to 269 * @param handlerFunction the handler function to handle all {@code GET} requests that 270 * match {@code pattern} 271 * @return this builder 272 */ 273 Builder GET(String pattern, HandlerFunction<ServerResponse> handlerFunction); 274 275 /** 276 * Adds a route to the given handler function that handles all HTTP {@code GET} requests 277 * that match the given pattern and predicate. 278 * <p>For instance, the following example routes GET requests for "/user" that accept JSON 279 * to the {@code listUsers} method in {@code userController}: 280 * <pre class="code"> 281 * RouterFunction<ServerResponse> route = 282 * RouterFunctions.route() 283 * .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers) 284 * .build(); 285 * </pre> 286 * @param pattern the pattern to match to 287 * @param predicate additional predicate to match 288 * @param handlerFunction the handler function to handle all {@code GET} requests that 289 * match {@code pattern} 290 * @return this builder 291 * @see RequestPredicates 292 */ 293 Builder GET(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 294 295 /** 296 * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests 297 * that match the given pattern. 298 * @param pattern the pattern to match to 299 * @param handlerFunction the handler function to handle all {@code HEAD} requests that 300 * match {@code pattern} 301 * @return this builder 302 */ 303 Builder HEAD(String pattern, HandlerFunction<ServerResponse> handlerFunction); 304 305 /** 306 * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests 307 * that match the given pattern and predicate. 308 * @param pattern the pattern to match to 309 * @param predicate additional predicate to match 310 * @param handlerFunction the handler function to handle all {@code HEAD} requests that 311 * match {@code pattern} 312 * @return this builder 313 */ 314 Builder HEAD(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 315 316 /** 317 * Adds a route to the given handler function that handles all HTTP {@code POST} requests 318 * that match the given pattern. 319 * @param pattern the pattern to match to 320 * @param handlerFunction the handler function to handle all {@code POST} requests that 321 * match {@code pattern} 322 * @return this builder 323 */ 324 Builder POST(String pattern, HandlerFunction<ServerResponse> handlerFunction); 325 326 /** 327 * Adds a route to the given handler function that handles all HTTP {@code POST} requests 328 * that match the given pattern and predicate. 329 * <p>For instance, the following example routes POST requests for "/user" that contain JSON 330 * to the {@code addUser} method in {@code userController}: 331 * <pre class="code"> 332 * RouterFunction<ServerResponse> route = 333 * RouterFunctions.route() 334 * .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser) 335 * .build(); 336 * </pre> 337 * @param pattern the pattern to match to 338 * @param predicate additional predicate to match 339 * @param handlerFunction the handler function to handle all {@code POST} requests that 340 * match {@code pattern} 341 * @return this builder 342 */ 343 Builder POST(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 344 345 /** 346 * Adds a route to the given handler function that handles all HTTP {@code PUT} requests 347 * that match the given pattern. 348 * @param pattern the pattern to match to 349 * @param handlerFunction the handler function to handle all {@code PUT} requests that 350 * match {@code pattern} 351 * @return this builder 352 */ 353 Builder PUT(String pattern, HandlerFunction<ServerResponse> handlerFunction); 354 355 /** 356 * Adds a route to the given handler function that handles all HTTP {@code PUT} requests 357 * that match the given pattern and predicate. 358 * <p>For instance, the following example routes PUT requests for "/user" that contain JSON 359 * to the {@code editUser} method in {@code userController}: 360 * <pre class="code"> 361 * RouterFunction<ServerResponse> route = 362 * RouterFunctions.route() 363 * .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser) 364 * .build(); 365 * </pre> 366 * @param pattern the pattern to match to 367 * @param predicate additional predicate to match 368 * @param handlerFunction the handler function to handle all {@code PUT} requests that 369 * match {@code pattern} 370 * @return this builder 371 */ 372 Builder PUT(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 373 374 /** 375 * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests 376 * that match the given pattern. 377 * @param pattern the pattern to match to 378 * @param handlerFunction the handler function to handle all {@code PATCH} requests that 379 * match {@code pattern} 380 * @return this builder 381 */ 382 Builder PATCH(String pattern, HandlerFunction<ServerResponse> handlerFunction); 383 384 /** 385 * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests 386 * that match the given pattern and predicate. 387 * <p>For instance, the following example routes PATCH requests for "/user" that contain JSON 388 * to the {@code editUser} method in {@code userController}: 389 * <pre class="code"> 390 * RouterFunction<ServerResponse> route = 391 * RouterFunctions.route() 392 * .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser) 393 * .build(); 394 * </pre> 395 * @param pattern the pattern to match to 396 * @param predicate additional predicate to match 397 * @param handlerFunction the handler function to handle all {@code PATCH} requests that 398 * match {@code pattern} 399 * @return this builder 400 */ 401 Builder PATCH(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 402 403 /** 404 * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests 405 * that match the given pattern. 406 * @param pattern the pattern to match to 407 * @param handlerFunction the handler function to handle all {@code DELETE} requests that 408 * match {@code pattern} 409 * @return this builder 410 */ 411 Builder DELETE(String pattern, HandlerFunction<ServerResponse> handlerFunction); 412 413 /** 414 * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests 415 * that match the given pattern and predicate. 416 * @param pattern the pattern to match to 417 * @param predicate additional predicate to match 418 * @param handlerFunction the handler function to handle all {@code DELETE} requests that 419 * match {@code pattern} 420 * @return this builder 421 */ 422 Builder DELETE(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 423 424 /** 425 * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests 426 * that match the given pattern. 427 * @param pattern the pattern to match to 428 * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that 429 * match {@code pattern} 430 * @return this builder 431 */ 432 Builder OPTIONS(String pattern, HandlerFunction<ServerResponse> handlerFunction); 433 434 /** 435 * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests 436 * that match the given pattern and predicate. 437 * @param pattern the pattern to match to 438 * @param predicate additional predicate to match 439 * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that 440 * match {@code pattern} 441 * @return this builder 442 */ 443 Builder OPTIONS(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 444 445 /** 446 * Adds a route to the given handler function that handles all requests that match the 447 * given predicate. 448 * @param predicate the request predicate to match 449 * @param handlerFunction the handler function to handle all requests that match the predicate 450 * @return this builder 451 * @since 5.2 452 * @see RequestPredicates 453 */ 454 Builder route(RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction); 455 456 /** 457 * Adds the given route to this builder. Can be used to merge externally defined router 458 * functions into this builder, or can be combined with 459 * {@link RouterFunctions#route(RequestPredicate, HandlerFunction)} 460 * to allow for more flexible predicate matching. 461 * <p>For instance, the following example adds the router function returned from 462 * {@code OrderController.routerFunction()}. 463 * to the {@code changeUser} method in {@code userController}: 464 * <pre class="code"> 465 * RouterFunction<ServerResponse> route = 466 * RouterFunctions.route() 467 * .GET("/users", userController::listUsers) 468 * .add(orderController.routerFunction()); 469 * .build(); 470 * </pre> 471 * @param routerFunction the router function to be added 472 * @return this builder 473 * @see RequestPredicates 474 */ 475 Builder add(RouterFunction<ServerResponse> routerFunction); 476 477 /** 478 * Route requests that match the given pattern to resources relative to the given root location. 479 * For instance 480 * <pre class="code"> 481 * Resource location = new FileSystemResource("public-resources/"); 482 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location); 483 * </pre> 484 * @param pattern the pattern to match 485 * @param location the location directory relative to which resources should be resolved 486 * @return this builder 487 */ 488 Builder resources(String pattern, Resource location); 489 490 /** 491 * Route to resources using the provided lookup function. If the lookup function provides a 492 * {@link Resource} for the given request, it will be it will be exposed using a 493 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests. 494 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest} 495 * @return this builder 496 */ 497 Builder resources(Function<ServerRequest, Mono<Resource>> lookupFunction); 498 499 /** 500 * Route to the supplied router function if the given request predicate applies. This method 501 * can be used to create <strong>nested routes</strong>, where a group of routes share a 502 * common path (prefix), header, or other request predicate. 503 * <p>For instance, the following example creates a nested route with a "/user" path 504 * predicate, so that GET requests for "/user" will list users, 505 * and POST request for "/user" will create a new user. 506 * <pre class="code"> 507 * RouterFunction<ServerResponse> nestedRoute = 508 * RouterFunctions.route() 509 * .nest(RequestPredicates.path("/user"), () -> 510 * RouterFunctions.route() 511 * .GET(this::listUsers) 512 * .POST(this::createUser) 513 * .build()) 514 * .build(); 515 * </pre> 516 * @param predicate the predicate to test 517 * @param routerFunctionSupplier supplier for the nested router function to delegate to if 518 * the predicate applies 519 * @return this builder 520 * @see RequestPredicates 521 */ 522 Builder nest(RequestPredicate predicate, Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier); 523 524 /** 525 * Route to a built router function if the given request predicate applies. 526 * This method can be used to create <strong>nested routes</strong>, where a group of routes 527 * share a common path (prefix), header, or other request predicate. 528 * <p>For instance, the following example creates a nested route with a "/user" path 529 * predicate, so that GET requests for "/user" will list users, 530 * and POST request for "/user" will create a new user. 531 * <pre class="code"> 532 * RouterFunction<ServerResponse> nestedRoute = 533 * RouterFunctions.route() 534 * .nest(RequestPredicates.path("/user"), builder -> 535 * builder.GET(this::listUsers) 536 * .POST(this::createUser)) 537 * .build(); 538 * </pre> 539 * @param predicate the predicate to test 540 * @param builderConsumer consumer for a {@code Builder} that provides the nested router 541 * function 542 * @return this builder 543 * @see RequestPredicates 544 */ 545 Builder nest(RequestPredicate predicate, Consumer<Builder> builderConsumer); 546 547 /** 548 * Route to the supplied router function if the given path prefix pattern applies. This method 549 * can be used to create <strong>nested routes</strong>, where a group of routes share a 550 * common path prefix. Specifically, this method can be used to merge externally defined 551 * router functions under a path prefix. 552 * <p>For instance, the following example creates a nested route with a "/user" path 553 * predicate that delegates to the router function defined in {@code userController}, 554 * and with a "/order" path that delegates to {@code orderController}. 555 * <pre class="code"> 556 * RouterFunction<ServerResponse> nestedRoute = 557 * RouterFunctions.route() 558 * .path("/user", userController::routerFunction) 559 * .path("/order", orderController::routerFunction) 560 * .build(); 561 * </pre> 562 * @param pattern the pattern to match to 563 * @param routerFunctionSupplier supplier for the nested router function to delegate to if 564 * the pattern matches 565 * @return this builder 566 */ 567 Builder path(String pattern, Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier); 568 569 /** 570 * Route to a built router function if the given path prefix pattern applies. 571 * This method can be used to create <strong>nested routes</strong>, where a group of routes 572 * share a common path prefix. 573 * <p>For instance, the following example creates a nested route with a "/user" path 574 * predicate, so that GET requests for "/user" will list users, 575 * and POST request for "/user" will create a new user. 576 * <pre class="code"> 577 * RouterFunction<ServerResponse> nestedRoute = 578 * RouterFunctions.route() 579 * .path("/user", builder -> 580 * builder.GET(this::listUsers) 581 * .POST(this::createUser)) 582 * .build(); 583 * </pre> 584 * @param pattern the pattern to match to 585 * @param builderConsumer consumer for a {@code Builder} that provides the nested router 586 * function 587 * @return this builder 588 */ 589 Builder path(String pattern, Consumer<Builder> builderConsumer); 590 591 /** 592 * Filters all routes created by this builder with the given filter function. Filter 593 * functions are typically used to address cross-cutting concerns, such as logging, 594 * security, etc. 595 * <p>For instance, the following example creates a filter that returns a 401 Unauthorized 596 * response if the request does not contain the necessary authentication headers. 597 * <pre class="code"> 598 * RouterFunction<ServerResponse> filteredRoute = 599 * RouterFunctions.route() 600 * .GET("/user", this::listUsers) 601 * .filter((request, next) -> { 602 * // check for authentication headers 603 * if (isAuthenticated(request)) { 604 * return next.handle(request); 605 * } 606 * else { 607 * return ServerResponse.status(HttpStatus.UNAUTHORIZED).build(); 608 * } 609 * }) 610 * .build(); 611 * </pre> 612 * @param filterFunction the function to filter all routes built by this builder 613 * @return this builder 614 */ 615 Builder filter(HandlerFilterFunction<ServerResponse, ServerResponse> filterFunction); 616 617 /** 618 * Filter the request object for all routes created by this builder with the given request 619 * processing function. Filters are typically used to address cross-cutting concerns, such 620 * as logging, security, etc. 621 * <p>For instance, the following example creates a filter that logs the request before 622 * the handler function executes. 623 * <pre class="code"> 624 * RouterFunction<ServerResponse> filteredRoute = 625 * RouterFunctions.route() 626 * .GET("/user", this::listUsers) 627 * .before(request -> { 628 * log(request); 629 * return request; 630 * }) 631 * .build(); 632 * </pre> 633 * @param requestProcessor a function that transforms the request 634 * @return this builder 635 */ 636 Builder before(Function<ServerRequest, ServerRequest> requestProcessor); 637 638 /** 639 * Filter the response object for all routes created by this builder with the given response 640 * processing function. Filters are typically used to address cross-cutting concerns, such 641 * as logging, security, etc. 642 * <p>For instance, the following example creates a filter that logs the response after 643 * the handler function executes. 644 * <pre class="code"> 645 * RouterFunction<ServerResponse> filteredRoute = 646 * RouterFunctions.route() 647 * .GET("/user", this::listUsers) 648 * .after((request, response) -> { 649 * log(response); 650 * return response; 651 * }) 652 * .build(); 653 * </pre> 654 * @param responseProcessor a function that transforms the response 655 * @return this builder 656 */ 657 Builder after(BiFunction<ServerRequest, ServerResponse, ServerResponse> responseProcessor); 658 659 /** 660 * Filters all exceptions that match the predicate by applying the given response provider 661 * function. 662 * <p>For instance, the following example creates a filter that returns a 500 response 663 * status when an {@code IllegalStateException} occurs. 664 * <pre class="code"> 665 * RouterFunction<ServerResponse> filteredRoute = 666 * RouterFunctions.route() 667 * .GET("/user", this::listUsers) 668 * .onError(e -> e instanceof IllegalStateException, 669 * (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build()) 670 * .build(); 671 * </pre> 672 * @param predicate the type of exception to filter 673 * @param responseProvider a function that creates a response 674 * @return this builder 675 */ 676 Builder onError(Predicate<? super Throwable> predicate, 677 BiFunction<? super Throwable, ServerRequest, Mono<ServerResponse>> responseProvider); 678 679 /** 680 * Filters all exceptions of the given type by applying the given response provider 681 * function. 682 * <p>For instance, the following example creates a filter that returns a 500 response 683 * status when an {@code IllegalStateException} occurs. 684 * <pre class="code"> 685 * RouterFunction<ServerResponse> filteredRoute = 686 * RouterFunctions.route() 687 * .GET("/user", this::listUsers) 688 * .onError(IllegalStateException.class, 689 * (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build()) 690 * .build(); 691 * </pre> 692 * @param exceptionType the type of exception to filter 693 * @param responseProvider a function that creates a response 694 * @return this builder 695 */ 696 <T extends Throwable> Builder onError(Class<T> exceptionType, 697 BiFunction<? super T, ServerRequest, Mono<ServerResponse>> responseProvider); 698 699 /** 700 * Builds the {@code RouterFunction}. All created routes are 701 * {@linkplain RouterFunction#and(RouterFunction) composed} with one another, and filters 702 * (if any) are applied to the result. 703 * @return the built router function 704 */ 705 RouterFunction<ServerResponse> build(); 706 } 707 708 709 /** 710 * Receives notifications from the logical structure of router functions. 711 */ 712 public interface Visitor { 713 714 /** 715 * Receive notification of the beginning of a nested router function. 716 * @param predicate the predicate that applies to the nested router functions 717 * @see RouterFunctions#nest(RequestPredicate, RouterFunction) 718 */ 719 void startNested(RequestPredicate predicate); 720 721 /** 722 * Receive notification of the end of a nested router function. 723 * @param predicate the predicate that applies to the nested router functions 724 * @see RouterFunctions#nest(RequestPredicate, RouterFunction) 725 */ 726 void endNested(RequestPredicate predicate); 727 728 /** 729 * Receive notification of a standard predicated route to a handler function. 730 * @param predicate the predicate that applies to the handler function 731 * @param handlerFunction the handler function. 732 * @see RouterFunctions#route(RequestPredicate, HandlerFunction) 733 */ 734 void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction); 735 736 /** 737 * Receive notification of a resource router function. 738 * @param lookupFunction the lookup function for the resources 739 * @see RouterFunctions#resources(Function) 740 */ 741 void resources(Function<ServerRequest, Mono<Resource>> lookupFunction); 742 743 /** 744 * Receive notification of an unknown router function. This method is called for router 745 * functions that were not created via the various {@link RouterFunctions} methods. 746 * @param routerFunction the router function 747 */ 748 void unknown(RouterFunction<?> routerFunction); 749 } 750 751 752 abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> { 753 754 @Override 755 public String toString() { 756 ToStringVisitor visitor = new ToStringVisitor(); 757 accept(visitor); 758 return visitor.toString(); 759 } 760 } 761 762 763 /** 764 * A composed routing function that first invokes one function, and then invokes the 765 * another function (of the same response type {@code T}) if this route had 766 * {@linkplain Mono#empty() no result}. 767 * @param <T> the server response type 768 */ 769 static final class SameComposedRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> { 770 771 private final RouterFunction<T> first; 772 773 private final RouterFunction<T> second; 774 775 public SameComposedRouterFunction(RouterFunction<T> first, RouterFunction<T> second) { 776 this.first = first; 777 this.second = second; 778 } 779 780 @Override 781 public Mono<HandlerFunction<T>> route(ServerRequest request) { 782 return Flux.concat(this.first.route(request), Mono.defer(() -> this.second.route(request))) 783 .next(); 784 } 785 786 @Override 787 public void accept(Visitor visitor) { 788 this.first.accept(visitor); 789 this.second.accept(visitor); 790 } 791 } 792 793 794 /** 795 * A composed routing function that first invokes one function, and then invokes 796 * another function (of a different response type) if this route had 797 * {@linkplain Mono#empty() no result}. 798 */ 799 static final class DifferentComposedRouterFunction extends AbstractRouterFunction<ServerResponse> { 800 801 private final RouterFunction<?> first; 802 803 private final RouterFunction<?> second; 804 805 public DifferentComposedRouterFunction(RouterFunction<?> first, RouterFunction<?> second) { 806 this.first = first; 807 this.second = second; 808 } 809 810 @Override 811 public Mono<HandlerFunction<ServerResponse>> route(ServerRequest request) { 812 return Flux.concat(this.first.route(request), Mono.defer(() -> this.second.route(request))) 813 .next() 814 .map(this::cast); 815 } 816 817 @SuppressWarnings("unchecked") 818 private <T extends ServerResponse> HandlerFunction<T> cast(HandlerFunction<?> handlerFunction) { 819 return (HandlerFunction<T>) handlerFunction; 820 } 821 822 @Override 823 public void accept(Visitor visitor) { 824 this.first.accept(visitor); 825 this.second.accept(visitor); 826 } 827 } 828 829 830 /** 831 * Filter the specified {@linkplain HandlerFunction handler functions} with the given 832 * {@linkplain HandlerFilterFunction filter function}. 833 * @param <T> the type of the {@linkplain HandlerFunction handler function} to filter 834 * @param <S> the type of the response of the function 835 */ 836 static final class FilteredRouterFunction<T extends ServerResponse, S extends ServerResponse> 837 implements RouterFunction<S> { 838 839 private final RouterFunction<T> routerFunction; 840 841 private final HandlerFilterFunction<T, S> filterFunction; 842 843 public FilteredRouterFunction( 844 RouterFunction<T> routerFunction, 845 HandlerFilterFunction<T, S> filterFunction) { 846 this.routerFunction = routerFunction; 847 this.filterFunction = filterFunction; 848 } 849 850 @Override 851 public Mono<HandlerFunction<S>> route(ServerRequest request) { 852 return this.routerFunction.route(request).map(this.filterFunction::apply); 853 } 854 855 @Override 856 public void accept(Visitor visitor) { 857 this.routerFunction.accept(visitor); 858 } 859 860 @Override 861 public String toString() { 862 return this.routerFunction.toString(); 863 } 864 } 865 866 867 private static final class DefaultRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> { 868 869 private final RequestPredicate predicate; 870 871 private final HandlerFunction<T> handlerFunction; 872 873 public DefaultRouterFunction(RequestPredicate predicate, HandlerFunction<T> handlerFunction) { 874 Assert.notNull(predicate, "Predicate must not be null"); 875 Assert.notNull(handlerFunction, "HandlerFunction must not be null"); 876 this.predicate = predicate; 877 this.handlerFunction = handlerFunction; 878 } 879 880 @Override 881 public Mono<HandlerFunction<T>> route(ServerRequest request) { 882 if (this.predicate.test(request)) { 883 if (logger.isTraceEnabled()) { 884 String logPrefix = request.exchange().getLogPrefix(); 885 logger.trace(logPrefix + String.format("Matched %s", this.predicate)); 886 } 887 return Mono.just(this.handlerFunction); 888 } 889 else { 890 return Mono.empty(); 891 } 892 } 893 894 @Override 895 public void accept(Visitor visitor) { 896 visitor.route(this.predicate, this.handlerFunction); 897 } 898 } 899 900 901 private static final class DefaultNestedRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> { 902 903 private final RequestPredicate predicate; 904 905 private final RouterFunction<T> routerFunction; 906 907 public DefaultNestedRouterFunction(RequestPredicate predicate, RouterFunction<T> routerFunction) { 908 Assert.notNull(predicate, "Predicate must not be null"); 909 Assert.notNull(routerFunction, "RouterFunction must not be null"); 910 this.predicate = predicate; 911 this.routerFunction = routerFunction; 912 } 913 914 @Override 915 public Mono<HandlerFunction<T>> route(ServerRequest serverRequest) { 916 return this.predicate.nest(serverRequest) 917 .map(nestedRequest -> { 918 if (logger.isTraceEnabled()) { 919 String logPrefix = serverRequest.exchange().getLogPrefix(); 920 logger.trace(logPrefix + String.format("Matched nested %s", this.predicate)); 921 } 922 return this.routerFunction.route(nestedRequest) 923 .doOnNext(match -> { 924 if (nestedRequest != serverRequest) { 925 serverRequest.attributes().clear(); 926 serverRequest.attributes() 927 .putAll(nestedRequest.attributes()); 928 } 929 }); 930 } 931 ).orElseGet(Mono::empty); 932 } 933 934 935 @Override 936 public void accept(Visitor visitor) { 937 visitor.startNested(this.predicate); 938 this.routerFunction.accept(visitor); 939 visitor.endNested(this.predicate); 940 } 941 } 942 943 944 private static class ResourcesRouterFunction extends AbstractRouterFunction<ServerResponse> { 945 946 private final Function<ServerRequest, Mono<Resource>> lookupFunction; 947 948 public ResourcesRouterFunction(Function<ServerRequest, Mono<Resource>> lookupFunction) { 949 Assert.notNull(lookupFunction, "Function must not be null"); 950 this.lookupFunction = lookupFunction; 951 } 952 953 @Override 954 public Mono<HandlerFunction<ServerResponse>> route(ServerRequest request) { 955 return this.lookupFunction.apply(request).map(ResourceHandlerFunction::new); 956 } 957 958 @Override 959 public void accept(Visitor visitor) { 960 visitor.resources(this.lookupFunction); 961 } 962 } 963 964 965 private static class HandlerStrategiesResponseContext implements ServerResponse.Context { 966 967 private final HandlerStrategies strategies; 968 969 public HandlerStrategiesResponseContext(HandlerStrategies strategies) { 970 this.strategies = strategies; 971 } 972 973 @Override 974 public List<HttpMessageWriter<?>> messageWriters() { 975 return this.strategies.messageWriters(); 976 } 977 978 @Override 979 public List<ViewResolver> viewResolvers() { 980 return this.strategies.viewResolvers(); 981 } 982 } 983 984 985 private static class RouterFunctionWebHandler implements WebHandler { 986 987 private static final HandlerFunction<ServerResponse> NOT_FOUND_HANDLER = 988 request -> ServerResponse.notFound().build(); 989 990 private final HandlerStrategies strategies; 991 992 private final RouterFunction<?> routerFunction; 993 994 public RouterFunctionWebHandler(HandlerStrategies strategies, RouterFunction<?> routerFunction) { 995 this.strategies = strategies; 996 this.routerFunction = routerFunction; 997 } 998 999 @Override 1000 public Mono<Void> handle(ServerWebExchange exchange) { 1001 return Mono.defer(() -> { 1002 ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders()); 1003 addAttributes(exchange, request); 1004 return this.routerFunction.route(request) 1005 .defaultIfEmpty(notFound()) 1006 .flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request))) 1007 .flatMap(response -> wrapException(() -> response.writeTo(exchange, 1008 new HandlerStrategiesResponseContext(this.strategies)))); 1009 }); 1010 } 1011 1012 private void addAttributes(ServerWebExchange exchange, ServerRequest request) { 1013 Map<String, Object> attributes = exchange.getAttributes(); 1014 attributes.put(REQUEST_ATTRIBUTE, request); 1015 } 1016 1017 @SuppressWarnings("unchecked") 1018 private static <T extends ServerResponse> HandlerFunction<T> notFound() { 1019 return (HandlerFunction<T>) NOT_FOUND_HANDLER; 1020 } 1021 1022 private static <T> Mono<T> wrapException(Supplier<Mono<T>> supplier) { 1023 try { 1024 return supplier.get(); 1025 } 1026 catch (Throwable ex) { 1027 return Mono.error(ex); 1028 } 1029 } 1030 } 1031}