Spring MVC架構 - 九大組件 - RequestToViewNameTranslator

Overview

RequestToViewNameTranslator接口,如果請求中沒有明確指定視圖名,會將請求轉化成一個邏輯視圖名。

它提供瞭如下方法:

String getViewName(HttpServletRequest request) throws Exception;

DefaultToViewNameTranslator

在spring-webmvc依賴中,只定義了RequestToViewNameTranslator接口的唯一實現類 - DefaultRequestToViewNameTranslator

它的作用就是,簡單地將請求的URI轉換爲視圖名

可以在DispatcherServlet的上下文中,明確將其定義爲viewNameTranslator的bean。

接下來看一下源碼中如何定義它的屬性和方法的。

prefix - 前綴名 - 默認是""

public void setPrefix(@Nullable String prefix) {
	this.prefix = (prefix != null ? prefix : "");
}

suffix - 後綴名 - 默認是""

public void setSuffix(@Nullable String suffix) {
	this.suffix = (suffix != null ? suffix : "");
}

separator - 分隔符 - 默認是"/"

public void setSeparator(String separator) {
	this.separator = separator;
}

stripLeadingSlash - 跳過首字母的/ - 默認是true

public void setStripLeadingSlash(boolean stripLeadingSlash) {
	this.stripLeadingSlash = stripLeadingSlash;
}

stripTrailingSlash - 跳過尾字母的/ - 默認是true

public void setStripTrailingSlash(boolean stripTrailingSlash) {
	this.stripTrailingSlash = stripTrailingSlash;
}

stripExtension - 跳過拓展名 - 默認是true

public void setStripExtension(boolean stripExtension) {
	this.stripExtension = stripExtension;
}

設置是否在當前的上下文中,url查找總是使用全路徑

public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
	this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
}

設置是否對請求的URI進行解碼

public void setUrlDecode(boolean urlDecode) {
	this.urlPathHelper.setUrlDecode(urlDecode);
}

設置是否刪除分號後面的內容

public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
	this.urlPathHelper.setRemoveSemicolonContent(removeSemicolonContent);
}

設置UrlPathHelper

public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
	Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
	this.urlPathHelper = urlPathHelper;
}

將請求轉化爲視圖名

public String getViewName(HttpServletRequest request) {
	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH);
	return (this.prefix + transformPath(lookupPath) + this.suffix);
}

修改路徑

protected String transformPath(String lookupPath) {
	String path = lookupPath;
	if (this.stripLeadingSlash && path.startsWith(SLASH)) {
		/* 跳過首字母的斜槓 */
		path = path.substring(1);
	}
	if (this.stripTrailingSlash && path.endsWith(SLASH)) {
		/* 跳過尾字母的斜槓 */
		path = path.substring(0, path.length() - 1);
	}
	if (this.stripExtension) {
		/* 跳過文件拓展名 */
		path = StringUtils.stripFilenameExtension(path);
	}
	/* 替換分隔符 */
	if (!SLASH.equals(this.separator)) {
		path = StringUtils.replace(path, SLASH, this.separator);
	}
	return path;
}

在DispatchServlet中的使用

在DispatchServlet#doDispatch(…)方法中,有這樣一行代碼:applyDefaultViewName(processedRequest, mv);

private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
	/* 如果沒有設置View實例或者視圖名 */
	if (mv != null && !mv.hasView()) {
		String defaultViewName = getDefaultViewName(request);
		if (defaultViewName != null) {
			mv.setViewName(defaultViewName);
		}
	}
}

protected String getDefaultViewName(HttpServletRequest request) throws Exception {
	return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
}

UrlPathHelper

前面設置的UrlPathHelper,這裏呢,簡單看下它與本文相關的方法。

public String getLookupPathForRequest(HttpServletRequest request, @Nullable String lookupPathAttributeName) {
	/* org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping */
	if (lookupPathAttributeName != null) {
		String result = (String) request.getAttribute(lookupPathAttributeName);
		if (result != null) {
			return result;
		}
	}
	return getLookupPathForRequest(request);
}
public String getLookupPathForRequest(HttpServletRequest request) {
	// Always use full path within current servlet context?
	if (this.alwaysUseFullPath) {
		return getPathWithinApplication(request);
	}
	// Else, use path within current servlet mapping if applicable
	String rest = getPathWithinServletMapping(request);
	if (!"".equals(rest)) {
		return rest;
	}
	else {
		return getPathWithinApplication(request);
	}
}

先來看getPathWithinApplication(…)方法,如下:

public String getPathWithinApplication(HttpServletRequest request) {
	String contextPath = getContextPath(request);
	String requestUri = getRequestUri(request);
	String path = getRemainingPath(requestUri, contextPath, true);
	if (path != null) {
		return (StringUtils.hasText(path) ? path : "/");
	}
	else {
		return requestUri;
	}
}

它是用來獲取web application範圍內的給定請求匹配的路徑。

然後看下getPathWithinServletMapping(…)方法。

public String getPathWithinServletMapping(HttpServletRequest request) {
	String pathWithinApp = getPathWithinApplication(request);
	String servletPath = getServletPath(request);
	String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp);
	String path;
	if (servletPath.contains(sanitizedPathWithinApp)) {
		path = getRemainingPath(sanitizedPathWithinApp, servletPath, false);
	}
	else {
		path = getRemainingPath(pathWithinApp, servletPath, false);
	}
	if (path != null) {
		return path;
	}
	else {
		String pathInfo = request.getPathInfo();
		if (pathInfo != null) {
			return pathInfo;
		}
		if (!this.urlDecode) {
			path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false);
			if (path != null) {
				return pathWithinApp;
			}
		}
		return servletPath;
	}
}

這個方法用來返回servlet範圍內的給定請求的匹配的路徑。

e.g.

servlet mapping = “/"; request URI = “/test/a” -> “/test/a”.
servlet mapping = “/”; request URI = “/test/a” -> “/test/a”.
servlet mapping = "/test/
”; request URI = “/test/a” -> “/a”.
servlet mapping = “/test”; request URI = “/test” -> “”.
servlet mapping = “/*.test”; request URI = “/a.test” -> “”.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章