SpringMVC源码情操陶冶-ViewResolver视图解析
2017-07-19 21:24
549 查看
简单分析springmvc是如何解析view视图,并返回页面给前端
SpringMVC配置视图解析器
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property key="prefix" value="/WEB-INF/jsp/"/> <property key="suffix" value=".jsp" /> </bean>
配置的为
jsp的解析器
ViewResolver接口
其内部只有一个接口方法,具体如下View resolveViewName(String viewName, Locale locale) throws Exception;
由上可知其是通过解析ViewName来得到View视图对象
ViewResolver实现类-BeanNameViewResolver
其意图是参数viewName就是springmvc上下文中的beanName对象,具体源码如下
@Override public View resolveViewName(String viewName, Locale locale) throws BeansException { //获得springmvc上下文 ApplicationContext context = getApplicationContext(); if (!context.containsBean(viewName)) { //viewName不存在,则直接返回null return null; } if (!context.isTypeMatch(viewName, View.class)) { //viewName对应的beanName不是View.class的实现类,则直接返回 return null; } return context.getBean(viewName, View.class); }
BeanNameResolver表示返回的viewName必须是springmvc上下文中的beanName并且对应的实体类必须是View.class的实现类,否则返回null
ViewResolver实现类-AbstractCachingViewResolver
其是我们常用解析器的抽象类,比如Freemarker/Groovy,我们直接去看其实现的接口方法,具体源码如下
@Override public View resolveViewName(String viewName, Locale locale) throws Exception { //不采用缓存方案,则每次都进行创建View if (!isCache()) { return createView(viewName, locale); } else { //此处为使用缓存情况下的获取View对象 Object cacheKey = getCacheKey(viewName, locale); View view = this.viewAccessCache.get(cacheKey); if (view == null) { synchronized (this.viewCreationCache) { view = this.viewCreationCache.get(cacheKey); if (view == null) { // Ask the subclass to create the View object. view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { //默认会返回一个null的View对象 view = UNRESOLVED_VIEW; } if (view != null) { this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } } } } return (view != UNRESOLVED_VIEW ? view : null); } }
接以上代码我们接着分析
AbstractCachingViewResolver#createView()方法
protected View createView(String viewName, Locale locale) throws Exception { //此处的loadView便是模板方法,供子类去实现 return loadView(viewName, locale); }
此处我们只分析其某个实现类
UrlBasedViewResolver
UrlBasedViewResolver-对应请求url的解析器
常用的内部属性public static final String REDIRECT_URL_PREFIX = "redirect:"; public static final String FORWARD_URL_PREFIX = "forward:"; //设置前缀 private String prefix = ""; //设置后缀 private String suffix = ""; //设置指定的viewName集合 private String[] viewNames ;
createView()复写父类方法,即在创建view对象前做下跳转的请求检查
@Override protected View createView(String viewName, Locale locale) throws Exception { //viewNames集合为null或者对应的viewName在viewNames集合内则返回true if (!canHandle(viewName, locale)) { return null; } // Check for special "redirect:" prefix. //检查handler返回的值为string类型时是否包含"redirect:"前缀 //此处处理的便是跳转请求,比如"redirect:/user/list" if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); return applyLifecycleMethods(viewName, view); } // Check for special "forward:" prefix. //同"redirect:"请求,此处为服务端直接跳转 if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); return new InternalResourceView(forwardUrl); } //通过父类再去调用loadView()方法,其实是本类也复写了此方法 return super.createView(viewName, locale); }
loadView()复写方法
@Override protected View loadView(String viewName, Locale locale) throws Exception { //创建View对象 AbstractUrlBasedView view = buildView(viewName); //将view对象与viewName绑定注册至springmvc上下文中 View result = applyLifecycleMethods(viewName, view); return (view.checkResource(locale) ? result : null); }
buildView()创建View对象主逻辑
protected AbstractUrlBasedView buildView(String viewName) throws Exception { //获取类似FreemarkerView.class/GroovyView.class AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); //设置view对应的资源路径,此处便可知我们设置prefix和suffix的作用 view.setUrl(getPrefix() + viewName + getSuffix()); //下面都是设置与UrlBasedViewResolver的相关内部属性 String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); //是否暴露路径变量 Boolean exposePathVariables = getExposePathVariables(); if (exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } //是否暴露springmvc的bean对象作为属性使用 Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); if (exposeContextBeansAsAttributes != null) { view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); } String[] exposedContextBeanNames = getExposedContextBeanNames(); if (exposedContextBeanNames != null) { view.setExposedContextBeanNames(exposedContextBeanNames); } return view; }
主要作用是设置prefix和suffix参数以及对应的内部属性,可自行查阅,并通过
buildView()方法创建
ViewClass属性指定的View对象
AbstractTemplateViewResolver-UrlBasedViewResolver子类
添加另外的属性内部属性
//是否暴露request对象的attributes属性给前端引擎 private boolean exposeRequestAttributes = false; //是否允许请求处理过程中复写request对象的attributes private boolean allowRequestOverride = false; //是否暴露session对象的attributes属性给前端引擎 private boolean exposeSessionAttributes = false; //是否允许请求处理过程中复写session对象的attributes private boolean allowSessionOverride = false; //是否使用暴露springMacroRequestContext属性 private boolean exposeSpringMacroHelpers = true;
buildView()复写方法,主要是额外添加以上的属性
@Override protected AbstractUrlBasedView buildView(String viewName) throws Exception { //先调用父类的创建方法创建View对象 AbstractTemplateView view = (AbstractTemplateView) super.buildView(viewName); //设置AbstractTemplateView的内部属性 view.setExposeRequestAttributes(this.exposeRequestAttributes); view.setAllowRequestOverride(this.allowRequestOverride); view.setExposeSessionAttributes(this.exposeSessionAttributes); view.setAllowSessionOverride(this.allowSessionOverride); view.setExposeSpringMacroHelpers(this.exposeSpringMacroHelpers); return view; }
在UrlBasedViewResolver的基础上设置额外的属性,属性集合见上文
FreeMarkerViewResolver-AbstractTemplateViewResolver子类
为方便理解,我们选取常用的模板引擎Freemarker,其他的引擎工具则供读者自行分析
构造函数-设置viewClass,满足上述的模板方法的viewClass的获取
public FreeMarkerViewResolver() { //设置的为FreemarkView.class setViewClass(requiredViewClass()); }
小结
本节只解析了ViewResolver的简单逻辑,其根据配置的ViewClass属性,将配置的其他属性都设置到ViewClass对应的实例中,具体的关于视图的渲染,也就是
view#render()方法我们放在下节讲解
相关文章推荐
- springMVC源码解析--ViewResolver视图解析器执行(三)
- springMVC源码解析--ViewResolver视图解析器执行(三)
- springMVC源码解析--ViewResolver视图解析器执行(三)
- SpringMVC源码情操陶冶-View视图渲染
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- SpringMVC源码情操陶冶-AbstractHandlerExceptionResolver
- SpringMVC源码情操陶冶-ResourcesBeanDefinitionParser静态资源解析器
- springmvc 使用BeanNameViewResolver解析excel,pdf,json,xml视图
- SpringMVC 视图解析 - ViewResolver
- Spring:SpringMVC 视图解析 - ViewResolver&View
- springmvc中如何正确的解析视图InternalResourceViewResolver
- springmvc返回ModelAndView,视图解析不到jsp
- SpringMVC-Xml视图解析器XmlViewResolver
- [springmvc]返回ModelAndView,视图解析不到jsp,而是去解析“'请求路径'+ ‘.jsp’”
- SpringMVC源码情操陶冶-HandlerAdapter适配器简析
- Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析
- springMVC源码分析--RequestToViewNameTranslator请求到视图名称的转换
- Spring MVC中的视图解析ViewResolver