在Spring MVC 中,controllers不负责具体的页面渲染,仅仅是调用业务逻辑并返回model数据给view层,至于view层具体怎么展现,由专门的view层具体负责,这就是MVC模式,业务层与展示层是松耦合的。那么,Spring MVC是如何解耦合请求处理逻辑和页面渲染的呢?

视图解析器

请求进入DispathServlet后,通过HandlerMapping找到对应的HandlerExecutionChain,
最后交由HandlerAdapter来执行最终Handler【也就是Controller中的Action】,最终得到ModelAndView,然后再次交给DispatchServlet来处理,并执行render方法处理渲染逻辑,如下:

 1protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
2        Locale locale =
3                (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
4        response.setLocale(locale);
5
6        View view;
7        String viewName = mv.getViewName();
8        if (viewName != null) {
9            // 通过ViewResolver 来获取真正的View对象
10            view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
11
12            }
13        }
14        else {
15            view = mv.getView();
16            }
17        }
18        try {
19            if (mv.getStatus() != null) {
20                response.setStatus(mv.getStatus().value());
21            }
22           //通过执行View对象的render方法来真正执行视图渲染的逻辑
23            view.render(mv.getModelInternal(), request, response);
24        }
25        catch (Exception ex) {
26            throw ex;
27        }
28    }

 1    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
2            Locale locale, HttpServletRequest request) throws Exception {
3
4        if (this.viewResolvers != null) {
5            for (ViewResolver viewResolver : this.viewResolvers) {
6//遍历ViewResolver集合 来获取合适的ViewResolver 对象
7                View view = viewResolver.resolveViewName(viewName, locale);
8                if (view != null) {
9                    return view;
10                }
11            }
12        }
13        return null;
14    }

Spring MVC其实就是通过遍历ViewResolvers这种视图解析器集合,根据视图名来找到找到真正的物理视图【view页面】,对于普通的JSP页面,最常用到的view resolver就是InternalResourceViewResolver,它有两个属性,一个是匹配物理view的前缀,一个是后缀。前缀一般就是view页面的路径位置,后缀就是文件的格式,而前缀后缀之间的就是逻辑view名称。

1<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
2    <property name="prefix" value="/WEB-INF/views/" />
3    <property name="suffix" value=".jsp" />
4</bean>
5

比如按照上面的配置,如果controller返回的逻辑view名称是home的话,InternalResourceViewResolver会根据这个逻辑view名home找到其对应的实际物理view:/WEB-INF/views/home.jsp。

下面我们在看下视图解析器的定义如下,就一个方法resolveViewName,根据视图名称和Local对象得到最终的View视图

1public interface ViewResolver {
2    @Nullable
3    View resolveViewName(String viewName, Locale locale) throws Exception;
4}

视图渲染

如上,通过视图解析器ViewResolver 最终会得到视图View,然后会通过调用View对象的render方法来真正执行视图渲染的逻辑,View对象的定义如下

1public interface View {
2
3    String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
4
5
6    void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
7            throws Exception;
8
9}

不同的实现类有不同的视图效果:

1、VelocityView是用来和Velocity框架结合生成页面视图

2、FreeMarkerView是用来和FreeMarker框架结合生成页面视图

3、JstlView是用来生成jstl页面

4、RedirectView是生成页面跳转视图的。

看下View的实现逻辑AbstractView源码如下

 1    public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
2            HttpServletResponse response) throws Exception {
3
4//将model和request中的参数全部放到mergedModel中  
5Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
6//存放头部信息 
7        prepareResponse(request, response);
8////将mergedModel中的参数值放到request中  
9        renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
10    }

其实就根据ModelAndView和Request中的数据,加载视图,然后写入到Response中(先设置ContentType),最后输出给用户。

微信公众号:宋坤明
更多精彩请参考 完整版系列 请参考此博文 也可以直接关注我

View 渲染的更多相关文章

  1. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染

    对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的界面呈现工作是由浏览器完成的,Web应用的原理是通过Http协议从服务器上获取到 ...

  2. 把Android原生的View渲染到OpenGL Texture

    http://blog.csdn.net/u010949962/article/details/41865777 最近要把Android 原生的View渲染到OpenGL GLSurfaceView中 ...

  3. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染 ASP.NET没有魔法——ASP.NET MVC界面美化及使用Bundle完成静态资源管理

    ASP.NET没有魔法——ASP.NET MVC Razor与View渲染   对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的 ...

  4. Yii2.0源码阅读-视图(View)渲染过程

    之前的文章我们根据源码的分析,弄清了Yii如何处理一次请求,以及根据解析的路由如何调用控制器中的action,那接下来好奇的可能就是,我在控制器action中执行了return $this->r ...

  5. 高级UI晋升之View渲染机制(二)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 优化性能一般从渲染,运算与内存,电量三个方面进行,今天开始说聊一聊Android ...

  6. 在渲染前获取 View 的宽高

    在渲染前获取 View 的宽高 这是一个比较有意义的问题,或者说有难度的问题,问题的背景为:有时候我们需要在view渲染前去获取其宽高,典型的情形是,我们想在onCreate.onStart.onRe ...

  7. MVC Return View() 和 Return PartialView()的区别

    分部视图在action中返回一定要用PartialView(),而不要偷懒使用View(),因为,如果你使用View()渲染视图,系统会认为你是一个标准视图,会为你加个默认的母板页(Layout),除 ...

  8. Qt Model/View(官方翻译,图文并茂)

    http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mode ...

  9. android 自定义view详解

    1.自定义View前首先要了解一下View的方法,虽然有些不一定要实现. 分类 方法 描述 创建 Constructors View中有两种类型的构造方法,一种是在代码中构建View,另一种是填充布局 ...

随机推荐

  1. phporjquery生成二维码

    一.php生成二维码 下载文章末尾链接中phpcode文件 include "./phpqrcode/qrlib.php"; //QRcode::png('http://www.b ...

  2. thinkphp3.2+cropper上传多张图片剪切图片

    实现效果截图 点加号可以继续上传第二张图片 代码部<--引入cropper相关文件--> <link rel="stylesheet" href="/h ...

  3. UVA 514 - Rails ( 铁轨)

    from my CSDN: https://blog.csdn.net/su_cicada/article/details/86939523 例题6-2 铁轨(Rails, ACM/ICPC CERC ...

  4. 一个sqoop export案例中踩到的坑

    案例分析: 需要将hdfs上的数据导出到mysql里的一张表里. 虚拟机集群的为:centos1-centos5 问题1: 在centos1上将hdfs上的数据导出到centos1上的mysql里: ...

  5. leetcode记录-罗马数字转整数

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并 ...

  6. 20155317王新玮 2016-2017-2《Java程序设计》第2周学习总结

    20155317 2016-2017-2<Java程序设计>第2周学习总结 课本知识: 认识类型与环境 整数:包括short,int,long .它们分别占用2个字节,4个字节和8个字节. ...

  7. 2016-2017-2 20155339 《Java面向对象程序设计》实验三敏捷开发与XP实践实验报告

    2016-2017-2 20155339 <Java面向对象程序设计>实验三敏捷开发与XP实践实验报告 实验内容 XP基础 XP核心实践 相关工具 实验内容 一.在IDEA中使用工具(Co ...

  8. 洛谷 P3369 【模板】普通平衡树(Treap/SBT)

    题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除x数(若有多个相同的数,因只删除一个) 查询x数的排名(排名定义为比当前数小的数的个数+1.若有多 ...

  9. 【LG3236】[HNOI2014]画框

    [LG3236][HNOI2014]画框 题面 洛谷 题解 和这题一模一样. 将最小生成树换成\(KM\)即可. 关于复杂度,因为决策点肯定在凸包上,且\(n\)凸包的期望点数为\(\sqrt {\l ...

  10. Walle代码发布

    一.概述 Walle 一个web部署系统工具,配置简单.功能完善.界面流畅.开箱即用!支持git.svn版本管理,支持各种web代码发布,PHP,Python,JAVA等代码的发布.回滚,可以通过we ...