From 2b528bb6436da728d130f595b1a12a02133bd204 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 7 May 2015 10:42:44 -0400 Subject: [PATCH] Improve and update docs on MvcUriComponentsBuilder Issue: SPR-12617 --- src/asciidoc/web-mvc.adoc | 74 +++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/asciidoc/web-mvc.adoc b/src/asciidoc/web-mvc.adoc index d9d979e012..d23bdd902b 100644 --- a/src/asciidoc/web-mvc.adoc +++ b/src/asciidoc/web-mvc.adoc @@ -3055,12 +3055,7 @@ also have the literal part of the servlet mapping included: [[mvc-links-to-controllers]] === Building URIs to Controllers and methods -Spring MVC provides another mechanism for building and encoding URIs that link to -Controllers and methods defined within an application. -{javadoc-baseurl}/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.html[`MvcUriComponentsBuilder`] -extends `UriComponentsBuilder` and provides such possibilities. - -Given this Controller: +Spring MVC also provides a mechanism for building links to controller methods. For example, given: [source,java,indent=0] [subs="verbatim,quotes"] @@ -3077,19 +3072,27 @@ Given this Controller: } ---- -and using the `MvcUriComponentsBuilder`, the previous example is now: +You can prepare a link by referring to the method by name: [source,java,indent=0] [subs="verbatim,quotes"] ---- UriComponents uriComponents = MvcUriComponentsBuilder - .fromMethodName(BookingController.class, "getBooking",21).buildAndExpand(42); + .fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42); URI uri = uriComponents.encode().toUri(); ---- -The `MvcUriComponentsBuilder` can also create "mock Controllers", thus enabling to create -URIs by coding against the actual Controller's API: +In the above example we provided actual method argument values, in this case the long value 21, +to be used as a path variable and inserted into the URL. Furthermore, we provided the +value 42 in order to fill in any remaining URI variables such as the "hotel" variable inherited +from the type-level request mapping. If the method had more arguments you can supply null for +arguments not needed for the URL. In general only `@PathVariable` and `@RequestParam` arguments +are relevant for constructing the URL. + +There are additional ways to use `MvcUriComponentsBuilder`. For example you can use a technique +akin to mock testing through proxies to avoid referring to the controller method by name +(the example assumes static import of `MvcUriComponentsBuilder.on`): [source,java,indent=0] [subs="verbatim,quotes"] @@ -3100,19 +3103,44 @@ URIs by coding against the actual Controller's API: URI uri = uriComponents.encode().toUri(); ---- +The above examples use static methods in `MvcUriComponentsBuilder`. Internally they rely +on `ServletUriComponentsBuilder` to prepare a base URL from the scheme, host, port, +context path and servlet path of the current request. This works well in most cases, +however sometimes it may be insufficient. For example you may be outside the context of +a request (e.g. a batch process that prepares links) or perhaps you need to insert a path +prefix (e.g. a locale prefix that was removed from the request path and needs to be +re-inserted into links). + +For such cases you can use the static "fromXxx" overloaded methods that accept a +`UriComponentsBuilder` to use base URL. Or you can create an instance of `MvcUriComponentsBuilder` +with a base URL and then use the instance-based "withXxx" methods. For example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en"); + MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base); + builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42); + + URI uri = uriComponents.encode().toUri(); +---- + + [[mvc-links-to-controllers-from-views]] === Building URIs to Controllers and methods from views -It is also useful to build links to annotated controllers from views (e.g. JSP). -This can be done through a method on `MvcUriComponentsBuilder` which refers to mappings -by name called `fromMappingName`. +You can also build links to annotated controllers from views such as JSP, Thymeleaf, +FreeMarker. This can be done using the `fromMappingName` method in `MvcUriComponentsBuilder` +which refers to mappings by name. -As of 4.1 every `@RequestMapping` is assigned a default name based on the -capital letters of the class and the full method name. For example, the method `getFoo` in class -`FooController` is assigned the name "FC#getFoo". This naming strategy is pluggable -by implementing `HandlerMethodMappingNamingStrategy` and configuring it on your -`RequestMappingHandlerMapping`. Furthermore the `@RequestMapping` annotation includes -a name attribute that can be used to override the default strategy. +Every `@RequestMapping` is assigned a default name based on the capital letters of the +class and the full method name. For example, the method `getFoo` in class `FooController` +is assigned the name "FC#getFoo". This strategy can be replaced or customized by creating +an instance of `HandlerMethodMappingNamingStrategy` and plugging it into your +`RequestMappingHandlerMapping`. The default strategy implementation also looks at the +name attribute on `@RequestMapping` and uses that if present. That means if the default +mapping name assigned conflicts with another (e.g. overloaded methods) you can assign +a name explicitly on the `@RequestMapping`. [NOTE] ==== @@ -3135,7 +3163,7 @@ For example given: } ---- -The following JSP code can prepare a link: +You can prepare a link from a JSP as follows: [source,jsp,indent=0] [subs="verbatim,quotes"] @@ -3145,8 +3173,10 @@ The following JSP code can prepare a link: Get Person ---- - - +The above example relies on the `mvcUrl` JSP function declared in the Spring tag library +(i.e. META-INF/spring.tld). For more advanced cases (e.g. a custom base URL as explained +in the previous section), it is easy to define your own function, or use a custom tag file, +in order to use a specific instance of `MvcUriComponentsBuilder` with a custom base URL. [[mvc-localeresolver]]