Add naming strategy for @MVC request mappings.
This change adds a strategy for assigning a default name to an @RequestMapping controller method. The @RequestMapping annotation itself now has a name attribute allowing the explicit assignment of a mapping name. This is mainly intended for use in EL expressions in views. The RequestContext class now provides a getMvcUrl method that internally delegates to MvcUriComponents to look up the handler method. See the Javadoc of MvcUriComponents.fromMappingName. Issue: SPR-5779
This commit is contained in:
@@ -71,10 +71,15 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
|
||||
private boolean detectHandlerMethodsInAncestorContexts = false;
|
||||
|
||||
private HandlerMethodMappingNamingStrategy<T> namingStrategy;
|
||||
|
||||
|
||||
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
|
||||
|
||||
private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
|
||||
|
||||
private final MultiValueMap<String, HandlerMethod> nameMap = new LinkedMultiValueMap<String, HandlerMethod>();
|
||||
|
||||
|
||||
/**
|
||||
* Whether to detect handler methods in beans in ancestor ApplicationContexts.
|
||||
@@ -88,6 +93,16 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
this.detectHandlerMethodsInAncestorContexts = detectHandlerMethodsInAncestorContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the naming strategy to use for assigning a default name to every
|
||||
* mapped handler method.
|
||||
*
|
||||
* @param namingStrategy strategy to use.
|
||||
*/
|
||||
public void setHandlerMethodMappingNamingStrategy(HandlerMethodMappingNamingStrategy<T> namingStrategy) {
|
||||
this.namingStrategy = namingStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map with all handler methods and their mappings.
|
||||
*/
|
||||
@@ -95,6 +110,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
return Collections.unmodifiableMap(this.handlerMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the handler methods mapped to the mapping with the given name.
|
||||
* @param mappingName the mapping name
|
||||
*/
|
||||
public List<HandlerMethod> getHandlerMethodsForMappingName(String mappingName) {
|
||||
return this.nameMap.get(mappingName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects handler methods at initialization.
|
||||
*/
|
||||
@@ -203,6 +226,34 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
this.urlMap.add(pattern, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.namingStrategy != null) {
|
||||
String name = this.namingStrategy.getName(newHandlerMethod, mapping);
|
||||
updateNameMap(name, newHandlerMethod);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNameMap(String name, HandlerMethod newHandlerMethod) {
|
||||
|
||||
List<HandlerMethod> handlerMethods = this.nameMap.get(name);
|
||||
if (handlerMethods != null) {
|
||||
for (HandlerMethod handlerMethod : handlerMethods) {
|
||||
if (handlerMethod.getMethod().equals(newHandlerMethod.getMethod())) {
|
||||
logger.trace("Mapping name already registered. Multiple controller instances perhaps?");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.trace("Mapping name=" + name);
|
||||
this.nameMap.add(name, newHandlerMethod);
|
||||
|
||||
if (this.nameMap.get(name).size() > 1) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Mapping name clash for handlerMethods=" + this.nameMap.get(name) +
|
||||
". Consider assigning explicit names.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.handler;
|
||||
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A strategy for assigning a name to a controller method mapping.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
public interface HandlerMethodMappingNamingStrategy<T> {
|
||||
|
||||
/**
|
||||
* Determine the name for the given HandlerMethod and mapping.
|
||||
*
|
||||
* @param handlerMethod the handler method
|
||||
* @param mapping the mapping
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getName(HandlerMethod handlerMethod, T mapping);
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
|
||||
@@ -45,6 +46,8 @@ import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondit
|
||||
*/
|
||||
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final PatternsRequestCondition patternsCondition;
|
||||
|
||||
private final RequestMethodsRequestCondition methodsCondition;
|
||||
@@ -60,13 +63,11 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
private final RequestConditionHolder customConditionHolder;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given request conditions.
|
||||
*/
|
||||
public RequestMappingInfo(PatternsRequestCondition patterns, RequestMethodsRequestCondition methods,
|
||||
public RequestMappingInfo(String name, PatternsRequestCondition patterns, RequestMethodsRequestCondition methods,
|
||||
ParamsRequestCondition params, HeadersRequestCondition headers, ConsumesRequestCondition consumes,
|
||||
ProducesRequestCondition produces, RequestCondition<?> custom) {
|
||||
|
||||
this.name = (StringUtils.hasText(name) ? name : null);
|
||||
this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
|
||||
this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
|
||||
this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
|
||||
@@ -76,15 +77,32 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
this.customConditionHolder = new RequestConditionHolder(custom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given request conditions.
|
||||
*/
|
||||
public RequestMappingInfo(PatternsRequestCondition patterns, RequestMethodsRequestCondition methods,
|
||||
ParamsRequestCondition params, HeadersRequestCondition headers, ConsumesRequestCondition consumes,
|
||||
ProducesRequestCondition produces, RequestCondition<?> custom) {
|
||||
|
||||
this(null, patterns, methods, params, headers, consumes, produces, custom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-create a RequestMappingInfo with the given custom request condition.
|
||||
*/
|
||||
public RequestMappingInfo(RequestMappingInfo info, RequestCondition<?> customRequestCondition) {
|
||||
this(info.patternsCondition, info.methodsCondition, info.paramsCondition, info.headersCondition,
|
||||
this(info.name, info.patternsCondition, info.methodsCondition, info.paramsCondition, info.headersCondition,
|
||||
info.consumesCondition, info.producesCondition, customRequestCondition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name for this mapping, or {@code null}.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL patterns of this {@link RequestMappingInfo};
|
||||
* or instance with 0 patterns, never {@code null}.
|
||||
@@ -148,6 +166,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
*/
|
||||
@Override
|
||||
public RequestMappingInfo combine(RequestMappingInfo other) {
|
||||
String name = combineNames(other);
|
||||
PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition);
|
||||
RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition);
|
||||
ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition);
|
||||
@@ -156,7 +175,21 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition);
|
||||
RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder);
|
||||
|
||||
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom.getCondition());
|
||||
return new RequestMappingInfo(name, patterns,
|
||||
methods, params, headers, consumes, produces, custom.getCondition());
|
||||
}
|
||||
|
||||
private String combineNames(RequestMappingInfo other) {
|
||||
if (this.name != null && other.name != null) {
|
||||
String separator = RequestMappingInfoHandlerMethodMappingNamingStrategy.SEPARATOR;
|
||||
return this.name + separator + other.name;
|
||||
}
|
||||
else if (this.name != null) {
|
||||
return this.name;
|
||||
}
|
||||
else {
|
||||
return (other.name != null ? other.name : null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +221,8 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
return null;
|
||||
}
|
||||
|
||||
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom.getCondition());
|
||||
return new RequestMappingInfo(this.name, patterns,
|
||||
methods, params, headers, consumes, produces, custom.getCondition());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ import org.springframework.web.util.WebUtils;
|
||||
*/
|
||||
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
|
||||
|
||||
|
||||
protected RequestMappingInfoHandlerMapping() {
|
||||
setHandlerMethodMappingNamingStrategy(new RequestMappingInfoHandlerMethodMappingNamingStrategy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL path patterns associated with this {@link RequestMappingInfo}.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A {@link org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy
|
||||
* HandlerMethodMappingNamingStrategy} for {@code RequestMappingInfo}-based handler
|
||||
* method mappings.
|
||||
*
|
||||
* If the {@code RequestMappingInfo} name attribute is set, its value is used.
|
||||
* Otherwise the name 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.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
public class RequestMappingInfoHandlerMethodMappingNamingStrategy
|
||||
implements HandlerMethodMappingNamingStrategy<RequestMappingInfo> {
|
||||
|
||||
/** Separator between the type and method-level parts of a HandlerMethod mapping name */
|
||||
public static final String SEPARATOR = "#";
|
||||
|
||||
|
||||
@Override
|
||||
public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
|
||||
if (mapping.getName() != null) {
|
||||
return mapping.getName();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String simpleTypeName = handlerMethod.getBeanType().getSimpleName();
|
||||
for (int i = 0 ; i < simpleTypeName.length(); i++) {
|
||||
if (Character.isUpperCase(simpleTypeName.charAt(i))) {
|
||||
sb.append(simpleTypeName.charAt(i));
|
||||
}
|
||||
}
|
||||
sb.append(SEPARATOR).append(handlerMethod.getMethod().getName());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -29,6 +30,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.target.EmptyTargetSource;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
@@ -50,9 +52,11 @@ import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.CompositeUriComponentsContributor;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
@@ -195,6 +199,43 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
|
||||
return fromMethod(info.getControllerMethod(), info.getArgumentValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link UriComponentsBuilder} from a request mapping identified
|
||||
* by name. 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.
|
||||
*
|
||||
* <p>This is intended for use in EL expressions, typically in JSPs or other
|
||||
* view templates, which can use the convenience method:
|
||||
* {@link org.springframework.web.servlet.support.RequestContext#getMvcUrl(String, Object...)
|
||||
* RequestContext.getMvcUrl(String, Object...)}).
|
||||
*
|
||||
* <p>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
|
||||
*
|
||||
* @throws java.lang.IllegalStateException if the mapping name is not found
|
||||
* or there is no unique match
|
||||
*/
|
||||
public static UriComponentsBuilder fromMappingName(String name, Object... argumentValues) {
|
||||
RequestMappingInfoHandlerMapping hm = getRequestMappingInfoHandlerMapping();
|
||||
List<HandlerMethod> handlerMethods = hm.getHandlerMethodsForMappingName(name);
|
||||
Assert.state(handlerMethods != null, "Mapping name not found: " + name);
|
||||
Assert.state(handlerMethods.size() == 1, "No unique match for mapping name " + name + ": " + handlerMethods);
|
||||
return fromMethod(handlerMethods.get(0).getMethod(), argumentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link UriComponentsBuilder} from the mapping of a controller method
|
||||
* and an array of method argument values. The array of values must match the
|
||||
@@ -263,6 +304,37 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
|
||||
}
|
||||
|
||||
protected static CompositeUriComponentsContributor getConfiguredUriComponentsContributor() {
|
||||
WebApplicationContext wac = getWebApplicationContext();
|
||||
if (wac == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return wac.getBean(MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME, CompositeUriComponentsContributor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No CompositeUriComponentsContributor bean with name '" +
|
||||
MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME + "'");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static RequestMappingInfoHandlerMapping getRequestMappingInfoHandlerMapping() {
|
||||
WebApplicationContext wac = getWebApplicationContext();
|
||||
Assert.notNull(wac, "Cannot lookup handler method mappings without WebApplicationContext");
|
||||
try {
|
||||
return wac.getBean(RequestMappingInfoHandlerMapping.class);
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("More than one RequestMappingInfoHandlerMapping beans found", ex);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No RequestMappingInfoHandlerMapping bean", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static WebApplicationContext getWebApplicationContext() {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes == null) {
|
||||
logger.debug("No request bound to the current thread: is DispatcherSerlvet used?");
|
||||
@@ -281,17 +353,7 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
|
||||
logger.debug("No WebApplicationContext found: not in a DispatcherServlet request?");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return wac.getBean(MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME, CompositeUriComponentsContributor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No CompositeUriComponentsContributor bean with name '" +
|
||||
MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME + "'");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return wac;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -123,23 +123,34 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeMethodArgument(MethodParameter parameter, Object value,
|
||||
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) {
|
||||
public void contributeMethodArgument(MethodParameter param, Object value,
|
||||
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService cs) {
|
||||
|
||||
if (Map.class.isAssignableFrom(parameter.getParameterType())) {
|
||||
if (Map.class.isAssignableFrom(param.getParameterType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PathVariable annot = parameter.getParameterAnnotation(PathVariable.class);
|
||||
String name = StringUtils.isEmpty(annot.value()) ? parameter.getParameterName() : annot.value();
|
||||
|
||||
if (conversionService != null) {
|
||||
value = conversionService.convert(value, new TypeDescriptor(parameter), STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
PathVariable annot = param.getParameterAnnotation(PathVariable.class);
|
||||
String name = (StringUtils.isEmpty(annot.value()) ? param.getParameterName() : annot.value());
|
||||
value = formatUriValue(cs, new TypeDescriptor(param), value);
|
||||
uriVariables.put(name, value);
|
||||
}
|
||||
|
||||
protected String formatUriValue(ConversionService cs, TypeDescriptor sourceType, Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
else if (cs != null) {
|
||||
return (String) cs.convert(value, sourceType, STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class PathVariableNamedValueInfo extends NamedValueInfo {
|
||||
|
||||
|
||||
@@ -234,6 +234,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
|
||||
String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
|
||||
return new RequestMappingInfo(
|
||||
annotation.name(),
|
||||
new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
|
||||
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
|
||||
new RequestMethodsRequestCondition(annotation.method()),
|
||||
|
||||
@@ -47,6 +47,7 @@ import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.LocaleContextResolver;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.ThemeResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
@@ -596,6 +597,18 @@ public class RequestContext {
|
||||
return this.urlPathHelper.getOriginatingQueryString(this.request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a URL derived from a controller method's {@code @RequestMapping}.
|
||||
* This method internally uses
|
||||
* {@link org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder#fromMappingName(String, Object...)
|
||||
* MvcUriComponentsBuilder#fromMappingName(String, Object...)}. See its
|
||||
* Javadoc for more details.
|
||||
*/
|
||||
public String getMvcUrl(String mappingName, Object... handlerMethodArguments) {
|
||||
return MvcUriComponentsBuilder.fromMappingName(
|
||||
mappingName, handlerMethodArguments).build().encode().toUriString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
|
||||
* @param code code of the message
|
||||
|
||||
Reference in New Issue
Block a user