SpringMVC视图机制详解[附带源码分析]

linux:ssh-copy-id用法详解 本文主要介绍linux下的 ssh-copy-id 命令的详细用法 阅读详情

http://www.cnblogs.com/fangjian0423/p/springMVC-view-viewResolver.html

目录

前言

SpringMVC是目前主流的Web MVC框架之一。 

如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

本文将分析SpringMVC的视图这部分内容,让读者了解SpringMVC视图的设计原理。

重要接口和类介绍

1. View接口

  视图基础接口,它的各种实现类是无状态的,因此是线程安全的。 该接口定义了两个方法: 

2. AbstractView抽象类

  View接口的基础实现类。我们稍微介绍一下这个抽象类。

  首先看下这个类的属性:

  再看下抽象类中接口方法的实现:

  getContentType方法直接返回contentType属性即可。

   render方法:

3. AbstractUrlBasedView抽象类

  继承自AbstractView抽象类,增加了1个类型为String的url参数。

4. InternalResourceView类

  继承自AbstractUrlBasedView抽象类的类,表示JSP视图。

  我们看下这个类的renderMergedOutputModel方法(AbstractView抽象类定义的抽象方法,为View接口提供的render方法服务)。

5. JstlView类

  JSTL视图,继承自InternalResourceView,该类大致上与InternalResourceView类一致。

6. AbstractTemplateView抽象类

  继承自AbstractUrlBasedView抽象类,重写了renderMergedOutputModel方法,在该方法中会调用renderMergedTemplateModel方法,renderMergedTemplateModel方法为新定义的抽象方法。

  该抽象类有几个boolean属性exposeSessionAttributes,exposeRequestAttributes。 设置为true的话会将request和session中的键值和值丢入到renderMergedTemplateModel方法中的model这个Map参数中。

  这个类是某些模板引擎视图类的父类。 比如FreemarkerView,VelocityView。

7. FreeMarkerView类

  继承自AbstractTemplateView抽象类。

  直接看renderMergedTemplateModel方法,renderMergedTemplateModel内部会调用doRender方法:

8. RedirectView类

  继承自AbstractUrlBasedView,并实现SmartView接口。SmartView接口定义了1个boolean isRedirectView();方法。

  该视图的renderMergedOutputModel方法主要就是通过response.sendRedirect进行重定向。

  有关RedirectView方面的知识楼主另外写了1篇博客。http://www.cnblogs.com/fangjian0423/p/springMVC-redirectView-analysis.html

9. ViewResolver接口

  视图解释器,用来解析视图View,与View接口配合使用。

  该接口只有1个方法,通过视图名称viewName和Locale对象得到View接口实现类:

  View resolveViewName(String viewName, Locale locale) throws Exception;

10. AbstractCachingViewResolver抽象类

  带有缓存功能的ViewResolver接口基础实现抽象类,该类有个属性名为viewAccessCache的以 "viewName_locale" 为key, View接口为value的Map。

  该抽象类实现的resolveViewName方法内部会调用createView方法,方法内部会调用loadView抽象方法。

11. UrlBasedViewResolver类

  继承自AbstractCachingViewResolver抽象类、并实现Ordered接口的类,是ViewResolver接口简单的实现类。

  该类复写了createView方法:

  父类(AbstractCachingViewResolver)的createView方法内部会调用loadView抽象方法,UrlBasedViewResolver实现了这个抽象方法:

  下面对UrlBasedViewResolver做1个test,配置如下:

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  <property name="prefix" value="/WEB-INF/view/"/>
  <property name="suffix" value=".jsp"/>
  <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
  <property name="viewNames">
    <array>  
      <value type="java.lang.String">*</value>  
    </array>    
  </property>  
  <property name="contentType" value="text/html;charset=utf-8"/>
  <property name="attributesMap">
    <map>
      <entry key="mytest" value="mytestvalue"/>
    </map>
  </property>
  <property name="attributes">
    <props>
      <prop key="test">testvalue</prop>
    </props>
  </property>
</bean>

  我们看到:以InternalResourceView这个JSP视图作为视图;viewNames我们设置了*,这里的*代表全部视图名(这个viewNames属性不设置也可以,代表全部视图名都处理);http响应头部contentType信息:text/html;charset=utf-8;attributesMap和attributes传入的Map和Properties参数都会被丢入到staticAttributes属性中,这个staticAttributes会被设置成AbstractView的staticAttributes属性,也就是request域中的参数。

 

 

  我们看到request域中没有设置mytest和testvalue值。但是页面中会显示,因为我们配置了attributesMap和attributes参数。

  如果我们把viewNames中的"*"改成"index1"。那么就报错了,因为处理视图名的时候index匹配不上index1。

12. InternalResourceViewResolver类

  继承自UrlBasedViewResolver,以InternalResourceView作为视图,若项目中存在“javax.servlet.jsp.jstl.core.Config”该类,那么会以JstlView作为视图。重写了buildView方法,主要就是为了给InternalResourceView视图设置属性。

13. AbstractTemplateViewResolver类

  继承自UrlBasedViewResolver,重写了buildView方法,主要就是构造AbstractTemplateView以及为它设置相应的属性。

14. FreeMarkerViewResolver类

  继承自AbstractTemplateViewResolver,将视图设置为FreeMarkerView。

15. ModelAndView对象

  顾名思义,带有视图和Model属性的一个模型和视图类。

  值得注意的是,这个视图属性是一个Object类型的数据,可以直接是View接口的实现类或者视图名(字符串)。

源码分析

下面我们来分析SpringMVC处理视图的源码。

SpringMVC在处理请求的时候,通过RequestMappingHandlerMapping得到HandlerExecutionChain,然后通过RequestMappingHandlerAdapter得到1个ModelAndView对象,之后通过processDispatchResult方法处理。

processDispatchResult方法如下:

如果配置的ViewResolver如下:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/view/"/>
  <property name="suffix" value=".jsp"/>
</bean>

那么就是使用InternalResourceViewResolver来解析视图。

之前分析过,InternalResourceViewResolver重写了UrlBasedViewResolver的buildView方法。但是还是会调用UrlBasedViewResolver的buildView方法。

最终得到InternalResourceView或JstlView视图。这两个视图的render方法本文介绍重要接口及类的时候已分析。

 

PS:DispathcerServlet中的viewResolvers属性是个集合,如果存在多个ViewResolver对象,必定会有优先级的问题,这部分的内容请参考楼主的另一篇博客:

http://www.cnblogs.com/fangjian0423/p/spring-Ordered-interface.html

编码自定义的ViewResolver

下面,我们就来编写自定义的ViewResolver。

自定义的ViewResolver处理视图名的时候,遇到 "jsp:" 开头的会找jsp页面,遇到 "freemarker:" 开头的找freemarker页面。

public class CustomViewResolver extends UrlBasedViewResolver {

  public static final String JSP_URL_PREFIX = "jsp:";
  public static final String FTL_URL_PREFIX = "freemarker:";
  
  private static final boolean jstlPresent = ClassUtils.isPresent(
            "javax.servlet.jsp.jstl.core.Config", CustomViewResolver.class.getClassLoader());

  private Boolean exposePathVariables = false;

  private boolean exposeRequestAttributes = false;

  private boolean allowRequestOverride = false;

  private boolean exposeSessionAttributes = false;

  private boolean allowSessionOverride = false;

  private boolean exposeSpringMacroHelpers = true;

  public CustomViewResolver() {
      this.setViewClass(FreeMarkerView.class);
  }  
  
  @Override
  protected AbstractUrlBasedView buildView(String viewName) throws Exception { 
    if(viewName.startsWith(FTL_URL_PREFIX)) {
        return buildFreemarkerView(viewName.substring(FTL_URL_PREFIX.length()));
    } else if(viewName.startsWith(JSP_URL_PREFIX)) {
        Class viewCls = jstlPresent ? JstlView.class : InternalResourceView.class;
        return buildView(viewCls, viewName.substring(JSP_URL_PREFIX.length()), getPrefix(), ".jsp");
    } else {
        //默认以freemarker处理
        return buildFreemarkerView(viewName);
    }
  }
  
  private AbstractUrlBasedView build(Class viewClass, String viewName, String prefix, String suffix) { 
    AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
    view.setUrl(prefix + viewName + suffix);
    String contentType = getContentType();
    if (contentType != null) {
        view.setContentType(contentType);
    }
    view.setRequestContextAttribute(getRequestContextAttribute());
    view.setAttributesMap(getAttributesMap());
    if (this.exposePathVariables != null) {
        view.setExposePathVariables(exposePathVariables);
    }
    return view;    
  }
  
  private AbstractUrlBasedView buildFreemarkerView(String viewName) throws Exception { 
    AbstractTemplateView view = (AbstractTemplateView) build(FreeMarkerView.class, viewName, "", getSuffix());
    view.setExposeRequestAttributes(this.exposeRequestAttributes);
    view.setAllowRequestOverride(this.allowRequestOverride);
    view.setExposeSessionAttributes(this.exposeSessionAttributes);
    view.setAllowSessionOverride(this.allowSessionOverride);
    view.setExposeSpringMacroHelpers(this.exposeSpringMacroHelpers);
    return view;      
  }
  
  //get set方法省略
  
}

xml配置:

<bean class="org.format.demo.support.viewResolver.CustomViewResolver">
  <property name="prefix" value="/WEB-INF/view/"/>
  <property name="suffix" value=".ftl"/>
  <property name="contentType" value="text/html;charset=utf-8"/>
  <property name="exposeRequestAttributes" value="true"/>
  <property name="exposeSessionAttributes" value="true"/>
  <property name="exposeSpringMacroHelpers" value="true"/>
  <property name="requestContextAttribute" value="request"/>
</bean>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath" value="/WEB-INF/view/"/>
  <property name="defaultEncoding" value="utf-8"/>
  <property name="freemarkerSettings">
    <props>
      <prop key="template_update_delay">10</prop>
      <prop key="locale">zh_CN</prop>
      <prop key="datetime_format">yyyy-MM-dd</prop>
      <prop key="date_format">yyyy-MM-dd</prop>
      <prop key="number_format">#.##</prop>
    </props>
  </property>
</bean>

简单解释一下:CustomViewResolver解析视图名的时候,判断 "jsp:" 和 "freemarker:" 开头的名字,如果是 "jsp:" 开头的,如果有JSTL依赖,构造JSTLView视图,否则构造InternalResourceView视图。如果是 "freemarker:" 构造FreemarkerView。在构造视图之前分别会设置一些属性。

xml配置:配置prefix是为了给jsp视图用的,freemarker视图不需要prefix,因为FreemarkerView内部会使用配置的FreeMarkerConfigurer,并用FreeMarkerConfigurer内部的templateLoaderPath属性作为前缀,配置的suffix是为了让FreemarkerView使用,当后缀。

最后附上Controller代码:

@Controller
@RequestMapping(value = "/tvrc")
public class TestViewResolverController {
  
    @RequestMapping("jsp")
    public ModelAndView jsp(ModelAndView view) {
        view.setViewName("jsp:trvc/index");
        return view;
    }

    @RequestMapping("/ftl")
    public ModelAndView freemarker(ModelAndView view) {
        view.setViewName("freemarker:trvc/index");
        return view;
    }
  
}

视图 /WEB-INF/view/trvc/index.jsp 中的的内容是输出<h2>This is jsp page</h2>

视图 /WEB-INF/view/trvc/index.ftl 中的的内容是输出<h2>This is freemarker page</h2>

总结

本文分析了SpringMVC中的视图机制,View和ViewResolver这两个接口是视图机制的核心,并分析了几个重要的View和ViewResolver接口实现类,最终写了一个区别jsp和freemarker视图的ViewResolver实现类,让读者更加理解视图机制。

希望这篇文章能帮助读者了解SpringMVC视图机制。

SpringMVC源码分析 目录 1、SpringMVC架构图 2、SpringMVC初始化流程图 3、SpringMVC执行流程图 4、SpringMVC组件解析 5、SpringMVC的工作机制 6、源码分析 6.1 初始化流程 6.2 请求执行流程 7、谈谈SpringMVC的优化 1、SpringMVC架构图 2、SpringMVC初始化流程图 3、SpringMVC执行流程图 用户发送请求至前端控制器DispatcherServlet。 DispatcherServl. 阅读详情

相关推荐

ClickHouse的bitmap使用

ClickHouse的bitmap使用 bitmap的基本使用 在CK中bitmap有两种构建方式,在ClickHouse的官网有说明: (1)一个是由聚合函数groupBitmapState构造的, (2)另一个是由Array Object构造的。同时还可以将位图对象转化为数组对象。 bitmap实战 数据和基本数据表准备 创建一张基本表,一个用户表,有多个描述的维度,每个维度由该维度的唯一id。 CREATE TABLE test02(id UInt16, tag1 UInt8, tag2 UInt8,

zg_hover的专栏 5653

ssh-copy-id(1) command

ssh-copy-id 使用本地可用的密钥授权登录远程计算机。ssh-copy-id 可以把本地主机的公钥复制到远程主机的 authorized_keys 文件上。ssh-copy-id 也会给远程主机的用户主目录(home)和 ~/.ssh 和 ~/.ssh/authorized_keys 设置合适的权限。 3.选项说明 4.常用示例 (1)把本地主机的公钥复制到远程主机。 (2)拷贝本机指定公钥到远程主机。 参考文献 ssh-copy-id(1) — Linux manual page - linu

Doublelv 的博客专栏。 1万+

金蝶云星空核心数据表解析与高效关联查询指南

本文深入解析金蝶云星空核心数据表结构,提供高效关联查询的实战指南。文章详细介绍了基础资料、业务单据和财务模块的关键表及其关联逻辑,重点阐述了如何利用关联表(_LK表)进行跨单据溯源,并分享了编写高性能SQL的实用技巧与避坑建议,帮助开发者、实施顾问和数据分析师快速掌握数据查询方法,提升工作效率。

weixin_29254673的博客 524

ssh-copy-id命令的介绍,使免密更方便

ssh-copy-id命令的介绍,使免密更方便 ssh-copy-id命令可以把本地的ssh公钥文件安装到远程主机对应的账户下。 达到的功能: ssh-copy-id - 将你的公共密钥填充到一个远程机器上的authorized_keys文件中。 使用模式: ssh-copy-id [-i [identity_file]] [user@]machine 描述: **ssh-copy-id 是一个实用ssh去登陆到远程服务器的脚本(假设使用一个登陆密码, 因此,密码认证应该

qq_43688472的博客 3万+

ArcGIS学习记录—SHP文件转换为KML KMZ数据,并显示面要素相应的标注

使用相应软件操作获取KMZ数据得以下发到外业调查人员,使得矢量数据能够更显而易见,可视化,让外业人员的工作减轻许多。(过程步骤是借鉴于网络上的相关人士给的建议,根据这些建议自己做出来的步骤,可能有些粗略,有问题的话可以再进行探讨)...

qq_41046162的博客 5万+

CASS3D实战:高效三维房屋与地形采集绘制技巧

本文详细介绍了CASS3D在三维房屋与地形采集绘制中的高效技巧,包括智能绘房功能、不规则结构处理、特殊构件快速绘制及地形数据采集策略。通过实战案例和进阶操作指南,帮助用户快速掌握CASS3D的核心功能,提升三维采集与绘制效率。

weixin_29216049的博客 866

ssh-copy-id命令详解 & 使用ssh-keygen和ssh-copy-id三步实现SSH无密码登录

http://blog.youkuaiyun.com/john_f_lau/article/details/22303341 http://blog.chinaunix.net/uid-26284395-id-2949145.html ssh-copy-id命令可以把本地的ssh公钥文件安装到远程主机对应的账户下。

liukuan73的专栏 7万+

别再翻手册了!用Materials Studio的Forcite模块,5步搞定复杂溶剂的溶解度参数计算

本文详细介绍了如何使用Materials Studio的Forcite模块,通过5个步骤快速计算复杂溶剂的溶解度参数。从分子建模、结构优化到分子动力学采样,再到最终的内聚能密度计算,该方法大幅提升了石油化工和高分子材料研发中的效率,避免了传统手册查阅和实验的繁琐过程。

weixin_28707739的博客 278

springMVC原理(四):SpringMVC视图机制详解[附带源码分析]

重要接口和类介绍 1. View接口   视图基础接口,它的各种实现类是无状态的,因此是线程安全的。 该接口定义了两个方法:  2. AbstractView抽象类   View接口的基础实现类。我们稍微介绍一下这个抽象类。   首先看下这个类的属性:   再看下抽象类中接口方法的实现:   getContentType方法直接返回co

mll999888的专栏 503

AI应用架构师实战:高等教育智能课程推荐系统开发

性能:选课季并发量达1000QPS,推荐响应时间≤500ms(否则学生不耐烦)。数据隐私:符合《教育数据安全管理规范》,学生姓名、学号等敏感信息需匿名化存储。可扩展性:支持新增课程类型(如MOOC、实践课)、新增数据源(如竞赛获奖记录)。教育AI要“以教为中心”:不能纯技术驱动,要和教育工作者深度合作(如教师参与定义课程的前置关系)。数据是核心:数据质量决定推荐效果,要重视数据治理和隐私保护。持续迭代:教育需求是动态的(如每年新增课程、学生目标变化),要定期收集用户反馈,更新模型和策略。张三。

AI大模型应用之禅 1347

iqoo11如何获取root权限?

🏆本文收录于专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家!持续更新中,up!up!up!!

**My Coding Family** 5809

SpringMVC源码分析6:SpringMVC的视图解析原理

转自 SpringMVC视图机制详解[附带源码分析] 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的优快云专栏:Spring源码解析 https://blog.youkuaiyun.com/column/details/21851.html 部分代码会放在我的...

chuomaduo7432的博客 183

DA14531之搭建开发环境

DA14531之搭建开发环境

hejinwu1314的博客 1777

SpringMVC视图机制详解

SpringMVC视图机制详解[附带源码分析] 目录 前言重要接口和类介绍源码分析编码自定义的ViewResolver总结参考资料 前言 SpringMVC是目前主流的Web MVC框架之一。  如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.h

u014263388的专栏 2381

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

SpringMVC 源码分析

一、回顾 SpringMVC 原理 二、 SpringMVC 源码分析 1 DispatcherServlet 1.1 DispatcherServlet 继承结构 1.1.1 HttpServletBean HttpServletBean 覆写了 init 方法,主要做一些初始化的工作,将 web.xml 中配置的参数设置到 Servlet 中。比如 servlet 标签的子标签 init-param 标签中配置的参数 1.1.1.1 ServletConf...

奥迪的博客 1198

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

SpringMVC之视图解析

SpringMVC如何解析视图

OceanStar的博客 707

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SpringMVC源码分析之异常处理机制

本篇博文从ExceptionResolver接口出发,介绍了其springMVC整个异常处理的UML类图结构,并对其相关子类进行详尽的分析、应用进行讲解,所有的子类源码分析都使用了例子和源码分析结合的方法进行阐述异常,读者可以通过这篇文章较好的了解springMVC异常处理机制以及应用场景。希望可以帮到大家

liushangzaibeijing的博客 6万+

[转]SpringMVC源码分析系列

说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时springmvc基于Spring框架,Spring框架想必搞java的同学都很熟悉。 一进Spring的官网就发现了这样一排醒目的文字, spring可以让我们构造简单的、便携的、又快又...

ask26874的博客 131

SpringMVC入门到实战------六、SpringMVC的视图。ThymeleafView、转发视图、重定向视图、视图控制器的使用详解

SpringMVC的视图。ThymeleafView、转发视图、重定向视图、视图控制器的使用详解

日常笔记 | 干货分享 | 毕设源码 | 毕设指导 | 答辩指导 397

SpringMVC的执行流程与源码分析

SpringMVC概述。

weixin_63975657的博客 2948

SpringMVC系列 教程(八):视图机制详解(附源码分析)

来源:https://www.cnblogs.com/fangjian0423/p/springMVC-view-viewResolver.html一.前言SpringMVC是目前主流...

程序员大宇 199

SpringMVC源码分析之——处理请求核心流程之视图解析及全局异常处理

1.视图渲染 前面讲到在返回值解析的时候,返回返回值并没有@ResponseBody注解修饰,那么代表的是一个视图的名称,存放在ModelAndView对象中,由springmvc进行转发 接下来看看源码是怎么响应视图的 创建了一个View对象,从之前配置的页面前缀+视图名称+配置的后缀组成一个完成的地址 把响应数据设置到request对象中 最后用Servlet中的RequestDispatcher进行转发 2.全局异常处理 在项目中,后台处理请求之后返回的数据都会.

meser88的博客 691

SpringMVC视图解析

视图解析 1. SpringMVC如何解析视图概述 ① 不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转。 ② 视图解析源码分析:重要的两个接口 ③ 断点调试源码 ④ 流程图 2. 视图和视图解析器 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。 对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 Mo

naumy的博客 367
上一篇: SpringMVC拦截器详解[附带源码分析
下一篇: SpringMVC异常处理机制详解[附带源码分析]
god_love_hlq_xff
博客等级 码龄11年 27粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值