RequestToViewNameTranslator
作用 从request中获取viewName
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
*/
String getViewName(HttpServletRequest request) throws Exception;
}
我们知道它是容器中很重要的一个组件,并且是MVC容器的9大组件之一。
1.下这个viewNameTranslator是怎么得到的吧?
它是在容器组件初始化的过程中完成的 initStrategies完成9个组件的初始化包括该组件。
从容器中获取bean,bean 名称为:DefaultRequestToViewNameTranslator
/* Initialize the RequestToViewNameTranslator used by this servlet instance.
* <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
*/
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isDebugEnabled()) {
logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
"]");
}
}
}
2.它是如何完成从request中获取viewName的??
DefalutRequestToViewNameTranslator是它的默认实现类
获取默认view name的真正实现方法如下:
其实其简单实现就是将请求名称作为视图名称返回,逻辑还是比较简单的。
/**
* 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) {
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
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
*/
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;
}
/**
* Return the mapping lookup path for the given request, within the current
* servlet mapping if applicable, else within the web application.
* <p>Detects include request URL if called within a RequestDispatcher include.
* @param request current HTTP request
* @return the lookup path
* @see #getPathWithinApplication
* @see #getPathWithinServletMapping
*/
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);
}
}
/**
* Return the path within the servlet mapping for the given request,
* i.e. the part of the request's URL beyond the part that called the servlet,
* or "" if the whole URL has been used to identify the servlet.
* <p>Detects include request URL if called within a RequestDispatcher include.
* <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
* <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
* <p>E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "".
* @param request current HTTP request
* @return the path within the servlet mapping, or ""
*/
public String getPathWithinServletMapping(HttpServletRequest request) {
String pathWithinApp = getPathWithinApplication(request);
String servletPath = getServletPath(request);
String path = getRemainingPath(pathWithinApp, servletPath, false);
if (path != null) {
// Normal case: URI contains servlet path.
return path;
}
else {
// Special case: URI is different from servlet path.
String pathInfo = request.getPathInfo();
if (pathInfo != null) {
// Use path info if available. Indicates index page within a servlet mapping?
// e.g. with index page: URI="/", servletPath="/index.html"
return pathInfo;
}
if (!this.urlDecode) {
// No path info... (not mapped by prefix, nor by extension, nor "/*")
// For the default servlet mapping (i.e. "/"), urlDecode=false can
// cause issues since getServletPath() returns a decoded path.
// If decoding pathWithinApp yields a match just use pathWithinApp.
path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false);
if (path != null) {
return pathWithinApp;
}
}
// Otherwise, use the full servlet path.
return servletPath;
}
}
/**
* Return the path within the web application for the given request.
* <p>Detects include request URL if called within a RequestDispatcher include.
* @param request current HTTP request
* @return the path within the web application
*/
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
String path = getRemainingPath(requestUri, contextPath, true);
if (path != null) {
// Normal case: URI contains context path.
return (StringUtils.hasText(path) ? path : "/");
}
else {
return requestUri;
}
}
/**
* Match the given "mapping" to the start of the "requestUri" and if there
* is a match return the extra part. This method is needed because the
* context path and the servlet path returned by the HttpServletRequest are
* stripped of semicolon content unlike the requesUri.
*/
private String getRemainingPath(String requestUri, String mapping, boolean ignoreCase) {
int index1 = 0;
int index2 = 0;
for (; (index1 < requestUri.length()) && (index2 < mapping.length()); index1++, index2++) {
char c1 = requestUri.charAt(index1);
char c2 = mapping.charAt(index2);
if (c1 == ';') {
index1 = requestUri.indexOf('/', index1);
if (index1 == -1) {
return null;
}
c1 = requestUri.charAt(index1);
}
if (c1 == c2) {
continue;
}
if (ignoreCase && (Character.toLowerCase(c1) == Character.toLowerCase(c2))) {
continue;
}
return null;
}
if (index2 != mapping.length()) {
return null;
}
if (index1 == requestUri.length()) {
return "";
}
else if (requestUri.charAt(index1) == ';') {
index1 = requestUri.indexOf('/', index1);
}
return (index1 != -1 ? requestUri.substring(index1) : "");
}
DefalutRequestToViewNameTranslator完整源码点这里。—》