diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMethodMappingNamingStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMethodMappingNamingStrategy.java index 50eaf01611..5adbda0aed 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMethodMappingNamingStrategy.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMethodMappingNamingStrategy.java @@ -21,7 +21,20 @@ import org.springframework.web.method.HandlerMethod; import java.lang.reflect.Method; /** - * A strategy for assigning a name to a controller method mapping. + * A strategy for assigning a name to a handler method's mapping. + * + *

The strategy can be configured on + * {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping + * AbstractHandlerMethodMapping}. It is used to assign a name to the mapping of + * every registered handler method. The names can then be queried via + * {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerMethodsForMappingName(String) + * AbstractHandlerMethodMapping#getHandlerMethodsForMappingName}. + * + *

Applications can build a URL to a controller method by name with the help + * of the static method + * {@link org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder#fromMappingName(String) + * MvcUriComponentsBuilder#fromMappingName} or in JSPs through the "mvcUrl" + * function registered by the Spring tag library. * * @author Rossen Stoyanchev * @since 4.1 diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java index b10566312d..85a8b6a742 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java @@ -193,38 +193,62 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder { } /** - * Create a {@link UriComponentsBuilder} from a request mapping identified - * by name. The configured + * Create a URL from the name of a Spring MVC controller method's request mapping. + * + *

The configured * {@link org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy - * HandlerMethodMappingNamingStrategy} assigns a default name to every - * {@code @RequestMapping} method but an explicit name may also be assigned - * through the {@code @RequestMapping} name attribute. - *

This is intended for use in EL expressions, typically in JSPs or other - * view templates, which can use the convenience method {@link #toUriString()}. - *

The default naming convention for mappings is based on the capital - * letters of the class name, followed by "#" as a separator, and the method - * name. For example "TC#getFoo" for a class named TestController with method - * getFoo. Use explicit names where the naming convention does not produce - * unique results. - * @param name the mapping name - * @param argumentValues argument values for the controller method; those values - * are important for {@code @RequestParam} and {@code @PathVariable} arguments - * but may be passed as {@code null} otherwise. - * @return the UriComponentsBuilder + * HandlerMethodMappingNamingStrategy} determines the names of controller + * method request mappings at startup. By default all mappings are assigned + * a name based on the capital letters of the class name, followed by "#" as + * separator, and then the method name. For example "PC#getPerson" + * for a class named PersonController with method getPerson. In case the + * naming convention does not produce unique results, an explicit name may + * be assigned through the name attribute of the {@code @RequestMapping} + * annotation. + * + *

This is aimed primarily for use in view rendering technologies and EL + * expressions. The Spring URL tag library registers this method as a function + * called "mvcUrl". + * + *

For example, given this controller: + *

+	 * @RequestMapping("/people")
+	 * class PersonController {
+	 *
+	 *   @RequestMapping("/{id}")
+	 *   public HttpEntity getPerson(@PathVariable String id) { ... }
+	 *
+	 * }
+	 * 
+ * + * A JSP can prepare a URL to the controller method as follows: + * + *
+	 * <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
+	 *
+	 * <a href="${s:mvcUrl('PC#getPerson').arg(0,"123").build()}">Get Person</a>
+	 * 
+ * + *

Note that it's not necessary to specify all arguments. Only the ones + * required to prepare the URL, mainly {@code @RequestParam} and {@code @PathVariable}). + * + * @param mappingName the mapping name + * @return a builder to to prepare the URI String * @throws IllegalArgumentException if the mapping name is not found or * if there is no unique match * @since 4.1 */ - public static UriComponentsBuilder fromMappingName(String name, Object... argumentValues) { - RequestMappingInfoHandlerMapping hm = getRequestMappingInfoHandlerMapping(); - List handlerMethods = hm.getHandlerMethodsForMappingName(name); + public static MethodArgumentBuilder fromMappingName(String mappingName) { + RequestMappingInfoHandlerMapping handlerMapping = getRequestMappingInfoHandlerMapping(); + List handlerMethods = handlerMapping.getHandlerMethodsForMappingName(mappingName); if (handlerMethods == null) { - throw new IllegalArgumentException("Mapping name not found: " + name); + throw new IllegalArgumentException("Mapping mappingName not found: " + mappingName); } if (handlerMethods.size() != 1) { - throw new IllegalArgumentException("No unique match for mapping name " + name + ": " + handlerMethods); + throw new IllegalArgumentException( + "No unique match for mapping mappingName " + mappingName + ": " + handlerMethods); } - return fromMethod(handlerMethods.get(0).getMethod(), argumentValues); + return new MethodArgumentBuilder(handlerMethods.get(0).getMethod()); } /** @@ -455,4 +479,37 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder { Object[] getArgumentValues(); } + + public static class MethodArgumentBuilder { + + private final Method method; + + private final Object[] argumentValues; + + + public MethodArgumentBuilder(Method method) { + Assert.notNull(method, "'method' is required"); + this.method = method; + this.argumentValues = new Object[method.getParameterTypes().length]; + for (int i = 0; i < this.argumentValues.length; i++) { + this.argumentValues[i] = null; + } + } + + public MethodArgumentBuilder arg(int index, Object value) { + this.argumentValues[index] = value; + return this; + } + + public String build() { + return MvcUriComponentsBuilder.fromMethod(this.method, this.argumentValues) + .build(false).encode().toUriString(); + } + + public String buildAndExpand(Object... uriVariables) { + return MvcUriComponentsBuilder.fromMethod(this.method, this.argumentValues) + .build(false).expand(uriVariables).encode().toString(); + } + } + } diff --git a/spring-webmvc/src/main/resources/META-INF/spring.tld b/spring-webmvc/src/main/resources/META-INF/spring.tld index dab5f8cd86..d25232e529 100644 --- a/spring-webmvc/src/main/resources/META-INF/spring.tld +++ b/spring-webmvc/src/main/resources/META-INF/spring.tld @@ -472,4 +472,11 @@ + + Helps to prepare a URL to a Spring MVC controller method. + mvcUrl + org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder + org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.MethodArgumentBuilder fromMappingName(java.lang.String) + +