springmvc视图解析器详解
目录
1. 概述
2. ViewResolver和View接口
2.1 ViewResolver接口
2.2 View接口
3. springmvc中如何解析视图
3.1 初始化视图解析器
3.2 解析逻辑视图名
3.3 请求转发与重定向的视图解析
3.4 配置JstlView视图
3.5 产生上面异同的原因
4. 配置thymeleaf视图
5. 使用多种视图
6. 简化返回视图
1. 概述
文章有点长,建议收藏阅读
当一个请求被HandlerMapping处理完后,会返回一个ModelAndView对象,springmvc借助视图解析器(ViewResolver)得到最终将逻辑视图解析为视图对象(View),最终的视图可以是jsp,html,也可能是Excel等,转换成对应的View对象后渲染给用户,即返回浏览器,在这个渲染过程中,发挥作用的就是ViewResolver和View两个接口
对于最终采取哪种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点在生产模型数据上,从而实现mvc的充分解耦,视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户端,主要就是完成转发或重定向操作
2. ViewResolver和View接口
2.1 ViewResolver接口
public interface ViewResolver {/*** 只有这一个方法,用于把逻辑视图名称解析为真正视图View/@NullableView resolveViewName(String viewName, Locale locale) throws Exception;}
视图解析器继承关系:
从上图可以看出,springmvc提供了很多的视图解析器,下面说明一个常用的:
(1)UrlBasedViewResolver(URL资源视图):
主要就是提供的一种拼接URL的方式来解析视图,他可以指定前缀和后缀,然后拼接到返回的逻辑视图名称,就是指定的视图URL了
(2)子类InternalResourceViewResolver:
将视图名解析为一个URL文件,一般使用该解析器将视图名映射为一个保存在WEB-INF下的程序文件如jsp
jsp是常见的视图技术,可以使用InternalResourceViewResolver作为视图解析器:
案例一:
@Controller
public class LoginController {@RequestMapping(value = "login")public String login() {return "login";}
}//在springmvc中没有配置视图解析器的情况下,访问/login,会报错,错误的大概意思就是没有正确设置转发(或包含)到请求调度程序路径
//意思就是把逻辑视图解析后的URL路径还是/login,因为默认情况下该视图解析器解析视图是没有配置前缀和后缀的
抛出异常的就是下面那一行,准备渲染视图时进行的检查抛出的
现在在springmvc.xml文件中配置InternalResourceViewResolver视图解析器的前缀和后缀
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--前缀--><property name="prefix" value="/WEB-INF/"/><!--后缀--><property name="suffix" value=".jsp"/>
</bean>
再次访问/login,得到下图,就能看出区别,两个path是不一样的
2.2 View接口
不同的视图解析器解析成对应的视图类型
View接口有很多实现类,接口中有一个重要方法render(),用于渲染给定模型的视图,下面是继承结构,打钩的是常用的视图类型,当然也可以自己实现ViewResolver和View接口,自定义自己的视图解析器
InternalResourceView视图:
将jsp或者其他资源封装成一个视图,是InternalResourceViewResolver默认使用的视图实现类
文档视图:
AbstractExcelView: Excel文档视图的抽象类,该视图类基于POI构造excel文档
JSON视图:
MappingJacksonJsonView: 将数据模型通过Jackson开源框架的ObjectMapper以JSON方式输出
如访问localhost:8080/springmvc/login得到的视图(InternalResourceView)如下:
3. springmvc中如何解析视图
3.1 初始化视图解析器
private List<ViewResolver> viewResolvers; //定义视图解析器集合
private void initViewResolvers(ApplicationContext context) {/*** DispatcherServlet类中通过该方法初始化viewResolvers,如果容器中没有ViewResolver bean,则默认为 * InternalResourceViewResolver///其他代码不用关心}
3.2 解析逻辑视图名
也就是依次调用viewResolvers中视图解析器,如果得到了View就返回
3.3 请求转发与重定向的视图解析
请求转发: 返回逻辑视图名包含forward:前缀
重定向: 返回逻辑视图名包含redirect:前缀
默认的: 返回视图名不带任何前缀
此时我们知道默认视图解析器为InternalResourceViewResolver,我们也没有配置其他的
(1)如果是默认的,则解析后是InternalResourceView,如下图
(2)如果是请求转发,则解析后是InternalResourceView,如下图
(3)如果重定向,则解析后是RedirectView,如下图
3.4 配置JstlView视图
注意这里是配置视图不是视图解析器,当没有配置其他视图解析器(比如thymeleaf),但配置了InternalResourceViewResolver的viewClass属性
默认的: 就使用viewClass对应的视图,当前是JstlView
请求转发: 则解析后还是InternalResourceView
重定向: 则解析后还是RedirectView
如果导入相关Jstl相关jar包后,默认的视图会自动切换为JstlView,就不用在下面配置viewClass,也会自动生效
JstlView是InternalResourceView的子类,功能比InternalResourceView更强大,比如可以支持快速国际化,或者如果JSP文件中使用了JSTL国际化标签功能,则需要使用该类视图
JstlView视图依赖
<dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version>
</dependency>
3.5 产生上面异同的原因
比如访问localhost:8080/springmvc/login
为什么重定向与请求转发,解析后的视图类型不一样,或者添加JstlView依赖后又会产生不一样?
就需要知道InternalResourceViewResolver如何解析视图的,当前springmvc中只有这一个默认视图解析器
InternalResourceViewResolver继承结构如下:
1.从DispatcherServlet中视图解析入口
2.进入resolveViewName()方法
此时进入到AbstractCachingViewResolver中的resolveViewName()方法,从上面继承结构知道,只有AbstractCachingViewResolver实现了ViewResolver接口中解析方法,具体源码如下:
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {if (!isCache()) {return createView(viewName, locale);}else {/*** getCacheKey()实际上就是返回视图名称,在UrlBasedViewResolver中重写的,此时是cacheKey="login"*/Object cacheKey = getCacheKey(viewName, locale);/*** 尝试从缓存中获取视图,此时viewAccessCache的size为0,因为是第一次获取视图,缓存中肯定没有的* viewAccessCache中key:value比如为:* key:"redirect:login" value:"RedirectView"* key:"login" value:"InternalResourceView"*/View view = this.viewAccessCache.get(cacheKey);if (view == null) {/*** 如果没有获取到,就在同步块中创建一个视图并返回,并将其缓存,以便下一次需要该视图的时候直接从缓存中返回即可*/synchronized (this.viewCreationCache) {view = this.viewCreationCache.get(cacheKey);if (view == null) {/************************************************************************* 重要的就是这个方法,他决定了创建什么类型的视图,但在URLBasedViewResolver被重写了**********************************************************************/view = createView(viewName, locale);if (view == null && this.cacheUnresolved) {view = UNRESOLVED_VIEW;}if (view != null && this.cacheFilter.filter(view, viewName, locale)) {/*** 将逻辑视图名与对应视图存入缓存中*/this.viewAccessCache.put(cacheKey, view);this.viewCreationCache.put(cacheKey, view);}}}}else {if (logger.isTraceEnabled()) {logger.trace(formatKey(cacheKey) + "served from cache");}}return (view != UNRESOLVED_VIEW ? view : null);}
}
3. 进入createView():
用来创建一个视图, 具体源码如下:
@Override
protected View createView(String viewName, Locale locale) throws Exception {/*** 判断一下当前视图解析器能不能处理给定视图,如果不能处理的话,就返回null,交给下一个视图解析器处理*/if (!canHandle(viewName, locale)) {return null;}/*** 检查视图名是否以 "redirect:" 开头*/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);}/*** 检查视图名是否以 "forward:" 开头*/if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());/*** 创建请求转发InternalResourceView视图*/InternalResourceView view = new InternalResourceView(forwardUrl);return applyLifecycleMethods(FORWARD_URL_PREFIX, view);}/*** 如果视图名不以"redirect:"或"forward:"为前缀,则通过父类中的实现创建视图*/return super.createView(viewName, locale);
}
4.进入super.createView()
从上面继承结构知道,所以回到了AbstractCachingViewResolver中,他的实现如下:
5.进入loadView()
而loadView()这是个抽象方法,在UrlBasedViewResolver中实现,父类又调用子类实现,spring中有很多这种模式
实现如下:
6.进入buildView()
这个方法就在当前类URLBasedViewResolver中的,但是此时视图解析器为InternalResourceViewResolver,在这个子类中又重写了这个方法,下图为InternalResourceViewResolver中的重写,当前实际调用的是这个,而这个实际调用的又是URLBasedViewResolver中的,有点绕,但是跟着debug知道他的设计模式后就会一点一点明白的
回到URLBasedViewResolver中:
protected AbstractUrlBasedView buildView(String viewName) throws Exception {Class<?> viewClass = getViewClass(); ;//获取viewClass,需要viewClassAssert.state(viewClass != null, "No view class");AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);view.setUrl(getPrefix() + viewName + getSuffix());view.setAttributesMap(getAttributesMap());//********省略部分return view;
}
最终,我们默认返回的视图类型就在这里创建的,而请求转发和重定向解析的视图类型在上面代码中已经固定
因为当前项目中添加了Jstl依赖,所以返回默认视图时,解析为JstlView视图,如果不添加Jstl依赖,此时解析为InternalResourcesView视图,这也是为什么配置URLBasedViewResolver解析器时需要配置viewClass,而配置InternalResourcesViewResolver解析器时不用配置viewClass,应该InternalResourcesViewResolver已经设置viewClass默认为InternalResourceView
4. 配置thymeleaf视图
1. 导入依赖并配置
<!-- thymeleaf -->
<dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId><version>3.0.13.RELEASE</version>
</dependency>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"><property name="order" value="1"/><property name="characterEncoding" value="UTF-8"/><property name="templateEngine"><bean class="org.thymeleaf.spring5.SpringTemplateEngine"><property name="templateResolver"><bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"><!-- 视图前缀 --><property name="prefix" value="/WEB-INF/"/><!-- 视图后缀 --><property name="suffix" value=".html"/><property name="templateMode" value="HTML5"/><property name="characterEncoding" value="UTF-8" /></bean></property></bean></property>
</bean>
2. 查看springmvc中的解析
直接看图: 此时就只有thymeleaf解析器了,此时
默认的: 解析为ThymeleafView
请求转发: 则解析后还是InternalResourceView
重定向: 则解析后还是RedirectView
再看一张图:
thymeleaf解析器继承了AbstractCachingViewResolver,从上面知道,AbstractCachingViewResolver解析视图类型时先从缓存中找,缓存中没有的话就调用createView()方法来创建一个
而此时thymeleaf重写了该方法,源码如下:
5. 使用多种视图
我们可以选用一种视图解析器或混用多种视图解析器,每个视图解析器都实现Ordered接口并开放出一个order属性,springmvc会按照视图解析器顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出异常
<!-- 配置InternalResourceViewResolver视图解析器 -->
<bean id="viewResolver2" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--前缀--><property name="prefix" value="/WEB-INF/"/><!--后缀--><property name="suffix" value=".jsp"/><property name="order" value="2"/>
</bean><!-- 配置thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"><property name="order" value="1"/><property name="characterEncoding" value="UTF-8"/><property name="templateEngine"><bean class="org.thymeleaf.spring5.SpringTemplateEngine"><property name="templateResolver"><bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"><!-- 视图前缀 --><property name="prefix" value="/WEB-INF/"/><!-- 视图后缀 --><property name="suffix" value=".html"/><property name="templateMode" value="HTML5"/><property name="characterEncoding" value="UTF-8" /></bean></property></bean></property></bean>
配置的order越小,优先级越高,当前thmeleaf视图解析器在前,如下图:
6. 简化返回视图
当控制器只是返回视图时,可以在springmvc配置文件中配置来简化,并且需要加上开启注解驱动,否则造成@Controller注解无法解析,造成404错误
<!--此时直接访问localhost:8080/springmvc/login就可以获取名为login的逻辑视图 -->
<mvc:view-controller path="/login" view-name="login"></mvc:view-controller>
<mvc:annotation-driven/>
springmvc视图解析器详解相关推荐
- SpringMVC视图解析器
SpringMVC视图解析器 前言 在前一篇博客中讲了SpringMVC的Controller控制器,在这篇博客中将接着介绍一下SpringMVC视 图解析器.当我们对SpringMVC控制的资源发起 ...
- SpringMVC视图解析器(转)
前言 在前一篇博客中讲了SpringMVC的Controller控制器,在这篇博客中将接着介绍一下SpringMVC视图解析器.当我们对SpringMVC控制的资源发起请求时,这些请求都会被Sprin ...
- jsp springmvc 视图解析器_SpringMVC学习笔记
Springmvc springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合. springmvc是一个基于mvc的web框架. 基本概念和执行过程 ...
- jsp springmvc 视图解析器_Springmvc中多视图解析器解析问题
最近被问到过几次关于springmvc多视图解析器解析的问题:总结一下. 1.问题: 假设我有两个jsp: WEB-INF/html/a.jsp WEB-INF/report/b.jsp 且我配置了视 ...
- springmvc视图解析器_SpringMVC视图及REST风格
什么是视图解析器? springMVC用于处理视图最重要的两个接口是ViewResolver和View. ViewResolver的主要作用是把一个逻辑上的视图名称解析成一个真的的视图,而Spring ...
- jsp springmvc 视图解析器_Java面试题整理——SpringMVC
SpringMVC 1.什么是SpringMVC Spring MVC是一个MVC的开源框架,Spring MVC = Struts2+spring,Spring MVC就相当于是Struts2加上S ...
- jsp springmvc 视图解析器_springMVC配置jsp/html视图解析器
1.maven项目引入freemark相关jar包 freemaker是以个模板引擎,可以根据提供的数据和创建好的模板,去自动的创建html静态页面.所以在返回html视图时可以用这个引擎结合数据生成 ...
- SpringMVC 视图解析器及拦截器
视图解析器 跳转方式(设置返回值字符串内容) ①默认请求转发 forward:资源路径,forward可省略 ②重定向 redirect:资源路径 自定义视图解析器 SpringMVC会提供默认的视图 ...
- jsp springmvc 视图解析器_SpringMVC工作原理
SpringMVC的工作原理图: SpringMVC流程 1. 用户发送请求至前端控制器DispatcherServlet. 2. DispatcherServlet收到请求调用HandlerMapp ...
- springMvc视图解析器作用
我们在配置springMVC时通常会配置如下代码段: <!-- 视图解析器 --> <bean class="org.springframework.web.ser ...
最新文章
- debian linux 硬盘,[Debian] 硬盘安装Debian,
- 如何在C ++中使用数组?
- 一起学习android图片四舍五入图片集资源 (28)
- 下单问题分析及解决方式
- [Hei.Captcha] Asp.Net Core 跨平台验证码实现
- TopicDeletionManager分析
- 桌面 NAS 是什么
- php目录隔离,PHP 应用隔离的几种方法
- unix环境高级编程读后感
- sitemesh2.4
- MyEclipse暗黑主题设置
- 手把手会教你搭建微信小程序服务器node!!!
- 手机上如何让页面强制横屏
- 腾讯微博qq说说备份导出工具_电竞和游戏火了,和它走得很近的腾讯微博却早已透心凉...
- 麒麟服务器系统编译raid驱动
- Maven自动更新SNAPSHOT包
- python可变数据类型和不可变数据类型
- 体声波(BAW)射频滤波器行业调研报告 - 市场现状分析与发展前景预测
- 知识付费-windows+宝塔安装教程
- Hadoop集群搭建07_克隆搭建Linux集群环境
热门文章
- 高德地图ajax距离,高德地图 API 计算两个城市之间的距离
- 黑马程序员_IO输入输出流
- JavaEE程序猿面向对象世界观⑥
- 欧美html游戏安卓,HTML5 Games - Rated M or for 18+ only
- 微信公众号盈利模式_微信公众号的盈利方式有哪些?
- Nginx平滑升级与自定义错误页面
- apache ftpserver 被动模式配置
- 淮师计算机网络题库,淮阴师范学院(淮师)计算机基础一至六章习题
- ubuntu看不了bilibili视频
- VS2010 C++ 操作Excel表格的编程实现(OLE/COM)