1. 程式人生 > >SpringMVC之url的使用

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

。MappingRegistry裡面有多個map,用來儲存URL和Handler的對應關係。當前需要用到的是nameLookup。裡面儲存的是name和handlerMethos的對應關係,name的獲取規則是 類名的大寫字母+“#”+方法名。spring4.2之前的版本,用的是MultiValueMap,這個是一Key多Value的Map集合。spring4.2之後,做了程式碼優化,使用 ConcurrentHashMap用來提高效率。

// 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原始碼分析與實踐>一書。