目录
三、ContentNegotiatingViewResolver分析
ContentNegotiatingViewResolver解析器配置
四、AbstractCachingViewResolver相关类分析
六、InternalResourceViewResolver类
一、ViewResolver体系介绍
1、ViewResolver组件是啥
在我们学习SpringMVC框架的时候最熟悉的其 “一Servlet三组件”
DispatcherServlet:SpringMVC处理请求的入口类
HandlerMapping(处理器映射器):用于根据请求获取(映射)到一个Handler对象(通常是我们真实场景中的Controller的使用@RequestingMapping注解修饰的方法)
HandlerAdapter(处理器适配器):对获取到的Handler对象进行调用处理获取到ModelView对象。
ViewResolver(视图解析器):对于处理器适配器获取到的对象进行解析获取对应的视图最终呈现给浏览器进行渲染(比如jsp页面,freeMarket模板语言)
在前面的博文中我们已经分析了SpringMVC的处理流程、HandlerMapping原理分析、HandlerAdapter原理分析,现在该说一说ViewResolver组件的相关逻辑了。
总结:
ViewResolver组件是根据String类型的视图名和对应的Locale(语言环境 国际化相关)解析出View对象,而View对象则是用来将数据填充进来,并解析成对应的html(也可能是其他类型)类型的文件渲染给前台。View对象是根据不同的类型使用某些模块来渲染的,比如针对jsp类型使用JstlView进行渲染。
2、ViewResolver体系介绍
ViewResolver只有一个接口方法resolveViewName
/根据名字在不同的地区语言环境中解析出View视图对象
View resolveViewName(String viewName, Locale locale) throws Exception;
ViewResolver接口全览
ViewResolver接口结构概览
总体的该就有四大类(StaticViewResolver 除外 用于单元测试)
1、BeanNameViewResolver: 根据名字获取对应的视图对象
2、ContentNegituatingViewResolver: 根据请求的MediaTypes(context-type)来获取最佳的View对象
3、AbstractCachingViewResolver: 可以缓存解析过的视图对象的基类,亮点是视图解析后的缓存,实现了相关固定化的功能,提供变化的抽象功能交由子类实现,我们常使用的jsp相关的视图InternalResourceViewResolver,以及freeMarket模板语言的FreeMarkerViewResolver解析器。
4、ViewResolverComposite: 是包含如上各个ViewResolver的组合类
接下来我们分别对其中的三种不同类型进行分别分析BeanNameViewResolver
、ContentNegituatingViewResolver、AbstractCachingViewResolver(ViewResolverComposite组合类不分析),重点是我们真是场景中最常用的AbstractCachingViewResolver
二、BeanNameViewResolver分析
2.1、示范例子
-
配置视图解析器
Xml配置对象eanNameViewResolver 视图解析器,同时配置对应的view
<!--视图解析 -->
<!--1、BeanNameViewResolver视图解析器 根据controller类的方法返回的String
类型的viewName 作为bean的name从spring中获取 View对象调用其的render()方法 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
</bean>
<!--配置view对象 view对象在后面贴出-->
<bean id="helloView" class="com.xiu.config.HelloView"/>
-
Controller
@Controller
@RequestMapping(value = "/beanNameView")
public class BeanNameViewController {
@RequestMapping(value = "hello", method = RequestMethod.GET)
public String toHello(HttpServletRequest request){
System.out.println("使用BeanNameViewResolver解析器 获取解析视图");
//返回时String 类型的View 对象
return "helloView";
}
}
-
HelloView(view对象)
/**
* @Desc 自定义的View对象
*/
public class HelloView implements View {
/**
* 该视图的media类型
* @return
*/
@Override
public String getContentType() {
return "text/html";
}
@Override //核心方法用于将数据在浏览器中呈现
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().print("Welcome to hello View:"+new Date());
}
}
结果
从上面的示范例子中我们可以大概了解BeanNameViewResolver组件的功能,在我们Controller中返回一个“helloView”,同时也实例化了一个HelloView对象,结果渲染就使用调用HelloView对象的render()方法渲染数据信息到浏览器。总的来说BeanNameViewResolver就是通过我们Controller返回的string 作为beanName去spring容器中获取View对象调用其render方法渲染数据。
源码分析
通过上面的例子,我们对BeanNameViewResolver有了直观的了解,下面我们从源码的角度分析一下该类。
/**
* 根据viewName解析视图对象
*/
public View resolveViewName(String viewName, Locale locale) throws BeansException {
//获取spring容器上下文环境
ApplicationContext context = obtainApplicationContext();
//容器中没有viewName对应的bean实例 则返回视图对象为null
if (!context.containsBean(viewName)) {
// Allow for ViewResolver chaining...
return null;
}
//对于viewName不是View对象 则抛出异常
if (!context.isTypeMatch(viewName, View.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Found bean named '" + viewName + "' but it does not implement View");
}
return null;
}
//根据viewName和View类型从spring容器中获取View的Bean实例
return context.getBean(viewName, View.class);
}
通过对该类分析,这个类很简单明白了其就是根据返回的ViewName从spring环境中获取View对象返回。
三、ContentNegotiatingViewResolver分析
3.1、前言
最近比较火的Restful风格接口指的是通过同一个url、不同的请求方式、请求头信息,可以针对同一个资源有不同的表述。比如
- GET /book/id:获取某本书籍信息
- PUT /book/id:更新某本书籍信息
- DELETE /book/id删除某本书籍
其实ContentNegotiatingViewResolver也可以很好的实现restful风格的接口同样的内容数据来使用不同的view来实现,.譬如需要实现如下功能,相同数据l,通过请求头,参数,后缀名等形式展示位不同的表现形式.
- 使用url后缀的形式
http://xxx.com/book/{bookId}.xml 呈现xml文件