Skip to content

Commit 6b129c5

Browse files
committed
Add "mvcUrl" function to Spring tag library
This commit adds a new function to the Spring tag library for preparing links to @controller methods. For more details see the Javadoc of MvcUriComponentsBuilder.fromMappingName. Issue: SPR-5779
1 parent 2140648 commit 6b129c5

File tree

3 files changed

+101
-24
lines changed

3 files changed

+101
-24
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMethodMappingNamingStrategy.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,20 @@
2121
import java.lang.reflect.Method;
2222

2323
/**
24-
* A strategy for assigning a name to a controller method mapping.
24+
* A strategy for assigning a name to a handler method's mapping.
25+
*
26+
* <p>The strategy can be configured on
27+
* {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
28+
* AbstractHandlerMethodMapping}. It is used to assign a name to the mapping of
29+
* every registered handler method. The names can then be queried via
30+
* {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerMethodsForMappingName(String)
31+
* AbstractHandlerMethodMapping#getHandlerMethodsForMappingName}.
32+
*
33+
* <p>Applications can build a URL to a controller method by name with the help
34+
* of the static method
35+
* {@link org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder#fromMappingName(String)
36+
* MvcUriComponentsBuilder#fromMappingName} or in JSPs through the "mvcUrl"
37+
* function registered by the Spring tag library.
2538
*
2639
* @author Rossen Stoyanchev
2740
* @since 4.1

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -193,38 +193,62 @@ public static UriComponentsBuilder fromMethodCall(Object invocationInfo) {
193193
}
194194

195195
/**
196-
* Create a {@link UriComponentsBuilder} from a request mapping identified
197-
* by name. The configured
196+
* Create a URL from the name of a Spring MVC controller method's request mapping.
197+
*
198+
* <p>The configured
198199
* {@link org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy
199-
* HandlerMethodMappingNamingStrategy} assigns a default name to every
200-
* {@code @RequestMapping} method but an explicit name may also be assigned
201-
* through the {@code @RequestMapping} name attribute.
202-
* <p>This is intended for use in EL expressions, typically in JSPs or other
203-
* view templates, which can use the convenience method {@link #toUriString()}.
204-
* <p>The default naming convention for mappings is based on the capital
205-
* letters of the class name, followed by "#" as a separator, and the method
206-
* name. For example "TC#getFoo" for a class named TestController with method
207-
* getFoo. Use explicit names where the naming convention does not produce
208-
* unique results.
209-
* @param name the mapping name
210-
* @param argumentValues argument values for the controller method; those values
211-
* are important for {@code @RequestParam} and {@code @PathVariable} arguments
212-
* but may be passed as {@code null} otherwise.
213-
* @return the UriComponentsBuilder
200+
* HandlerMethodMappingNamingStrategy} determines the names of controller
201+
* method request mappings at startup. By default all mappings are assigned
202+
* a name based on the capital letters of the class name, followed by "#" as
203+
* separator, and then the method name. For example "PC#getPerson"
204+
* for a class named PersonController with method getPerson. In case the
205+
* naming convention does not produce unique results, an explicit name may
206+
* be assigned through the name attribute of the {@code @RequestMapping}
207+
* annotation.
208+
*
209+
* <p>This is aimed primarily for use in view rendering technologies and EL
210+
* expressions. The Spring URL tag library registers this method as a function
211+
* called "mvcUrl".
212+
*
213+
* <p>For example, given this controller:
214+
* <pre class="code">
215+
* &#064;RequestMapping("/people")
216+
* class PersonController {
217+
*
218+
* &#064;RequestMapping("/{id}")
219+
* public HttpEntity<Void> getPerson(&#064;PathVariable String id) { ... }
220+
*
221+
* }
222+
* </pre>
223+
*
224+
* A JSP can prepare a URL to the controller method as follows:
225+
*
226+
* <pre class="code">
227+
* <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
228+
*
229+
* &lt;a href="${s:mvcUrl('PC#getPerson').arg(0,"123").build()}"&gt;Get Person&lt;/a&gt;
230+
* </pre>
231+
*
232+
* <p>Note that it's not necessary to specify all arguments. Only the ones
233+
* required to prepare the URL, mainly {@code @RequestParam} and {@code @PathVariable}).
234+
*
235+
* @param mappingName the mapping name
236+
* @return a builder to to prepare the URI String
214237
* @throws IllegalArgumentException if the mapping name is not found or
215238
* if there is no unique match
216239
* @since 4.1
217240
*/
218-
public static UriComponentsBuilder fromMappingName(String name, Object... argumentValues) {
219-
RequestMappingInfoHandlerMapping hm = getRequestMappingInfoHandlerMapping();
220-
List<HandlerMethod> handlerMethods = hm.getHandlerMethodsForMappingName(name);
241+
public static MethodArgumentBuilder fromMappingName(String mappingName) {
242+
RequestMappingInfoHandlerMapping handlerMapping = getRequestMappingInfoHandlerMapping();
243+
List<HandlerMethod> handlerMethods = handlerMapping.getHandlerMethodsForMappingName(mappingName);
221244
if (handlerMethods == null) {
222-
throw new IllegalArgumentException("Mapping name not found: " + name);
245+
throw new IllegalArgumentException("Mapping mappingName not found: " + mappingName);
223246
}
224247
if (handlerMethods.size() != 1) {
225-
throw new IllegalArgumentException("No unique match for mapping name " + name + ": " + handlerMethods);
248+
throw new IllegalArgumentException(
249+
"No unique match for mapping mappingName " + mappingName + ": " + handlerMethods);
226250
}
227-
return fromMethod(handlerMethods.get(0).getMethod(), argumentValues);
251+
return new MethodArgumentBuilder(handlerMethods.get(0).getMethod());
228252
}
229253

230254
/**
@@ -455,4 +479,37 @@ public interface MethodInvocationInfo {
455479
Object[] getArgumentValues();
456480
}
457481

482+
483+
public static class MethodArgumentBuilder {
484+
485+
private final Method method;
486+
487+
private final Object[] argumentValues;
488+
489+
490+
public MethodArgumentBuilder(Method method) {
491+
Assert.notNull(method, "'method' is required");
492+
this.method = method;
493+
this.argumentValues = new Object[method.getParameterTypes().length];
494+
for (int i = 0; i < this.argumentValues.length; i++) {
495+
this.argumentValues[i] = null;
496+
}
497+
}
498+
499+
public MethodArgumentBuilder arg(int index, Object value) {
500+
this.argumentValues[index] = value;
501+
return this;
502+
}
503+
504+
public String build() {
505+
return MvcUriComponentsBuilder.fromMethod(this.method, this.argumentValues)
506+
.build(false).encode().toUriString();
507+
}
508+
509+
public String buildAndExpand(Object... uriVariables) {
510+
return MvcUriComponentsBuilder.fromMethod(this.method, this.argumentValues)
511+
.build(false).expand(uriVariables).encode().toString();
512+
}
513+
}
514+
458515
}

spring-webmvc/src/main/resources/META-INF/spring.tld

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,4 +472,11 @@
472472
</attribute>
473473
</tag>
474474

475+
<function>
476+
<description>Helps to prepare a URL to a Spring MVC controller method.</description>
477+
<name>mvcUrl</name>
478+
<function-class>org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder</function-class>
479+
<function-signature>org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.MethodArgumentBuilder fromMappingName(java.lang.String)</function-signature>
480+
</function>
481+
475482
</taglib>

0 commit comments

Comments
 (0)