首页IT科技视图解析器有哪些功能组成(day04-视图和视图解析器)

视图解析器有哪些功能组成(day04-视图和视图解析器)

时间2025-05-01 09:25:12分类IT科技浏览3953
导读:视图和视图解析器 1.基本介绍...

视图和视图解析器

1.基本介绍

在SpringMVC中的目标方法            ,最终返回的都是一个视图(有各种视图)

注意                 ,这里的视图是一个类对象      ,不是一个页面!!

返回的视图都会由一个视图解析器来处理(视图解析器有很多种)

2.自定义视图

2.1为什么需要自定义视图

在默认情况下         ,我们都是返回默认的视图                 ,然后返回的视图交由 SpringMVC 的 InternalResourcesViewResolver 默认视图解析器来处理的:

在实际开发中         ,因为业务需求      ,我们有时候需要自定义视图解析器

视图解析器可以配置多个                 ,按照指定的顺序来对视图进行解析            。如果上一个视图解析器不匹配            ,下一个视图解析器就会去解析视图   ,以此类推                 。

2.2应用实例

执行流程:

view.jsp                 ,请求到 Handler

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>自定义视图测试</title> </head> <body> <h1>自定义视图测试</h1> <a href="https://www.cnblogs.com/liyuelian/archive/2023/02/07/goods/buy">点击到自定义视图</a> </body> </html>

GoodsHandler.java

package com.li.web.viewresolver; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @author 李 * @version 1.0 */ @RequestMapping(value = "/goods") @Controller public class GoodsHandler { @RequestMapping(value = "/buy") public String buy(){ System.out.println("----------buy()---------"); return "liView";//自定义视图名 } }

自定义视图 MyView.java

package com.li.web.viewresolver; import org.springframework.stereotype.Component; import org.springframework.web.servlet.view.AbstractView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; /** * @author 李 * @version 1.0 * 1. MyView 继承了AbstractView              ,就可以作为了一个视图使用 * 2. @Component(value = "myView") ,该视图会注入到容器中               ,id为 liView */ @Component(value = "liView") public class MyView extends AbstractView { @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { //1.完成视图渲染 System.out.println("进入到自己的视图..."); //2.并且确定我们要跳转的页面                 ,如 /WEB-INF/pages/my_view.jsp /* * 1.下面就是请求转发到 /WEB-INF/pages/my_view.jsp * 2.该路径会被springmvc解析成 /web工程路径/WEB-INF/pages/my_view.jsp */ request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp") .forward(request, response); } }

结果页面 my_view.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>my_view</title> </head> <body> <h1>进入到my_view页面</h1> <p>从自定义视图来的...</p> </body> </html>

springDispatcherServlet-servlet.xml 配置自定义视图解析器

<!--1.指定扫描的包--> <context:component-scan base-package="com.li.web"/> <!--2.配置视图解析器[默认的视图解析器]--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置属性 suffix(后缀) 和 prefix(前缀)--> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> <!--3. 3.1 配置自定义视图解析器 BeanNameViewResolver 3.2 BeanNameViewResolver 可以解析我们自定义的视图 3.3 属性 order 表示视图节解析器执行的顺序   ,值越小优先级越高 3.4 order 的默认值为最低优先级-LOWEST_PRECEDENCE 3.5 默认的视图解析器就是最低优先级            ,因此我们的自定义解析器会先执行 --> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> <property name="order" value="99"/> </bean> <!--4.加入两个常规的配置--> <!--支持SpringMVC的高级功能                 ,比如:JSR303校验      ,映射动态请求--> <mvc:annotation-driven></mvc:annotation-driven> <!--将SpringMVC不能处理的请求         ,交给tomcat处理                 ,比如css         ,js--> <mvc:default-servlet-handler/>

测试      ,访问view.jsp                 ,点击超链接

成功跳转到 my_view.jsp

后台输出如下:说明整个执行流程如图所示      。

2.3创建自定义视图的步骤

自定义一个视图:创建一个 View 的 bean            ,该 bean 需要继承自 AbstractView   ,并实现renderMergedOutputModel方法 并把自定义 View 加入到 IOC 容器中 自定义视图的视图解析器                 ,使用 BeanNameViewResolver              ,这个视图解析器也需要配置到 ioc 容器文件中 BeanNameViewResolver 的调用优先级需要设置一下,设置 order 比 Integer.MAX_VALUE 小的值               ,以确保其在默认的视图解析器之前被调用

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

自定义视图-工作流程:

SpringMVC 调用目标方法                 ,返回自定义 View 在 IOC 容器中的 id SpringMVC 调用 BeanNameViewResolver 视图解析器:从 IOC 容器中获取返回 id 值对应的 bean   ,即自定义的 View 的对象 SpringMVC 调用自定义视图的 renderMergedOutputModel 方法            ,渲染视图 说明:如果 SpringMVC 调用 Handler 的目标方法时                 ,返回的自定义 View       ,在 IOC 容器中的 id 不存在         ,则仍然按照默认的视图解析器机制处理         。

Debug-01

(1)在GoodsHandler的目标方法中打上断点:

(2)点击debug                 ,访问view.jsp         ,点击超链接      ,可以看到后台光标跳转到断点处:

(3)在源码 BeanNameViewResolver 的 resolveViewName 方法处打上断点:

(4)点击Resume                 ,光标跳转到了这个断点处            ,viewName 的值就是自定义视图对象的 id:这里完成视图解析

resolveViewName 方法如下:

@Override @Nullable public View resolveViewName(String viewName, Locale locale) throws BeansException { //获取ioc容器对象 ApplicationContext context = obtainApplicationContext(); //如果容器对象中不存在 目标方法返回的自定义视图对象id if (!context.containsBean(viewName)) { // Allow for ViewResolver chaining... //就返回null   ,让默认的视图解析器处理该视图 return null; } //判断自定义的视图是不是 org.springframework.web.servlet.View 类型 if (!context.isTypeMatch(viewName, View.class)) { //如果不是 if (logger.isDebugEnabled()) { logger.debug("Found bean named " + viewName + " but it does not implement View"); } // Since were looking into the general ApplicationContext here, // lets accept this as a non-match and allow for chaining as well... return null; } //如果是                 ,就返回这个自定义视图对象 return context.getBean(viewName, View.class); }

(5)在自定义视图对象里打上断点:

(6)点击 resume              ,光标跳转到该断点:在这里完成视图渲染,并转发到结果页面

(7)最后由 tomcat 将数据返回给客户端:

2.5Debug源码-默认视图解析器执行流程

将默认视图解析器的优先级调高:

debug-02

(1)仍然在GoodsHandler中添加断点:

(2)浏览器访问 view.jsp               ,可以看到后台光标跳转到了断点处:

(3)分别在默认视图解析器(InternalResourceViewResolver)和自定义视图解析器(BeanNameViewResolver) 中的方法中打上断点:

(4)点击resume                 ,可以看到光标先跳到了默认视图解析器的 buildView 方法中:因为默认解析器的优先级在之前设置为最高                 。

buildView 方法:

@Override protected AbstractUrlBasedView buildView(String viewName) throws Exception { //根据目标方法返回的viewName创建一个View对象 InternalResourceView view = (InternalResourceView) super.buildView(viewName); if (this.alwaysInclude != null) { view.setAlwaysInclude(this.alwaysInclude); } view.setPreventDispatchLoop(true); return view; }

这个 View 对象的 url 是按照你配置的前缀和后缀   ,拼接完成的 url

(5)之后就会到该View对象进行视图渲染            ,然后由Tomcat将数据返回给客户端         。

但是如果该url下没有/WEB-INF/pages/liView.jsp文件                 ,就会报错:

2.6Debug源码-自定义View不存在      ,会走默认视图解析机制

视图解析器可以配置多个         ,按照指定的顺序来对视图进行解析      。如果上一个视图解析器不匹配                 ,下一个视图解析器就会去解析视图         ,以此类推:

在容器文件中      ,将默认的视图解析器调用优先级降低                 ,提高自定义视图解析器的调用优先级                 。见2.2的容器文件配置

删除2.2中的自定义视图MyView.java            。也就是说            ,自定义视图解析器解析目标方法返回的视图对象时   ,将会无法解析该视图                 ,因为它不存在   。

这时就会去调用下一个优先级的视图解析器              ,即默认视图解析器                 。

debug-03

(1)仍然在GoodsHandler中添加断点:

(2)浏览器访问 view.jsp,可以看到后台光标跳转到了断点处:

(3)在自定义的视图解析器 BeanNameViewResolver 中打上断点:

(4)点击resume               ,可以看到光标跳转到该断点处:

(5)因为在容器文件中找不到该视图对象的id了                 ,因此会进入第一个分支   ,方法直接返回 null

(6)点击step over            ,光标跳转到中央控制器的 resolveViewName 方法中:

@Nullable protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { //循环调用视图解析器                 ,直到某个视图解析器返回的view不为null for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }

因为自定义视图解析器会返回 null      ,因此这里进入第二次循环         ,由默认的视图解析器去进行解析                 ,然后返回对应的视图:

(7)在该方法中打上断点         ,点击 resume      ,可以看到此时 view 是由默认的视图解析器返回的视图对象                 ,走的是默认机制              。

(8)下一个就按照默认机制拼接的 url 去访问该页面            ,并进行渲染。然后由Tomcat返回给客户端               。如果根据 url 找不到该页面   ,就报404错误                 。

补充:如果默认视图解析器优先级高                 ,自定义的视图解析器优先级低              ,但是默认视图解析器返回的的View为null,这时候会继续调用自定义的视图解析器吗?

答:事实上               ,默认视图解析器返回的 View 不会为 null   。

因为它是根据目标方法返回的字符串+你配置的前后缀进行 url 的拼接            。只要目标方法返回了一个字符串                 ,默认视图处理器就不会返回 null                 。

如果目标方法返回的是 null 呢?将会以目标方法的路径名称+配置的前后缀作为寻找页面的 url

因此在循环调用视图处理器的时候   ,一旦循环到默认视图处理器            ,就不会调用后面的自定义视图解析器      。

3.目标方法直接指定转发或重定向

3.1使用实例

目标方法中指定转发或者重定向:

默认返回的方式是请求转发                 ,然后用视图处理器进行处理         。 但是也可以在目标方法中直接指定重定向或者转发的 url 的地址                 。 注意:如果指定重定向      ,则不能定向到 /WEB-INF 目录中         。因为该目录为 Tomcat 的内部目录      。

例子

view.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>请求转发或重定向</title> </head> <body> <h1>请求转发或重定向</h1> <a href="https://www.cnblogs.com/liyuelian/archive/2023/02/07/goods/order">测试在目标方法找中指定请求转发或重定向</a> </body> </html>

GoodsHandler.java

package com.li.web.viewresolver; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @author 李 * @version 1.0 */ @RequestMapping(value = "/goods") @Controller public class GoodsHandler { //演示直接指定请求转发或者重定向 @RequestMapping(value = "/order") public String order() { System.out.println("=========order()========="); //请求转发到 /WEB-INF/pages/my_view.jsp //下面的路径会被解析/web工程路径/WEB-INF/pages/my_view.jsp return "forward:/WEB-INF/pages/my_view.jsp"; } }

访问 view.jsp         ,点击超链接:

成功进入到请求转发的页面:

请求转发也可以转发到WEB-INF目录之外的页面                 。

修改 GoodsHandler.java 的 order 方法:

//演示直接指定请求转发或者重定向 @RequestMapping(value = "/order") public String order() { System.out.println("=========order()========="); //重定向 //1.对于重定向来说                 ,不能重定向到/WEB-INF/目录下 //2.redirect 为重定向的关键字 //3./login.jsp 是在服务器解析的         ,解析为 /web工程路径/login.jsp return "redirect:/login.jsp"; }

redeployTomcat      ,访问 view.jsp                 ,点击超链接            ,可以看到成功重定向到 login.jsp页面

3.2Debug-指定请求转发流程分析

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
代理ip可以用来做什么(ip 代理,附详细介绍) 香港服务器的好处(适合租用香港服务器的行业是什么)