22_2 Spring MVC - ViewResolver系列 - UrlBasedViewResolver
22_2 Spring MVC - ViewResolver系列 - UrlBasedViewResolver
一、简介
UrlBasedViewResolver是对ViewResolver的一种简单实现,而且继承了AbstractCachingViewResolver,主要提供一种拼接URL的方式来解析视图,它可以通过prefix属性指定一个前缀,通过suffix属性指定一个后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是视图的URL了。如prefix=/WEB-INF/jsps/,suffix=.jsp,返回的视图名称viewName=test/indx,则UrlBasedViewResolver解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp。默认的prefix和suffix都是空串。
1.1 支持 redirect
UrlBasedViewResolver支持返回的视图名称中包含redirect:
前缀,这样就可以支持URL在客户端的跳转,如当返回的视图名称是"redirect:test.do"的时候,UrlBasedViewResolver发现返回的视图名称包含redirect:
前缀,于是把返回的视图名称前缀redirect:
去掉,取后面的test.do组成一个RedirectView。RedirectView中将把请求返回的模型属性组合称查询参数的形式组合到redirect的URL后面,然后调用HttpServletResponse对象的sendRedirect方法进行重定向。
1.2 支持 forword
UrlBasedViewResolver还支持forword:
前缀,对于视图名称中包含forword:
前缀的视图名称将会被封装称一个InternalResourceView对象,然后在服务器端利用RequestDispatcher的forword:
方式跳转到指定的地址。使用UrlBasedViewResolver的时候必须指定属性viewClass,表示解析成哪种视图,一般使用较多的就是InternalResourceView,利用它来展现jsp。
二、源码解析
2.1 createView(String viewName, Locale locale)
createView是创建View的方法,UrlBasedViewResolver类重写了该方法,用来提供对 redirect:
和forword:
形式的支持。
@Override
protected View createView(String viewName, Locale locale) throws Exception {
// 先判断 是否支持 该视图名的处理
if (!canHandle(viewName, locale)) {
return null;
}
// 如果是以redirect: 开头,返回RedirectView
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
RedirectView view = new RedirectView(redirectUrl,
isRedirectContextRelative(), isRedirectHttp10Compatible());
String[] hosts = getRedirectHosts();
if (hosts != null) {
view.setHosts(hosts);
}
return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
}
// 如果是以forword:开头,返回InternalResourceView
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
return new InternalResourceView(forwardUrl);
}
// 其他情况 调用父类的 createView方法
return super.createView(viewName, locale);
}
- 先判断 UrlBasedViewResolver 解析器是否支持当前视图名的解析
- 判断 视图名称是否 以redirect:开头,如果是则构建返回RedirectView
- 判断 视图名称是否 以forword:开头,如果是则返回一个InternalResourceView
- 都不是的情况下调用父类的 createView方法
2.2 loadView(String viewName, Locale locale)
在AbstractCachingViewResolver类中 createView方法最后是通过调用 protected abstract View ``loadView``(``String viewName``, ``Locale locale``) ``throws Exception
方法创建。这个方法是一个抽象方法,具体的实现是通过子类来实现的。
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
AbstractUrlBasedView view = buildView(viewName);
View result = applyLifecycleMethods(viewName, view);
return (view.checkResource(locale) ? result : null);
}
- 通过 buildView方法创建一个 AbstractUrlBasedView 对象
- 通过 applyLifecycleMethods 方法将创建的 View对象交给 Spring容器管理
2.3 buildView(viewName)
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
Class<?> viewClass = getViewClass();
Assert.state(viewClass != null, "No view class");
AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
view.setUrl(getPrefix() + viewName + getSuffix());
String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
}
view.setRequestContextAttribute(getRequestContextAttribute());
view.setAttributesMap(getAttributesMap());
Boolean exposePathVariables = getExposePathVariables();
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
}
return view;
}