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” -> “”.