目录

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视图解析器详解相关推荐

  1. SpringMVC视图解析器

    SpringMVC视图解析器 前言 在前一篇博客中讲了SpringMVC的Controller控制器,在这篇博客中将接着介绍一下SpringMVC视 图解析器.当我们对SpringMVC控制的资源发起 ...

  2. SpringMVC视图解析器(转)

    前言 在前一篇博客中讲了SpringMVC的Controller控制器,在这篇博客中将接着介绍一下SpringMVC视图解析器.当我们对SpringMVC控制的资源发起请求时,这些请求都会被Sprin ...

  3. jsp springmvc 视图解析器_SpringMVC学习笔记

    Springmvc springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合. springmvc是一个基于mvc的web框架. 基本概念和执行过程 ...

  4. jsp springmvc 视图解析器_Springmvc中多视图解析器解析问题

    最近被问到过几次关于springmvc多视图解析器解析的问题:总结一下. 1.问题: 假设我有两个jsp: WEB-INF/html/a.jsp WEB-INF/report/b.jsp 且我配置了视 ...

  5. springmvc视图解析器_SpringMVC视图及REST风格

    什么是视图解析器? springMVC用于处理视图最重要的两个接口是ViewResolver和View. ViewResolver的主要作用是把一个逻辑上的视图名称解析成一个真的的视图,而Spring ...

  6. jsp springmvc 视图解析器_Java面试题整理——SpringMVC

    SpringMVC 1.什么是SpringMVC Spring MVC是一个MVC的开源框架,Spring MVC = Struts2+spring,Spring MVC就相当于是Struts2加上S ...

  7. jsp springmvc 视图解析器_springMVC配置jsp/html视图解析器

    1.maven项目引入freemark相关jar包 freemaker是以个模板引擎,可以根据提供的数据和创建好的模板,去自动的创建html静态页面.所以在返回html视图时可以用这个引擎结合数据生成 ...

  8. SpringMVC 视图解析器及拦截器

    视图解析器 跳转方式(设置返回值字符串内容) ①默认请求转发 forward:资源路径,forward可省略 ②重定向 redirect:资源路径 自定义视图解析器 SpringMVC会提供默认的视图 ...

  9. jsp springmvc 视图解析器_SpringMVC工作原理

    SpringMVC的工作原理图: SpringMVC流程 1. 用户发送请求至前端控制器DispatcherServlet. 2. DispatcherServlet收到请求调用HandlerMapp ...

  10. springMvc视图解析器作用

    我们在配置springMVC时通常会配置如下代码段: <!-- 视图解析器 -->     <bean class="org.springframework.web.ser ...

最新文章

  1. debian linux 硬盘,[Debian] 硬盘安装Debian,
  2. 如何在C ++中使用数组?
  3. 一起学习android图片四舍五入图片集资源 (28)
  4. 下单问题分析及解决方式
  5. [Hei.Captcha] Asp.Net Core 跨平台验证码实现
  6. TopicDeletionManager分析
  7. 桌面 NAS 是什么
  8. php目录隔离,PHP 应用隔离的几种方法
  9. unix环境高级编程读后感
  10. sitemesh2.4
  11. MyEclipse暗黑主题设置
  12. 手把手会教你搭建微信小程序服务器node!!!
  13. 手机上如何让页面强制横屏
  14. 腾讯微博qq说说备份导出工具_电竞和游戏火了,和它走得很近的腾讯微博却早已透心凉...
  15. 麒麟服务器系统编译raid驱动
  16. Maven自动更新SNAPSHOT包
  17. python可变数据类型和不可变数据类型
  18. 体声波(BAW)射频滤波器行业调研报告 - 市场现状分析与发展前景预测
  19. 知识付费-windows+宝塔安装教程
  20. Hadoop集群搭建07_克隆搭建Linux集群环境

热门文章

  1. 高德地图ajax距离,高德地图 API 计算两个城市之间的距离
  2. 黑马程序员_IO输入输出流
  3. JavaEE程序猿面向对象世界观⑥
  4. 欧美html游戏安卓,HTML5 Games - Rated M or for 18+ only
  5. 微信公众号盈利模式_微信公众号的盈利方式有哪些?
  6. Nginx平滑升级与自定义错误页面
  7. apache ftpserver 被动模式配置
  8. 淮师计算机网络题库,淮阴师范学院(淮师)计算机基础一至六章习题
  9. ubuntu看不了bilibili视频
  10. VS2010 C++ 操作Excel表格的编程实现(OLE/COM)