概述
这是Spring MVC
定义的一个策略接口,它根据请求对象自身的属性解析出一个逻辑视图名称,通常用在没有针对请求明确指定视图的场景。
RequestToViewNameTranslator
被DispatcherServlet
使用 :
/**
* Translate the supplied request into a default view name.
* 尝试从请求本身信息翻译出一个视图名称,用以作为处理该请求的缺省视图
* @param request current HTTP servlet request
* @return the view name (or {@code null} if no default found)
* @throws Exception if view name translation failed
*/
@Nullable
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
}
源代码
源代码版本 :
spring-webmvc-5.1.5.RELEASE
1. 接口RequestToViewNameTranslator
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import org.springframework.lang.Nullable;
public interface RequestToViewNameTranslator {
/**
* Translate the given {@link HttpServletRequest} into a view name.
* 从指定的请求对象中翻译出相应的视图名称
* @param request the incoming {@link HttpServletRequest} providing
* the context from which a view name is to be resolved
* @return the view name, or {@code null} if no default found
* @throws Exception if view name translation fails
*/
@Nullable
String getViewName(HttpServletRequest request) throws Exception;
}
Spring MVC
对RequestToViewNameTranslator
接口提供了一个缺省实现DefaultRequestToViewNameTranslator
。
2. 缺省实现类 DefaultRequestToViewNameTranslator
package org.springframework.web.servlet.view;
// 省略 import 行
public class DefaultRequestToViewNameTranslator implements RequestToViewNameTranslator {
private static final String SLASH = "/";
private String prefix = "";
private String suffix = "";
// 指定要使用的分隔符,缺省值使用 /
private String separator = SLASH;
// 是否要去除前缀/,缺省值为 true
private boolean stripLeadingSlash = true;
// 是否要去除后缀/,缺省值为 true
private boolean stripTrailingSlash = true;
// 是否要去除文件扩展名,缺省值为 true
private boolean stripExtension = true;
// URL 路径操作小助手,工具类,缺省值为 UrlPathHelper 对象
private UrlPathHelper urlPathHelper = new UrlPathHelper();
/**
* Set the prefix to prepend to generated view names.
* @param prefix the prefix to prepend to generated view names
*/
public void setPrefix(@Nullable String prefix) {
this.prefix = (prefix != null ? prefix : "");
}
/**
* Set the suffix to append to generated view names.
* @param suffix the suffix to append to generated view names
*/
public void setSuffix(@Nullable String suffix) {
this.suffix = (suffix != null ? suffix : "");
}
/**
* Set the value that will replace '{@code /}' as the separator
* in the view name. The default behavior simply leaves '{@code /}'
* as the separator.
*/
public void setSeparator(String separator) {
this.separator = separator;
}
/**
* Set whether or not leading slashes should be stripped from the URI when
* generating the view name. Default is "true".
*/
public void setStripLeadingSlash(boolean stripLeadingSlash) {
this.stripLeadingSlash = stripLeadingSlash;
}
/**
* Set whether or not trailing slashes should be stripped from the URI when
* generating the view name. Default is "true".
*/
public void setStripTrailingSlash(boolean stripTrailingSlash) {
this.stripTrailingSlash = stripTrailingSlash;
}
/**
* Set whether or not file extensions should be stripped from the URI when
* generating the view name. Default is "true".
*/
public void setStripExtension(boolean stripExtension) {
this.stripExtension = stripExtension;
}
/**
* Shortcut to same property on underlying {@link #setUrlPathHelper UrlPathHelper}.
* @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
}
/**
* Shortcut to same property on underlying {@link #setUrlPathHelper UrlPathHelper}.
* @see org.springframework.web.util.UrlPathHelper#setUrlDecode
*/
public void setUrlDecode(boolean urlDecode) {
this.urlPathHelper.setUrlDecode(urlDecode);
}
/**
* Set if ";" (semicolon) content should be stripped from the request URI.
* @see org.springframework.web.util.UrlPathHelper#setRemoveSemicolonContent(boolean)
*/
public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
this.urlPathHelper.setRemoveSemicolonContent(removeSemicolonContent);
}
/**
* Set the {@link org.springframework.web.util.UrlPathHelper} to use for
* the resolution of lookup paths.
* <p>Use this to override the default UrlPathHelper with a custom subclass,
* or to share common UrlPathHelper settings across multiple web components.
*/
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
this.urlPathHelper = urlPathHelper;
}
/**
* Translates the request URI of the incoming {@link HttpServletRequest}
* into the view name based on the configured parameters.
* @see org.springframework.web.util.UrlPathHelper#getLookupPathForRequest
* @see #transformPath
*/
@Override
public String getViewName(HttpServletRequest request) {
// 使用 urlPathHelper 找到 request 的查找路径,记录到 lookupPath
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 1. 对 lookupPath 做变形处理,去除前缀后缀/,文件扩展名等 ;
// 2. 加上指定的前缀后缀 prefix/suffix ;
return (this.prefix + transformPath(lookupPath) + this.suffix);
}
/**
* Transform the request URI (in the context of the webapp) stripping
* slashes and extensions, and replacing the separator as required.
* @param lookupPath the lookup path for the current request,
* as determined by the UrlPathHelper
* @return the transformed path, with slashes and extensions stripped
* if desired
*/
@Nullable
protected String transformPath(String lookupPath) {
String path = lookupPath;
if (this.stripLeadingSlash && path.startsWith(SLASH)) {
// 如果被要求去除前缀/,并且 lookupPath 以/为前缀,则去除该前缀
path = path.substring(1);
}
if (this.stripTrailingSlash && path.endsWith(SLASH)) {
// 如果被要求去除后缀/,并且 lookupPath 以/为后缀,则去除该后缀
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;
}
}
DefaultRequestToViewNameTranslator
是Spring MVC
对接口RequestToViewNameTranslator
的缺省实现。在实现DefaultRequestToViewNameTranslator
中,针对请求翻译相应的逻辑视图名称时,它先使用UrlPathHelper
获取该请求的lookupPath
,然后按要求变形后返回。缺省情况下,具体的变形如下:
- 去除前缀/
- 去除后缀/
- 去除文件扩展名部分
- 如果指定的分隔符不是/,则将路径中所有的/替换成/
- 添加指定的前缀和后缀
Spring MVC
前端控制器DispatcherServlet
缺省使用的RequestToViewNameTranslator
就是DefaultRequestToViewNameTranslator
。在缺省配置文件spring-webmvc-5.1.5.RELEASE.jar!\org\springframework\web\servlet\DispatcherServlet.properties
中有这样的定义 :
org.springframework.web.servlet.RequestToViewNameTranslator
=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
另外在DispatcherServlet
对象初始化时,它会在找不到外部定义到容器中的RequestToViewNameTranslator
时使用DefaultRequestToViewNameTranslator
:
// DispatcherServlet 代码实现
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
// 首先尝试从容器中获取类型为 RequestToViewNameTranslator 的 bean组件供使用
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.viewNameTranslator);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 如果从容器中找不到类型为 RequestToViewNameTranslator 的bean,提取缺省值,也就是
// DispatcherServlet.properties 文件中定义的 DefaultRequestToViewNameTranslator
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
}
}
}