SpringMVC自定义视图完成步骤 和 视图解析的源码剖析

自定义视图完成步骤:

7.2.1自定义视图完成步骤

1. 自定义视图* *:** 创建一个 View bean, bean 需要继承自 AbstractView, 并实现

renderMergedOutputModel 方法**.**

2. 并把自定义 View 加入到 IOC 容器中

3. 自定义视图的视图处理器,使用 BeanNameViewResolver**, 这个视图处理器也需要配置**

ioc 容器

4. BeanNameViewResolver 的调用优先级需要设置一下,设置 order Integer.MAX_VAL

小的值* *.** 以确保其在 InternalResourceViewResolver 之前被调用

复制代码
 /**
  * 老师解读
  * 1. MyView继承了AbstractView, 就可以作为一个视图使用
  * 2. @Component(value = "myView"),该视图会注入到容器中, 名字/id是 myView
  */
 @Component(value = "hspView")
 public class MyView extends AbstractView {
     @Override
     protected void renderMergedOutputModel(Map<String, Object> model,
                                            HttpServletRequest request,
                                            HttpServletResponse response) throws Exception {
 ​
         //完成视图渲染
         //并且可以确定我们要跳转的页面 [请求转发] /WEB-INF/pages/my_view.jsp
         System.out.println("进入到自己的视图..");
 ​
         //老师解读
         //1. 下面就是进行请求转发到 /WEB-INF/pages/my_view.jsp
         //2. /WEB-INF/pages/my_view.jsp 会被springmvc解析
         //   /springmvc/WEB-INF/pages/my_view.jsp
         request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp")
                 .forward(request, response);
 ​
     }
 }
复制代码
 <!--
     老师解读
     1. 配置自定义视图解析器BeanNameViewResolver
     2. BeanNameViewResolver可以去解析我们自定义的视图
     3. 配置 属性 order, 表示视图解析器执行的顺序, 值越小, 优先级越高
     4. 属性 order 的默认值是最低优先级 ,值为 Integer.MAX_VALUE
        int LOWEST_PRECEDENCE = 2147483647
 -->
 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
     <property name="order" value="99"/>
 </bean>

使用

复制代码
 @RequestMapping(value = "/buy")
 public String buy() {
     System.out.println("------buy()-----");
     return "hspView";//填写自定义视图id
 }

源码剖析:

视图解析过程

1.先到DispatcherServlet中央控制器, 根据视图解析的 优先级 执行对应的 视图解析器
复制代码
 @Nullable
 protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
       Locale locale, HttpServletRequest request) throws Exception {
 ​
    if (this.viewResolvers != null) {
       for (ViewResolver viewResolver : this.viewResolvers) {//viewResolvers存放了两个视图解析器(1)InternalResourceViewResolver默认视图解析器   (2)BeanNameViewResolver自定义视图解析器
          View view = viewResolver.resolveViewName(viewName, locale);
          if (view != null) {//如果返回的视图为空,那么会继续遍历所有的视图解析器;
              //注意:如果 默认视图解析器 优先级在前,那么不管怎样,它都不会再执行 自定义视图解析器 
              //原因:默认视图解析器 一定会返回视图,因为它是通过传入的视图名build一个视图
             return view;
          }
       }
    }
    return null;
 }
2.若默认视图解析器在前,那么用 视图解析器 解析
复制代码
 @Override
 protected AbstractUrlBasedView buildView(String viewName) throws Exception {
    InternalResourceView view = (InternalResourceView) super.buildView(viewName);//根据viewName创建视图
    if (this.alwaysInclude != null) {
       view.setAlwaysInclude(this.alwaysInclude);
    }
    view.setPreventDispatchLoop(true);
    return view;
 }

注意:如果 默认视图解析器 优先级在前,那么不管怎样,它都不会再执行 自定义视图解析器 (因为:默认视图解析器 一定会返回视图,因为它是通过传入的视图名build一个视图)

3.若自定义视图解析器在前
复制代码
 public View resolveViewName(String viewName, Locale locale) throws BeansException {
    ApplicationContext context = obtainApplicationContext();//context实质上就类似于ioc容器
    if (!context.containsBean(viewName)) {//判断context(ioc)中是否有id为viewName的bean
       // Allow for ViewResolver chaining...
       return null;
    }
    if (!context.isTypeMatch(viewName, View.class)) {//判断context(ioc)中是否有id为viewName并实现View接口的bean
       if (logger.isDebugEnabled()) {
          logger.debug("Found bean named '" + viewName + "' but it does not implement View");
       }
       // Since we're looking into the general ApplicationContext here,
       // let's accept this as a non-match and allow for chaining as well...
       return null;
    }
    return context.getBean(viewName, View.class);
 }

1.拿到context对象,实质上类似于ioc容器

2.//判断context(ioc)中是否有id为viewName的bean, 没有就返回null; 有就接着往下走

3.//判断context(ioc)中是否有id为viewName并实现View接口的bean 有就返回该视图 ,如果不存在传入的viewName对应的自定义视图,那么就返回null,接着走其他视图解析器

视图渲染和响应

1. 拿到view对象后, SpringMVC 调用自定义视图的 renderMergedOutputModel 方法渲染视图
相关推荐
前进的李工3 分钟前
MySQL用户管理与权限控制指南(含底层架构说明)
开发语言·数据库·sql·mysql·架构
少司府8 分钟前
C++基础入门:类和对象(中)
c语言·开发语言·c++·类和对象·运算符重载·默认成员函数
橘子编程22 分钟前
操作系统原理:从入门到精通全解析
java·linux·开发语言·windows·计算机网络·面试
唔6623 分钟前
原生 Android(Kotlin)仅串口「继承架构」完整案例二
android·开发语言·kotlin
错把套路当深情24 分钟前
Kotlin 全方向开发技术栈指南
开发语言·kotlin
飞Link30 分钟前
LangGraph 核心架构解析:节点 (Nodes) 与边 (Edges) 的工作机制及实战指南
java·开发语言·python·算法·架构
xuhaoyu_cpp_java1 小时前
Boyer-Moore 投票算法
java·经验分享·笔记·学习·算法
JavaEdge.1 小时前
Chrome加载已解压的扩展程序-清单文件缺失或不可读取 无法加载清单
java
iReachers1 小时前
HTML打包EXE配置管理教程:多项目打包设置一键保存、加载与切换
java·前端·javascript
武藤一雄1 小时前
WPF中ViewModel之间的5种通讯方式
开发语言·前端·microsoft·c#·wpf