SpringMVC基础之工作流程

文章目录

  • [SpringMVC 的工作流程](#SpringMVC 的工作流程)
    • [1. 总图](#1. 总图)
    • [2. DispatcherServlet](#2. DispatcherServlet)
    • [3. 必需的配置](#3. 必需的配置)
    • [4. 加载配置文件的两个时机](#4. 加载配置文件的两个时机)
    • [5. 定义控制器](#5. 定义控制器)
    • [6. 创建 JSP 视图](#6. 创建 JSP 视图)

SpringMVC 的工作流程

1. 总图

如上图,Spring MVC 程序的完整执行流程如下:

  1. 用户通过浏览器发送请求,请求会被 Spring MVC 的『前端控制器』DispatcherServlet 接收。

  2. DispatcherServlet 拦截到请求后,会调用『处理器映射器』HandlerMapping

  3. 『处理器映射器』根据请求 URL 找到具体的『处理器』Handler ,生成『处理器』对象(如果有,还会生成拦截器对象)并返回给 DispatcherServlet

  4. DispatcherServlet 根据返回信息(Handler)选择合适的『处理器适配器』HandlerAdapter

  5. HandlerAdapter 会调用并指定 Handler 。此处和上述所说的处理器 Handler ,就是我们所编写的 Controller 类。

  6. Controller 执行完成后,会返回一个 ModelAndView 对象,该对象中会包含『视图名』和『模型对象』。

  7. HandlerAdapterModelAndView 返回给 DispatcherServlet

  8. DispatcherServlet 会根据返回信息(ModelAndView)选择一个合适的『视图解析器』ViewResolver

  9. 视图解析器 ViewResolver 解析视图后,会向 DispatcherServlet 返回具体的 View 对象。

  10. DispatcherServletView 进行渲染。即,将『模型数据』填充至『视图』中。

  11. DispatcherServlet 将渲染后的结果返回、发送给客户端浏览器。

在上述执行过程中,DispatcherServletHandlerMappingHandlerAdapterViewResolver 对象的工作都是在框架内部执行的,开发人员并不需要关心这些对象内部实现过程。

和程序员有关的内容只有 Handler (即,代码中的 Controller),和 ModelAndView 对象。

2. DispatcherServlet

Spring Web 的『模型 - 视图 - 控制器 』(MVC)框架是围绕 DispatcherServlet 设计的,它处理所有的 HTTP 请求和响应。

以下是对应于到 DispatcherServlet 的传入 HTTP 请求的事件顺序:

  • 在接收到 HTTP 请求后,DispatcherServlet 会查询 HandlerMapping ,并通过 Adapter 调用相应的 Controller

  • Controller 接受请求并根据使用的 GETPOST 方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给 DispatcherServlet

  • DispatcherServlet 将从 ViewResolver 获取请求的定义视图。当视图完成,DispatcherServlet 将模型数据传递到最终的视图,并在浏览器上呈现。

3. 必需的配置

需要通过使用 web.xml 文件中的 URL 映射来映射希望 DispatcherServlet 处理的请求。

xml 复制代码
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
        http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">

    ...

    <!-- 配置 SpringMVC 前端控制器 -->
    <servlet>
        <servlet-name>HelloWeb</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        ...
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloWeb</servlet-name>
        <url-pattern>*.do</url-pattern> <!-- 后缀拦截 -->
    </servlet-mapping>

</web-app>

4. 加载配置文件的两个时机

SpringMVC 有两次加载 Spring 配置文件的时机:

首先在 SpringMVC 项目启动时,会依据 web.xml 配置文件中所配置的监听器:ContextLoaderListener 去加载对应位置下的 Spring 配置文件。

  • Spring 配置文件版:web.xml

    xml 复制代码
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring-dao.xml,
            classpath:spring-service.xml
        </param-value>
    </context-param>
    
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
  • Spring 代码配置版:web.xml

    xml 复制代码
    <context-param>
        <param-name>contextClass</param-name>
        <param-value> <!-- 相较于 XML 配置,Java 代码配置『多』一个这个 -->
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            com.example.config.SpringServiceConfig,
            com.example.config.SpringDaoConfig
        </param-value>
    </context-param>
    
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

无论你有没有利用第一次加载时机(配置 ContextLoadListener),那么 Spring MVC 都会继续进入第二个加载配置文件时机:根据 DispatcherServlet 的初始化配置(<init-param>)加载对应位置的 Spring 配置。

  • Spring 配置文件版:web.xml

    xml 复制代码
    <servlet>
        <servlet-name>sampleServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-web.xml</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
        ...
    </servlet-mapping>
  • Spring 代码配置版:web.xml

    xml 复制代码
    <servlet>
        <servlet-name>sampleServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param><!-- 相较于 XML 配置,Java 代码配置『多』一个这个 -->
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.example.config.SpringWebConfig</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
        ...
    </servlet-mapping>

如果是 XML 配置文件,这里的 Spring 配置文件的路径如果是以 classpath: 开始,则表示配置文件是在 classpath 路径下。否则,就是在项目的工程根目录(webapp)>下。

SpringMVC 首先加载的是 <context-param> 配置的内容,而并不会去初始化 servlet。只有进行了网站的跳转,经过了 DispatcherServlet 的导航的时候,才会初始化 Servlet,从而加载 <init-param> 中的内容。

一般而言,

  • <context-param> 配置的 Spring 配置文件,习惯性叫 applicationContext ,或 webApplicationContext ,表示全局性 Spring 配置。

  • <init-param> 配置的 Spring 配置文件可以叫 SpringWebApplicationContext ,表示 spirng-webmvc(web 层)相关的 Spring 配置。

现在来看看 SpringWebConfig.java 文件的必需配置:

java 复制代码
@Configuration
@EnableWebMvc
@ComponentScan("com.example.inlet.controllers")
public class SpringWebConfig implements WebMvcConfigurer {
    ...
}

Spring MVC 配置类的关键,除了实现 WebMvcConfigurer 接口之外,还有就是需要标注 @EnableWebMvc 注解。

因为 @EnableWebMvc 注解的存在,Spring MVC 会自动创建、激活使用 19 个 Bean,这 19 个 Bean 在各个场景、环境中默默地支持着 Spring MVC 框架的的工作。

当然,如果也可以不使用 @EnableWebMvc 注解,这样的话,你需要直接(或间接地)去声明这 19 个 Bean(或其等价的替代品)。否则,Spring MVC 就不会以你想当然地方式运行。

另外,你也无须担心这默认的 19 个 Bean 是否符合你的需求,在合适的常见中,当你觉得其中的某个所提供的功能并非你所需要,你可以自定义 Bean 去覆盖、替代它(们)。

5. 定义控制器

DispatcherServlet 将请求委派给控制器以执行特定于其的功能。 @Controller 注释指示特定类充当控制器的角色。@RequestMapping 注释用于将 URL 映射到整个类或特定处理程序方法。

java 复制代码
@Controller
public class HelloController {

  @RequestMapping(value="/hello", method=RequestMethod.GET)
  public ModelAndView printHello() {
    ModelAndView mav = new ModelAndView();
    mav.addObject("message", "Hello Spring MVC Framework!");
    mav.setViewName("/WEB-INF/jsp/hello.jsp");
    return mav;
  }
}

@Controller 注释将类定义为 Spring MVC 控制器。

@RequestMapping 的第一个用法表示此控制器上的所有处理方法都与 /hello 路径相关。

@RequestMapping(method = RequestMethod.GET) 用于声明 printHello 方法作为控制器的默认服务方法来处理 HTTP GET 请求。可以定义另一个方法来处理同一 URL 的任何 POST 请求。

value 属性指示处理程序方法映射到的 URL,method 属性定义处理 HTTP GET 请求的服务方法。关于以上定义的控制器,需要注意以下几点:

  • 在服务方法中定义所需的业务逻辑。可以根据需要在此方法内调用其他方法。

  • 基于定义的业务逻辑,将在此方法中创建一个模型。可以设置不同的模型属性,这些属性将被视图访问以呈现最终结果。此示例创建且有属性 message 的模型。

  • 定义的服务方法可以返回一个 String,它包含要用于渲染模型的视图的名称。此示例将 "hello" 返回为逻辑视图名称。

6. 创建 JSP 视图

xml 复制代码
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

Spring MVC 支持许多类型的视图用于不同的表示技术。包括 JSP,HTML,PDF,Excel 工作表,XML,Velocity 模板,XSLT,JSON,Atom 和 RSS 源,JasperReports 等。这里使用的是 JSP 模板,并在 /WEB-INF/hello/hello.jsp 中写一个简单的 hello 视图:

xml 复制代码
<html>
    <head>
        <title>Hello Spring MVC</title>
    </head>
    <body>
        <h2>${message}</h2>
    </body>
</html>

这里 ${message} 是在 Controller 中设置的属性。可以在视图中显示多个属性。

另一张图,表达了同样的逻辑:

相关推荐
ExiFengs28 分钟前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring
瓜牛_gn1 小时前
依赖注入注解
java·后端·spring
一元咖啡2 小时前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway
java亮小白19973 小时前
Spring循环依赖如何解决的?
java·后端·spring
苏-言4 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
草莓base4 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
冰帝海岸11 小时前
01-spring security认证笔记
java·笔记·spring
没书读了12 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
代码小鑫15 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖15 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring