SpringMVC之url的使用
1. 實踐場景
通常情況下。在jsp頁面給<a>標籤加連結,會直接給出一個具體的URL。例1:
<a href="<c:url value='/demo/demo' />">按鈕1</a>
<a href="${pageContext.request.contextPath}/demo/demo">按鈕2</a>
然而,SpringMVC4還提供了另外一種方式,可以通過Controller類名的大寫字元+“#”+方法名,獲得路徑。例2:
<a href="${s:mvcUrl('DC#demo').build()}">按鈕3</a>
2. 程式碼分析
例1是我們絕大部分人的操作。這裡不再細講。
例2是SpringMVC給我們的提供的一個方便操作。需要用到這個標籤。
<%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
標籤裡面定義了一個方法:mvcUrl。對映到MvcUriComponentsBuilder.MethodArgumentBuilder.fromMappingName 。方法的作用很簡單。首先獲得Spring中的RequestMappingInfoHandlerMapping實體類,接著拿到父類的內部類AbstractHandlerMethodMapping.MappingRegistry
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry class MappingRegistry { private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>(); private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>(); private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>(); private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>(); private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>(); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); }
使用nameLookUp解析輸入的字串,獲得對應的handlerMethod,拼裝handlerMethod中controller和method的requestMapping中的值然後輸出。具體操作是通過MvcUriComponentsBuilder中內部類MethodArgumentBuilder的bulid()呼叫外部類的 fromMethodInternal 方法。詳見程式碼:
//org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.MethodArgumentBuilder#build
public String build() {
return fromMethodInternal(this.baseUrl, this.controllerType, this.method,
this.argumentValues).build(false).encode().toUriString();
}
//org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder#fromMethodInternal
private static UriComponentsBuilder fromMethodInternal(UriComponentsBuilder baseUrl,
Class<?> controllerType, Method method, Object... args) {
baseUrl = getBaseUrlToUse(baseUrl);
String typePath = getTypeRequestMapping(controllerType);
String methodPath = getMethodRequestMapping(method);
String path = pathMatcher.combine(typePath, methodPath);
baseUrl.path(path);
UriComponents uriComponents = applyContributors(baseUrl, method, args);
return UriComponentsBuilder.newInstance().uriComponents(uriComponents);
}
3. 優缺點分析
下面詳細分析一下當前使用例2的優缺點。
優點:
1.前端頁面顯示路徑與@RequestMapping註解解耦。可以隨意更改類名和方法的@RequestMapping註解。只要保證類名和方法名不修改即可
2.springMVC4.2以後,為了提高nameMap的使用效率,將nameMap的實現方式,從MultiValueMap改成ConcurrentHashMap。使用併發響應速度大大提高。
缺點:
1. 使用不方便,需要手動寫類大寫和方法名
2. 響應速度慢。需要從NameMap中獲得。如果專案較大,方法較多並且頁面中的連結較多。會降低響應速度。
3. 需要將前端頁面URL和類名的@RequestMapping解耦的地方不多,可用性不高。
綜上所述,需要結合專案的實際情況,綜合考慮使用。推薦使用例1的倆種方法。
SpringMVC使用版本:4.2.4
本文參考<看透SpringMVC原始碼分析與實踐>一書。