深度学习springMVC(五)一篇文章讲清楚 SpringMVC的视图解析器和 自定义视图解析器(看不懂你打我)

2021-07-08 15:23:45 浏览数 (1)

目录

  • SpringMVC的视图解析器
    • 问题:
    • 解决:
    • 实现:
    • 本质:
    • 内容:
    • 回顾没有学视图解析器之前,我们如何实现转发和重定向
    • 视图解析器代码实现
      • 使用View接口完成请求转发|重定向
      • SpringMVC视图解析器升级:ModelAndView
      • SpringMVC视图解析器再次升级:
  • SpringMVC的自定义视图解析器
    • 问题
    • 解决:
    • 实现:
    • 概念:
    • 使用:
  • SpringMVC自定义视图解析器的使用
    • 目前项目资源的声明位置和访问中存在的问题
      • 问题:
      • 实现方案:
      • 项目密室:
    • 使用自定义视图解析器优化资源跳转路径
      • 问题:
      • 解决:
      • 代码实现
    • 使用restful声明公共单元方法请求转发WEB-INF下的资源
      • 问题:
      • 解决:
      • 实现:
      • 代码
    • 重新配置springmvc.xml文件中的资源放行

SpringMVC的视图解析器

问题:

我们在使用了SpringMVC后,对于请求的处理由以前我们自己声明

Servlet处理,变为声明单元方法来处理。请求处理完成之后,需要将

处理结果响应给浏览器 ,响应方式有直接响应,请求转发,重定向。对于

请求转发和重定向,我们在单元方法中是通过返回值来告诉 DispatcherServlet如何进行此次请求的响应。而方法的返回值只有一个,所 以,我们就需要在返回值值中声明指定的关键字,让DispatcherServlet可以

通过关键字来区分是请求转发还是重定向,那么DispactherServlet底层是

如何来实现请求转发和重定向的区分的呢?

解决:

在DispatcherServlet的底层,增加逻辑代码,根据单元方法的返回值

将其返回值中的forward或者redirect关键字拆分出来,然后根据关键字

以及资源路径,最终完成资源的请求转发或者重定向。而这段逻辑代码

就是根据单元方法的返回值来完成最终的资源的处理,为了让Dispatcher

Servlet的代码结构层次更加清晰,我们可以将这段逻辑代码专门封装

起来,然后在DispatcherServlet中进行调用即可。也就意味着单元方法的

返回值被DispatcherServlet接收后,作为实参传递给了这段封装好的逻辑

代码。

实现:

视图解析器

本质:

视图解析器就是SpringMVC官方封装好的,根据单元方法的返回值

完成对应的请求转发或者重定向的对象。

**由DisatcherServlet来调用。**把返回值作为参数给DisatcherServlet。DisatcherServlet里面会创建一个处理返回值类的对象,这个对象调用里面 的方法就可以处理 返回值了

内容:

InternalResourceView:请求转发

RedirectView:重定向

ModelAndView:请求转发和重定向

回顾没有学视图解析器之前,我们如何实现转发和重定向

使用关键字实现的,使用forward关键字完成响应,使用redirect关键字完成响应。

具体不清楚这些关键字的,看之前的文章

深度学习springMVC(四)springmvc如何实现数据的响应,SpringMVC中使用作用域对象完成数据的流转(看不懂你打我)

每次我们自己写关键字,springmvc框架也想到了,比较的麻烦,所以人家把这些关键字封装到类里面,返回值作为参数给了这些类对象,就可以实现转发或者重定向。

视图解析器代码实现

使用View接口完成请求转发|重定向

代码语言:javascript复制
  //声明单元方法:使用View接口的子类对象完成请求转发或者重定向

    /**
     * 使用View接口完成请求转发|重定向
     *  解释:
     *      SpringMVC的官方,提供了一个叫做View的接口,告诉开发人员
     *      DispatcherServlet底层会调用View接口的实例化对象中的逻辑方法
     *      来完成对应的请求转发和重定向。
     *  使用:
     *      1. 单元方法的返回值为View接口类型
     *      2.真实return的为View接口的实例化对象(视图解析器)。
     *          官方提供的实现了View接口的视图解析器:
     *              InternalResourceView:请求转发
     *              RedirectView:重定向
     * @return
     */
    @RequestMapping("demoView")
   public View demoView(HttpServletRequest request){
       //处理请求
        System.out.println("MyController.demoView:View接口实例化对象完成请求转发|重定向");
       //响应结果
            //请求转发
                //return  new InternalResourceView("/req.jsp");
            //重定向
                return new RedirectView(request.getContextPath() "/redirect.jsp");
   }

SpringMVC视图解析器升级:ModelAndView

代码语言:javascript复制
 /**
     * SpringMVC视图解析器升级:ModelAndView
     *  问题:
     *      在原有的View接口的视图解析器中需要自己在单元方法中根据响应方式
     *      来创建对应的视图解析器对象返回给DispatcherServlet使用,过于麻烦。
     *  解决:
     *      从根据响应方式的不同创建不同的视图解析器对象,变为只创建一个
     *      视图解析器对象,该对象内部自动根据参数来实现请求转发或者重定向。
     *  实现:
     *      ModelAndView
     *   注意:
     *      升级后也就意味着DispatcherServlet使用ModelAndView来接收
     *      单元方法的返回值,为了兼容早期版本,让ModelAndView可以接收
     *      View接口的实例化对象。
     *  特点:
     *    ModelAndView对象是Model和View对象的结合体。既可以作为视图解析器使用
     *    又可以作为数据流转的载体使用。
     */
    @RequestMapping("md")
    public ModelAndView demoModelAndView(){
        //处理请求
        System.out.println("MyController.demoModelAndView:ModelAndView视图解析器");
        //响应结果
            //创建ModelAndView对象
            ModelAndView modelAndView=new ModelAndView();
            modelAndView.addObject("str","我是流转的数据");
            //请求转发
                //modelAndView.setViewName("forward:/mdReq.jsp");
           //重定向
                modelAndView.setViewName("redirect:/mdRedirect.jsp");
            return modelAndView;
    }

SpringMVC视图解析器再次升级:

代码语言:javascript复制
  /**
     * SpringMVC视图解析器再次升级:
     *  问题:
     *      在使用了ModelAndView对象后,已经很爽了。但是在单元方法中
     *      我们还需要创建ModelAndView对象并将请求转发或者重定向的
     *      路径存储进入,返回给DispatcherServlet使用,而我们真正
     *      想写的是资源路径以及响应方式
     *  解决:
     *      我们在单元方法中直接返回字符串资源路径及其响应方式关键字。
     *      由DispatcherServlet底层帮我们创建ModelAndView来接收
     *      单元方法的返回值。
     *  注意:
     *      虽然我们在单元方法中直接返回的字符串数据,但是DispatcherServlet
     *      并不是直接使用字符串数据而是仍然调用ModelAndView视图解析器完成请求转发或者重定向。
     */
    @RequestMapping("demoString")
    public String demoString(){
        //处理请求
        System.out.println("目前的请求转发或者重定向的方式");
        //响应结果
            //请求转发
                //return "forward:/req.jsp";
            //重定向
                return "redirect:/redirect.jsp";
    }

SpringMVC的自定义视图解析器

问题

目前我们在SpringMVC的响应中,虽然我们直接在单元方法中返回字符串数据来

表明请求转发或者重定向的资源,但是DispatcherServlet的底层默认使用 ModelAndView来完成视图资源的解析和跳转。但是ModelAndView这个视图 解析器比较死板,ModelAndView会将单元方法返回的字符串,根据关键拆分后

来完成资源的跳转,比如:”forward:/index.jsp”,那么ModelAndView就会直接

请求转发index.jsp资源。但是我们在实际生产环境中往往会有很多特殊的需求,

这样ModelAndView就无法满足了,比如,我们在项目下创建一个a文件夹,在

a文件夹下创建b子文件夹,在b下创建一个c子文件夹,然后将项目的页面资 源全部放到c文件夹下,这样我们如果在单元方法中请求转发c文件夹中的资源,

返回值路径就会很麻烦:

”forward:/a/b/c/index.jsp”

”forward:/a/b/c/page.jsp”

“forward:/a/b/c/sel.jsp”…

而且后期一旦资源路径的文件夹名字发生变更,修改起来也会非常的麻烦。

自己写的路径太长,太麻烦

**核心问题:**官方视图 解析器比较死板,只会转发重定向,我们需要灵活 的视图解析器,自己写的路径太长,太麻烦

解决:

使用自定义视图解析器,而我们自定义的视图解析器除了可以让我们根据需求

配置一些路径上的常量参数以外,还需具备ModelAndView的逻辑。所以,

我们自己需要从头创建一个新的视图解析器,在我们自己创建的视图解析器中

声明ModelAndView中的原有逻辑代码,以及我们自己需要的部分常量参数。

但是ModelAndView的逻辑我们是不知道的,那么能不能让SpringMVC官方

提供一个支持部分数据自定义的视图解析器呢,答案是可以的。我们可以通过配置 文件来配置一些我们在视图解析器中的常量数据

实现:

代码语言:javascript复制
	InternalResourceViewResolver

概念:

因为InternalResourceViewResolver可以让我们通过配置文件来设置一些常量

参数,所以我们将该视图解析器称为自定义视图解析器。

使用:

1.在springmvc.xml文件中进行配置

2.在单元方法中按照指定的格式返回资源路径

代码语言:javascript复制
 <!--配置自定义视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--配置资源路径的前缀-->
            <property name="prefix" value="/a/b/c/"></property>
        <!--配置资源路径的后缀-->
            <property name="suffix" value=".jsp"></property>
    </bean>
代码语言:javascript复制
@Controller
public class MyControllerView {
    //声明单元方法:使用默认的ModelAndView视图解析器
    @RequestMapping("mv")
    public String demoMv(){
        System.out.println("MyControllerView.demoMv:测试使用默认的ModelAndView视图解析器");
        return "forward:/a/b/c/c.jsp";
    }

返回的字符串里面带了forward这些关键字,就调用ModelAndView视图解析器。不带,就使用自定义视图解析器





    //声明单元方法:使用默认的ModelAndView视图解析器
    @RequestMapping("myView")
    public String demoInternalResourceViewResolver(){
        System.out.println("MyControllerView.demoInternalResourceViewResolver:测试使用自定义视图解析器");
        return "c";
    }
}

SpringMVC自定义视图解析器的使用

目前项目资源的声明位置和访问中存在的问题

问题:

目前我们在完成功能开发时,会将项目相关的页面资源及静态资源直接声明

在web目录下,或者web目录下的子文件夹中。而web目录及其声明的子

目录中的资源,在浏览器中是可以直接被访问到的。也就是说,只要我们知道

某个资源的URL地址,在浏览器中是可以直接发起请求访问该资源的,极不安全。

实现方案:

在我们的web项目中造一间密室,将重要的资源放到密室中。而密室是对外不开 放的,也就说密室中的资源必须通过tomcat服务器的内部转发才能进行访问。就 算浏览器听说项目有这样密室,并且密室中也有浏览器想要的资源,浏览器发起的 请求地址是正确的,但是我们可以在服务器端死不承认,我们没有这个资源,在后 台给浏览器响应404.如果是我们觉得靠谱的请求,我们就在服务器端请求转发资 源给浏览器使用。

项目密室:

其实我们的web项目在创建的时候就自动的在web目录下创建了密室,就是

WEB-INF文件夹。也就是说WEB-INF文件夹下的资源浏览器是无法直接访问

的,必须通过内部请求转发才能访问。

代码语言:javascript复制
   //声明单元方法:检查请求,是否给密室中的资源
    @RequestMapping("getJsp")
    public String getJsp(){
        //处理请求
        System.out.println("MyController.getJsp:检查密室资源请求是否合理");
        //响应结果
        return "forward:/WEB-INF/jsp/cc.jsp";
    }

使用自定义视图解析器优化资源跳转路径

问题:

我们在将重要的项目资源放在WEB-INF文件夹中后,只能通过内部的请求转发来

访问资源。如果WEB-INF下的资源较多,造成请求转发的路径书写麻烦,而且后 期一旦资源的目录发生变更,修改起来会非常的麻烦,怎么办?

解决:

我们真正想在单元方法中想写的是资源的名字,而请求转发WEB-INF下的资源路 径是公共的,每次都要写。而刚好我们的自定义视图解析器就是专门用来进行请求

转发的,而且可以设置转发资源的公共前缀和后缀信息。所以,我们可以使用自定 义视图解析器来完成WEB-INF下的资源的请求转发。

代码实现

代码语言:javascript复制
  <!--配置自定义视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
代码语言:javascript复制
    //声明单元方法:使用自定义视图解析器请求转发WEB-INF下的资源
    @RequestMapping("getJsp2")
    public String getJsp2(){
        //处理请求
        System.out.println("MyController.getJsp2:使用自定义视图解析器访问");
        //响应结果
        return "dd";
    }

使用restful声明公共单元方法请求转发WEB-INF下的资源

问题:

在项目中使用了自定义视图解析器后,可以在单元方法中简单的返回一个 WEB-INF下的资源的名字就可以完成资源的请求转发了,美滋滋。但是我们的资 源是非常多的,但是我们的单元方法的返回值只能有一个。总不能我们给WEB-INF

下的每个资源都声明一个对应的单元方法来完成请求转发吧,太麻烦了。

解决:

根据请求,请求转发WEB-INF下的资源的单元方法是肯定要声明的。我们可以

声明一个公共的单元方法,该单元方法不参与请求的逻辑处理,只负责根据请求

转发WEB-INF下的资源。

实现:

使用restful完成

代码

代码语言:javascript复制
  <!--配置自定义视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
代码语言:javascript复制
//声明公共单元方法:请求转发WEB-INF下的资源
    @RequestMapping("{url}")
    public String getJsp3(@PathVariable  String url){
        //处理请求
        System.out.println("MyController.getJsp3:公共单元方法,请求转发WEB-INF下的资源");
        //响应结果
        return url;
    }

重新配置springmvc.xml文件中的资源放行

如果把静态资源放到 web-inf 下,我们需要资源放行

代码语言:javascript复制
    <!--配置静态资源放行-->
    <mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
    <mvc:resources mapping="/css/**" location="/WEB-INF/css/"></mvc:resources>
    <mvc:resources mapping="/images/**" location="/WEB-INF/images/"></mvc:resources>

0 人点赞