通过网盘分享的文件:SpringMVC6
链接: https://pan.baidu.com/s/1zXHQejjbU-hD3bMyBaGVJw?pwd=648t 提取码: 648t
–来自百度网盘超级会员v6的分享

五、SpringMVC中视图的实现原理

1、Spring MVC视图

5.1.1、视图可配置

在Spring MVC中视图View是支持定制的,例如我们之前在 springmvc.xml 文件中进行了如下的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--组件扫描-->
    <context:component-scan base-package="com.longdidi"/>
    <!--视图解析器-->
    <bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
        <!--作用于视图渲染的过程中,可以设置视图渲染后输出时采用的编码字符集-->
        <property name="characterEncoding" value="UTF-8"/>
        <!--如果配置多个视图解析器,它来决定优先使用哪个视图解析器,它的值越小优先级越高-->
        <property name="order" value="1"/>
        <!--当 ThymeleafViewResolver 渲染模板时,会使用该模板引擎来解析、编译和渲染模板-->
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring6.SpringTemplateEngine">
                <!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息,加载模板并对其进行解析-->
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
                        <!--设置模板文件的位置(前缀)-->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!--设置模板文件后缀(后缀),Thymeleaf文件扩展名不一定是html,也可以是其他,例如txt,大部分都是html-->
                        <property name="suffix" value=".html"/>
                        <!--设置模板类型,例如:HTML,TEXT,JAVASCRIPT,CSS等-->
                        <property name="templateMode" value="HTML"/>
                        <!--用于模板文件在读取和解析过程中采用的编码字符集-->
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>

以上的配置表明当前SpringMVC框架使用的视图View是Thymeleaf的
如果需要换成其他的视图View,修改以上的配置即可,这样就可以非常轻松的完成视图View的扩展
这种设计是完全符合OCP开闭原则的:视图View和框架是解耦合的,耦合度低扩展能力强,视图View可以通过配置文件进行灵活切换。

5.1.2、Spring MVC常见视图

Spring MVC支持的常见视图包括

  1. InternalResourceView:内部资源视图(Spring MVC框架内置的,专门为JSP模板语法准备的)
  2. RedirectView:重定向视图(Spring MVC框架内置的,用来完成重定向效果)
  3. ThymeleafView:Thymeleaf视图(第三方的,为Thymeleaf模板语法准备的)
  4. FreeMarkerView:FreeMarker视图(第三方的,为FreeMarker模板语法准备的)
  5. VelocityView:Velocity视图(第三方的,为Velocity模板语法准备的)
  6. PDFView:PDF视图(第三方的,专门用来生成pdf文件视图)
  7. ExcelView:Excel视图(第三方的,专门用来生成excel文件视图)

5.1.3、视图的核心接口

实现视图的核心类与接口包括

  1. DispatcherServlet类(前端控制器)

    • 职责:在整个Spring MVC执行流程中负责中央调度

    • 核心方法:doDispatch

      在这里插入图片描述

  2. ViewResolver接口(视图解析器)

    • 职责:负责将逻辑视图名转换为物理视图名,最终创建View接口的实现类(即视图实现类对象)

    • 核心方法:resolveViewName

      在这里插入图片描述

  3. View接口(视图)

    • 职责:负责将模型数据Model渲染为视图格式(HTML代码),并最终将生成的视图(HTML代码)输出到客户端(它负责将模板语言转换成HTML代码)

    • 核心方法:render

      在这里插入图片描述

  4. ViewResolverRegistry(视图解析器注册器)

    • 负责在web容器(Tomcat)启动的时候完成视图解析器的注册。如果有多个视图解析器会将视图解析器对象按照order的配置放入List集合

总结

  • 实现视图的核心类和接口包括:ViewResolverRegistry、DispatcherServlet、ViewResolver、View
  • 如果想定制自己的视图组件:
    • 编写类实现ViewResolver接口,实现resolveViewName方法,在该方法中完成逻辑视图名转换为物理视图名并返回View对象
    • 编写类实现View接口,实现render方法,在该方法中将模板语言转换成HTML代码,并将HTML代码响应到浏览器
  • 如果Spring MVC框架中使用Thymeleaf作为视图技术,那么相关的类包括:
    • ThymeleafView
    • ThymeleafViewResolver

5.1.4、视图机制的原理描述

(1)、Thymeleaf

假设SpringMVC中使用了Thymeleaf作为视图

第一步:浏览器发送请求给web服务器

第二步:Spring MVC中的DispatcherServlet接收到请求

第三步:DispatcherServlet根据请求路径分发到对应的Controller

第四步:DispatcherServlet调用Controller的方法

第五步:Controller的方法处理业务并返回一个逻辑视图名给DispatcherServlet

第六步:DispatcherServlet调用ThymeleafViewResolver的resolveViewName方法,将逻辑视图名转换为物理视图名,并创建ThymeleafView对象返回给DispatcherServlet

第七步:DispatcherServlet再调用ThymeleafView的render方法,render方法将模板语言转换为HTML代码,响应给浏览器,完成最终的渲染

(2)、JSP

假设我们SpringMVC中使用了JSP作为视图

第一步:浏览器发送请求给web服务器

第二步:Spring MVC中的DispatcherServlet接收到请求

第三步:DispatcherServlet根据请求路径分发到对应的Controller

第四步:DispatcherServlet调用Controller的方法

第五步:Controller的方法处理业务并返回一个逻辑视图名给DispatcherServlet

第六步:DispatcherServlet调用InternalResourceViewResolverresolveViewName方法,将逻辑视图名转换为物理视图名,并创建InternalResourceView对象返回给DispatcherServlet

第七步:DispatcherServlet再调用InternalResourceViewrender方法,render方法将模板语言转换为HTML代码,响应给浏览器,完成最终的渲染

5.1.5、逻辑视图名到物理视图名

逻辑视图名最终转换的物理视图名是什么取决再springmvc.xml文件中视图解析器的配置

假如视图解析器配置的是ThymeleafViewResolver,如下

<bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
    <property name="characterEncoding" value="UTF-8"/>
    <property name="order" value="1"/>
    <property name="templateEngine">
        <bean class="org.thymeleaf.spring6.SpringTemplateEngine">
            <property name="templateResolver">
                <bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
                    <property name="prefix" value="/WEB-INF/templates/"/>
                    <property name="suffix" value=".html"/>
                    <property name="templateMode" value="HTML"/>
                    <property name="characterEncoding" value="UTF-8"/>
                </bean>
            </property>
        </bean>
    </property>
</bean>

以下程序返回逻辑视图名:index

@RequestMapping("/index")
public String toIndex(){
    return "index";
}

最终逻辑视图名"index" 转换为物理视图名:/WEB-INF/templates/index.html

假如视图解析器配置的是InternalResourceViewResolver,如下:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/templates/"/>
  <property name="suffix" value=".jsp"/>
</bean>

以下程序返回逻辑视图名:index

@RequestMapping("/index")
public String toIndex(){
    return "index";
}

最终逻辑视图名"index" 转换为物理视图名:/WEB-INF/templates/index.jsp

2、搭建测试模块框架

创建springmvc-05-001模块

  • 结构图

    在这里插入图片描述

  • 配置文件

    • pom.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.longdidi</groupId>
          <artifactId>springmvc-05-001</artifactId>
          <version>1.0-SNAPSHOT</version>
      
          <!-- 打包方式设置为war方式 -->
          <packaging>war</packaging>
      
          <properties>
              <maven.compiler.source>21</maven.compiler.source>
              <maven.compiler.target>21</maven.compiler.target>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          </properties>
      
          <dependencies>
              <!-- Spring MVC依赖 -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>6.1.13</version>
              </dependency>
              <!--日志框架Logback依赖-->
              <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
                  <version>1.5.11</version>
              </dependency>
              <!--Servlet依赖-->
              <dependency>
                  <groupId>jakarta.servlet</groupId>
                  <artifactId>jakarta.servlet-api</artifactId>
                  <version>6.1.0</version>
                  <scope>provided</scope>
              </dependency>
              <!--Spring6和Thymeleaf整合依赖-->
              <dependency>
                  <groupId>org.thymeleaf</groupId>
                  <artifactId>thymeleaf-spring6</artifactId>
                  <version>3.1.2.RELEASE</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • web.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
               version="6.0">
      
          <!--配置字符编码过滤器-->
          <filter>
              <filter-name>CharacterEncodingFilter</filter-name>
              <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
              <init-param>
                  <param-name>encoding</param-name>
                  <param-value>UTF-8</param-value>
              </init-param>
              <init-param>
                  <param-name>forceRequestEncoding</param-name>
                  <param-value>true</param-value>
              </init-param>
              <init-param>
                  <param-name>forceResponseEncoding</param-name>
                  <param-value>true</param-value>
              </init-param>
          </filter>
          <filter-mapping>
              <filter-name>CharacterEncodingFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
      
          <!--配置前端控制器-->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--手动设置springmvc配置文件的路径及名字-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc.xml</param-value>
              </init-param>
              <!--为了提高用户的第一次访问效率,建议在web服务器启动时初始化前端控制器-->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    • springmvc.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
          <!--组件扫描-->
          <context:component-scan base-package="com.longdidi"/>
          
          <!--视图解析器-->
          <bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
              <!--作用于视图渲染的过程中,可以设置视图渲染后输出时采用的编码字符集-->
              <property name="characterEncoding" value="UTF-8"/>
              <!--如果配置多个视图解析器,它来决定优先使用哪个视图解析器,它的值越小优先级越高-->
              <property name="order" value="1"/>
              <!--当 ThymeleafViewResolver 渲染模板时,会使用该模板引擎来解析、编译和渲染模板-->
              <property name="templateEngine">
                  <bean class="org.thymeleaf.spring6.SpringTemplateEngine">
                      <!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息,加载模板并对其进行解析-->
                      <property name="templateResolver">
                          <bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
                              <!--设置模板文件的位置(前缀)-->
                              <property name="prefix" value="/WEB-INF/templates/"/>
                              <!--设置模板文件后缀(后缀),Thymeleaf文件扩展名不一定是html,也可以是其他,例如txt,大部分都是html-->
                              <property name="suffix" value=".html"/>
                              <!--设置模板类型,例如:HTML,TEXT,JAVASCRIPT,CSS等-->
                              <property name="templateMode" value="HTML"/>
                              <!--用于模板文件在读取和解析过程中采用的编码字符集-->
                              <property name="characterEncoding" value="UTF-8"/>
                          </bean>
                      </property>
                  </bean>
              </property>
          </bean>
      </beans>
      
    • index.html

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>首页</title>
      </head>
      <body>
      <h1>SpringMVC视图实现原理</h1>
      <hr>
      
      </body>
      </html>
      
    • test.html

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>test page</title>
      </head>
      <body>
      <h1>test page!</h1>
      </body>
      </html>
      
    • a.html

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>page a</title>
      </head>
      <body>
      <h1>Page A!!!</h1>
      </body>
      </html>
      
    • b.html

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>page b</title>
      </head>
      <body>
      <h1>Page B!!!</h1>
      </body>
      </html>
      
    • c.html

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>page c</title>
      </head>
      <body>
      <h1>Page C!!!</h1>
      </body>
      </html>
      
    • d.html

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>page d</title>
      </head>
      <body>
      <h1>Page D!!!</h1>
      </body>
      </html>
      
    • index.jsp

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>JSP页面</title>
      </head>
      <body>
      <h1>我的第一个JSP页面</h1>
      </body>
      </html>
      
    • IndexController

      package com.longdidi;
      
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      
      @Controller
      public class IndexController {
      
          @RequestMapping("/")
          public String toIndex() {
              return "index";
          }
      }
      
      
  • 启动项目测试

    在这里插入图片描述

3、常见视图

5.3.1、Thymeleaf视图

在前面的内容中采用的都是Thymeleaf视图,测试一下看看底层创建的视图对象是不是ThymeleafView
springmvc.xml配置内容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--组件扫描-->
    <context:component-scan base-package="com.longdidi"/>

    <!--视图解析器-->
    <bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
        <!--作用于视图渲染的过程中,可以设置视图渲染后输出时采用的编码字符集-->
        <property name="characterEncoding" value="UTF-8"/>
        <!--如果配置多个视图解析器,它来决定优先使用哪个视图解析器,它的值越小优先级越高-->
        <property name="order" value="1"/>
        <!--当 ThymeleafViewResolver 渲染模板时,会使用该模板引擎来解析、编译和渲染模板-->
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring6.SpringTemplateEngine">
                <!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息,加载模板并对其进行解析-->
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
                        <!--设置模板文件的位置(前缀)-->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!--设置模板文件后缀(后缀),Thymeleaf文件扩展名不一定是html,也可以是其他,例如txt,大部分都是html-->
                        <property name="suffix" value=".html"/>
                        <!--设置模板类型,例如:HTML,TEXT,JAVASCRIPT,CSS等-->
                        <property name="templateMode" value="HTML"/>
                        <!--用于模板文件在读取和解析过程中采用的编码字符集-->
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>

Controller代码如下

package com.longdidi;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

    @RequestMapping("/")
    public String toIndex() {
        return "index";
    }
}

index.html视图页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>SpringMVC视图实现原理</h1>
<hr>

</body>
</html>

在DispatcherServlet的doDispatch方法的下图位置添加断点

在这里插入图片描述

启动Tomcat,在浏览器地址栏上发送请求:http://localhost:8080/springmvc/

在这里插入图片描述

程序走到以上位置,这行代码是调用对应的Controller,并且Controller最终会返回ModelAndView对象mv,返回mv之后,接下来就是视图处理与渲染

接着往下走,走到下图这一行

在这里插入图片描述

这个方法的作用是处理分发结果,就是在这个方法当中进行了视图的处理与渲染,进入该方法

在这里插入图片描述

进去之后走到上图位置,这个方法就是用来渲染页面的方法,再进入该方法

在这里插入图片描述

走到上图位置就可以看到底层创建的是ThymeleafView对象

5.3.2、JSP视图(了解)

再来跟一下源码看看JSP视图底层创建的是不是InternalResourceView对象

InternalResourceView是SpringMVC框架内置的,翻译为内部资源视图,SpringMVC把JSP看做是内部资源,可见JSP在之前的技术栈中有很高的地位

不过当下流行的开发中JSP使用较少,这里不再详细讲解,只是测试一下

springmvc.xml配置如下

	<!--组件扫描-->
    <context:component-scan base-package="com.longdidi"/>
    
    <!--视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

Controller代码如下:

package com.longdidi;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

    @RequestMapping("/")
    public String toIndex() {
        return "index";
    }
}

index.jsp视图页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSP页面</title>
</head>
<body>
<h1>我的第一个JSP页面</h1>
</body>
</html>

启动web容器添加断点跟踪

在这里插入图片描述

通过测试得知:对于JSP视图来说,底层创建的视图对象是InternalResourceView

4、转发与重定向

5.4.1、转发/重定向区别

(1)、转发
  • 请求次数

    • 转发是一次请求,因此浏览器地址栏上的地址不会发生变化

    • 重定向是两次请求,因此浏览器地址栏上的地址会发生变化

  • 实现方式

    • 转发的代码实现:request.getRequestDispatcher(“/index”).forward(request, response);

    • 重定向的代码实现:response.sendRedirect(“/webapproot/index”);

  • 资源跳转

    • 转发是服务器内部资源跳转,由服务器来控制,不可实现跨域访问

    • 重定向可以完成内部资源的跳转,也可以完成跨域跳转

  • 资源访问

    转发的方式可以访问WEB-INF目录下受保护的资源

    重定向相当于浏览器重新发送了一次请求,在浏览器直接发送的请求是无法访问WEB-INF目录下受保护资源的

5.4.2、转发/重定向原理

(1)、转发原理
  1. 假设发送了 /a 请求,执行了 AServlet
  2. 在AServlet 中通过request.getRequestDispatcher("/b").forward(request,response);转发到BServlet
  3. 从AServlet跳转到BServlet是服务器内部来控制的,对于浏览器而言,浏览器只发送了一个 /a 请求
(2)、重定向原理
  1. 假设发送了 /a 请求,执行了 AServlet
  2. 在AServlet 中通过response.sendRedirect("/webapproot/b")重定向到BServlet
  3. 此时服务器会将请求路径/webapproot/b响应给浏览器
  4. 浏览器会自发的再次发送/webapproot/b请求来访问BServlet
  5. 因此对于重定向来说,发送了两次请求,一次是 /webapproot/a,另一次是/webapproot/b

以上所描述的是使用原生Servlet API来完成转发和重定向

5.4.3、SpringMVC的实现

(1)、forward

在Spring MVC中默认就是转发的方式,之前所写的程序都是转发的方式

只不过都是转发到Thymeleaf的模板文件xxx.html上

在Spring MVC中使用forward:资源路径 转发到另一个Controller上

TestController添加如下方法

	@RequestMapping("/a")
    public String toA() {
        // 返回的是一个逻辑视图名称
        //return "a";

        // 采用SpringMVC的转发方式跳转到 /b
        // 转发的时候格式有特殊要求: return "forward:下一个资源的路径";
        // 这个就不是逻辑视图名称了
        return "forward:/b"; // 创建InternalResourceView对象
    }

    @RequestMapping("/b")
    public String toB() {
        // 返回的是一个逻辑视图名称
        return "b"; // 创建ThymeleafView对象
    }

index.html添加如下超链接

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>b</title>
</head>
<body>
<h1>Page B!!!</h1>
</body>
</html>

启动服务器,浏览器地址栏上输入:http://localhost:8080/springmvc/a

在这里插入图片描述

点击超链接A

在这里插入图片描述

通过测试,可以顺利的完成转发,转发是一次请求,可以看到地址栏上的地址没有发生改变

来跟踪一下源码,看看以上程序执行过程中,创建了几个视图对象,分别是什么?

在这里插入图片描述

在这里插入图片描述

通过源码的跟踪得知:整个请求处理过程中,一共创建了两个视图对象

  • InternalResourceView
  • ThymeleafView

这说明转发底层创建的视图对象是:InternalResourceView

思考:既然会创建InternalResourceView,应该会对应一个视图解析器呀(InternalResourceViewResolver)?但是在springmvc.xml文件中只配置了ThymeleafViewResolver,并没有配置InternalResourceViewResolver,这是因为forward: 后面的不是逻辑视图名,而是一个请求路径**,因此转发是不需要视图解析器的
另外转发使用的是InternalResourceView也说明了转发是内部资源的跳转(Internal是内部的意思,Resource是资源的意思)

(2)、redirect
应用内重定向

redirect是专门完成重定向效果的

重定向的语法: return "redirect:资源路径"

TestController添加如下方法

	@RequestMapping("/c")
    public String toC() {
        // 重定向写法
        return "redirect:/d"; // 创建RedirectView
    }

    @RequestMapping("/d")
    public String toD() {
        // 返回的是一个逻辑视图名称
        return "d"; // 创建ThymeleafView对象
    }

index.html视图页面添加超链接

<a th:href="@{/c}">C页面</a><br>
<a th:href="@{/d}">D页面</a><br>

启动服务器,浏览器地址栏上输入:http://localhost:8080/springmvc/

在这里插入图片描述

点击超链接C

在这里插入图片描述

可见重定向是两次请求,地址栏上的地址发生了改变

可以看一下源码,在重定向的时候,Spring MVC创建哪个视图对象

在这里插入图片描述

在这里插入图片描述

通过断点调试可以看出,当重定向的时候SpringMVC会创建一个重定向视图对象:RedirectView,这个视图对象也是SpringMVC框架内置的
另外可以看出重定向之后的第二次请求创建的视图对象就是ThymeleafView了

应用间重定向

从springmvc应用重定向到springmvc2应用(跨域),语法是:

@RequestMapping("/a")
public String a(){
    return "redirect:http://localhost:8080/springmvc2/b";
}

可以自行测试一下!!!

5、无方法跳转

(1)、mvc:view-controller

<mvc:view-controller> 配置用于将某个请求映射到特定的视图上,即指定某一个 URL 请求到一个视图资源的映射,使得这个视图资源可以被访问。它相当于是一个独立的处理程序,不需要编写任何 Controller,只需要指定 URL 和对应的视图名称就可以了

一般情况下,<mvc:view-controller> 配置可以替代一些没有业务逻辑的 Controller(例如首页、错误页面等)

当用户访问配置的 URL 时,框架将直接匹配到对应的视图而无需再经过其他控制器的处理

<mvc:view-controller> 配置的格式如下:

<mvc:view-controller path="/如何访问该页面" view-name="对应的逻辑视图名称" />

其中:

  • path:被映射的 URL 路径
  • view-name:对应的逻辑视图名称

例如配置首页的映射

<mvc:view-controller path="/" view-name="index" />

上述配置将会匹配上访问应用程序的根路径,如:http://localhost:8080/,当用户在浏览器中访问该根路径时,就会直接渲染名为 index 的视图

(2)、mvc:annotation-driven/

如果在springmvc.xml文件中配置了 <mvc:view-controller>,就需要同时在springmvc.xml文件中添加如下配置:

<mvc:annotation-driven/>

该配置的作用是启用Spring MVC的注解,因为使用mvc:view-controller后原先的注解就会失效,Controller就无法访问到,访问之前的Controller会发生 404 问题

【示例】

springmvc.xml配置文件中添加如下配置

	<!--配置视图控制器-->
    <mvc:view-controller path="/test" view-name="test"/>

    <!--开启注解驱动-->
    <mvc:annotation-driven/>

启动服务访问http://localhost:8080/springmvc/test

在这里插入图片描述

注释掉"mvc:annotation-driven/"再次访问http://localhost:8080/springmvc/test

在这里插入图片描述

但是访问原先的页面,比如访问首页http://localhost:8080/springmvc/

在这里插入图片描述

6、访问静态资源

一个项目可能会包含大量的静态资源,比如:css、js、images等

由于我们DispatcherServlet的url-pattern配置的是"/“,这个”/"代表的是除jsp请求之外的所有请求,也就是说访问应用中的静态资源,也会走DispatcherServlet,这会导致404错误,无法访问静态资源

解决方案有两种

  • 使用默认Servlet 处理静态资源
  • 使用 mvc:resources 标签配置静态资源处理

这两种方式都可以,自行选择

(1)、使用默认Servlet处理

首先需要在springmvc.xml文件中添加以下配置开启 默认Servlet处理静态资源 功能

    <!-- 开启注解驱动 -->
    <mvc:annotation-driven />

    <!--开启默认Servlet处理-->
    <mvc:default-servlet-handler/>

然后在web.xml文件中指定什么样的路径走其他Servlet

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

以上配置url-pattern使用的也是"/",和DispatcherServlet一样。表示的含义是:同一个请求路径先走DispatcherServlet,如果找不到则走默认的Servlet

默认的 Servlet 类中的代码已经由 Tomcat 服务器提供了实现,一般不需要开发者自己编写

在上面的示例中指定了 org.apache.catalina.servlets.DefaultServlet,则 Tomcat 服务器会自动将请求转发给该类处理

在处理时该类会根据请求的 URL 去查询 Web 应用的静态资源(如 HTML、CSS、JavaScript 和图片等),并将其返回给用户
告诉大家一个好消息,以上在web.xml文件中的配置也可以省略了,因为在Tomcat服务器中已经为我们提前配置好了,在CATALINA_HOME/conf/web.xml文件中

在这里插入图片描述

在这里插入图片描述

因此只需要在springmvc.xml文件中启用这个默认的Servlet和启用注解驱动即可

    <!-- 开启注解驱动 -->
    <mvc:annotation-driven />

    <!--开启默认Servlet处理-->
    <mvc:default-servlet-handler/>

访问http://localhost:8080/springmvc/static/img/java.jpeg

在这里插入图片描述

(2)、使用mvc:resources 标签

访问静态资源,也可以在springmvc.xml文件中添加如下的配置

<!-- 开启注解驱动 -->
<mvc:annotation-driven />

<!-- 配置静态资源处理 -->
<mvc:resources mapping="/static/**" location="/static/" />

表示凡是请求路径是"/static/“开始的,都会去”/static/"目录下找该资源
注意:要想使用 <mvc:resources> 配置,必须开启注解驱动 <mvc:annotation-driven />

测试访问http://localhost:8080/springmvc/static/img/java.jpeg

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐