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. HandlerAdapter 将 ModelAndView 返回给 DispatcherServlet 。

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

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

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

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

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

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

2. DispatcherServlet

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

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

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

  • Controller 接受请求并根据使用的 GET 或 POST 方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给 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 中设置的属性。可以在视图中显示多个属性。

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

相关推荐
代码什么用5 小时前
Spring基础使用
java·后端·spring
代码什么用5 小时前
Spring对IoC的实现
数据库·spring
Su米苏5 小时前
Spring AI 中MCP 与普通 @Tool的区别
java·人工智能·spring
java资料站8 小时前
二、Spring AI Alibaba · ChatModel
java·windows·spring
java资料站9 小时前
五、Spring AI Alibaba · Memory · Saver(短期会话)
java·spring·microsoft
bst@微胖子14 小时前
Spring AI (5) : MCP 深度实战:从工具抽取到鉴权,SSE 与 STDIO
人工智能·spring·dubbo
Nebula_g14 小时前
JavaSE拓展:工具类Executors
java·开发语言·后端·spring·基础·javase
鱼宵14 小时前
Spring AI 可观测与透明化:traceId 串起全链路,思考过程实时直播给用户
java·人工智能·spring·链路追踪·springai
Raas10014 小时前
AI网关能做语义缓存吗?MAI Gateway(魔芋企业级AI网关)实战能力深度解读
java·后端·spring
天空鸟_时光不老15 小时前
13-亮点提炼:把技术说辞翻译成业务价值
java·spring boot·spring·spring cloud·mybatis