ToB企服应用市场:ToB评测及商务社交产业平台

标题: day04-视图和视图解析器 [打印本页]

作者: 海哥    时间: 2023-2-7 22:50
标题: day04-视图和视图解析器
视图和视图解析器

1.基本介绍

2.自定义视图

2.1为什么需要自定义视图

2.2应用实例

执行流程:
2.3创建自定义视图的步骤

2.4Debug源码-自定义视图解析器执行流程

自定义视图-工作流程:
Debug-01
(1)在GoodsHandler的目标方法中打上断点:
(2)点击debug,访问view.jsp,点击超链接,可以看到后台光标跳转到断点处:
(3)在源码 BeanNameViewResolver 的 resolveViewName 方法处打上断点:
(4)点击Resume,光标跳转到了这个断点处,viewName 的值就是自定义视图对象的 id:这里完成视图解析
resolveViewName 方法如下:
  1. @Override
  2. @Nullable
  3. public View resolveViewName(String viewName, Locale locale) throws BeansException {
  4.    //获取ioc容器对象
  5.    ApplicationContext context = obtainApplicationContext();
  6.    //如果容器对象中不存在 目标方法返回的自定义视图对象id
  7.    if (!context.containsBean(viewName)) {
  8.       // Allow for ViewResolver chaining...
  9.       //就返回null,让默认的视图解析器处理该视图
  10.       return null;
  11.    }
  12.    //判断自定义的视图是不是 org.springframework.web.servlet.View 类型
  13.    if (!context.isTypeMatch(viewName, View.class)) {
  14.       //如果不是
  15.       if (logger.isDebugEnabled()) {
  16.          logger.debug("Found bean named '" + viewName + "' but it does not implement View");
  17.       }
  18.       // Since we're looking into the general ApplicationContext here,
  19.       // let's accept this as a non-match and allow for chaining as well...
  20.       return null;
  21.    }
  22.    //如果是,就返回这个自定义视图对象
  23.    return context.getBean(viewName, View.class);
  24. }
复制代码
(5)在自定义视图对象里打上断点:
(6)点击 resume,光标跳转到该断点:在这里完成视图渲染,并转发到结果页面
(7)最后由 tomcat 将数据返回给客户端:
2.5Debug源码-默认视图解析器执行流程

将默认视图解析器的优先级调高:
debug-02
(1)仍然在GoodsHandler中添加断点:
(2)浏览器访问 view.jsp,可以看到后台光标跳转到了断点处:
(3)分别在默认视图解析器(InternalResourceViewResolver)和自定义视图解析器(BeanNameViewResolver) 中的方法中打上断点:
(4)点击resume,可以看到光标先跳到了默认视图解析器的 buildView 方法中:因为默认解析器的优先级在之前设置为最高。
buildView 方法:
  1. @Override
  2. protected AbstractUrlBasedView buildView(String viewName) throws Exception {
  3.    //根据目标方法返回的viewName创建一个View对象
  4.    InternalResourceView view = (InternalResourceView) super.buildView(viewName);
  5.    if (this.alwaysInclude != null) {
  6.       view.setAlwaysInclude(this.alwaysInclude);
  7.    }
  8.    view.setPreventDispatchLoop(true);
  9.    return view;
  10. }
复制代码
这个 View 对象的 url 是按照你配置的前缀和后缀,拼接完成的 url
(5)之后就会到该View对象进行视图渲染,然后由Tomcat将数据返回给客户端。
但是如果该url下没有/WEB-INF/pages/liView.jsp文件,就会报错:
2.6Debug源码-自定义View不存在,会走默认视图解析机制

视图解析器可以配置多个,按照指定的顺序来对视图进行解析。如果上一个视图解析器不匹配,下一个视图解析器就会去解析视图,以此类推:
debug-03
(1)仍然在GoodsHandler中添加断点:
(2)浏览器访问 view.jsp,可以看到后台光标跳转到了断点处:
(3)在自定义的视图解析器 BeanNameViewResolver 中打上断点:
(4)点击resume,可以看到光标跳转到该断点处:
(5)因为在容器文件中找不到该视图对象的id了,因此会进入第一个分支,方法直接返回 null
(6)点击step over,光标跳转到中央控制器的 resolveViewName 方法中:
  1. @Nullable
  2. protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
  3.       Locale locale, HttpServletRequest request) throws Exception {
  4.    if (this.viewResolvers != null) {
  5.       //循环调用视图解析器,直到某个视图解析器返回的view不为null
  6.       for (ViewResolver viewResolver : this.viewResolvers) {
  7.          View view = viewResolver.resolveViewName(viewName, locale);
  8.          if (view != null) {
  9.             return view;
  10.          }
  11.       }
  12.    }
  13.    return null;
  14. }
复制代码
因为自定义视图解析器会返回 null,因此这里进入第二次循环,由默认的视图解析器去进行解析,然后返回对应的视图:
(7)在该方法中打上断点,点击 resume,可以看到此时 view 是由默认的视图解析器返回的视图对象,走的是默认机制。
(8)下一个就按照默认机制拼接的 url 去访问该页面,并进行渲染。然后由Tomcat返回给客户端。如果根据 url 找不到该页面,就报404错误。
补充:如果默认视图解析器优先级高,自定义的视图解析器优先级低,但是默认视图解析器返回的的View为null,这时候会继续调用自定义的视图解析器吗?
答:事实上,默认视图解析器返回的 View 不会为 null。
因为它是根据目标方法返回的字符串+你配置的前后缀进行 url 的拼接。只要目标方法返回了一个字符串,默认视图处理器就不会返回 null。
如果目标方法返回的是 null 呢?将会以目标方法的路径名称+配置的前后缀作为寻找页面的 url
因此在循环调用视图处理器的时候,一旦循环到默认视图处理器,就不会调用后面的自定义视图解析器。
3.目标方法直接指定转发或重定向

3.1使用实例

目标方法中指定转发或者重定向:
例子
3.2Debug-指定请求转发流程分析


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4