SpringMVC ----- SpringMVC的执行原理

前言

Spring强大的自动配置功能帮我们简化了很多开发的步骤,这是我们能快速上手一个复杂的项目,但是我们对于背后的原理确是一知半解,今天我们对MVC的执行流程进行说明。

1. SpringMVC的执行原理

说真的,着手写这篇文章的时候,我很纠结,因为感觉无论以何种方式入手都很难说明白这个流程;这里我尝试先使用图解,文字说明后,通过一段代码加深图形和文字的理解。
这是官方对于MVC流程的图解说明:
在这里插入图片描述

  1. 用户通过输入网址发送请求到前端控制器 DispatcherServlet
  2. 前端控制器把用户的请求委托给页面的控制器Controller层(这里的底层通过处理器映射HandlerMapping和处理器适配器HandlerAdapter 找到合适的控制层进行匹配)
    3,4. 页面控制器 Controller 通过调用service,dao层的相关业务后,把数据和视图封装成为一个模型视图对象(ModelVIew)并返回
  3. 页面控制器 (Controller层) 把 模型视图对象 (ModelAndView) 返回给前端控制器 (DispatcherServlet)
  4. 前端控制器 (DispatcherServlet) 进行相关的视图渲染后,把页面返回给用户并产生相应的响应。

这里我们再以我最喜欢的一个up 主狂神的图解再讲解一次它底层的实现
在这里插入图片描述
在开发中,上图的实线是Spring底层帮我们实现的,虚线才是我们需要完成的配置。
1 DispatcherServlet 表示的是前端控制器,是整个SpringMVC的控制中心,用户发送请求,DispatcherServlet 接收请求并拦截请求
假设我们发送的url请求为 :http://localhost:8080/SpringMVC/hello。
这个url 请求可以拆分为三部分:
- http://localhost:8080 服务器域名
- SpringMVC部署在服务器上的web站点
- hello 表示控制器
- 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
2 HandlerMapping为处理器映射,被DispatcherServlet所调用,主要是为了根据url 找到相应的处理器 (Handler)
3 HandlerExcution表示处理的结果,这里指的是具体的Handler,根据1我们知找到的控制器名为 hello
4 HandlerExcution将解析后的信息传递给 DispatcherServlet (如解析控制的映射等)
5. HandlerAdapter表示处理适配器,这就是按特定的名字去找Controller层的相关class类
6. Controller 层去调用底层service,dao层的方法。
7. Controller层把数据和页面封装成一个模型视图对象(ModelAndView)返回给处理适配器(HandlerAdapter)
8. HandlerAdapter将视图的逻辑名或模型传递给DispatcherServlet
9. DispatcherServlet调用视图解析器 (ViewResolver)来解析逻辑视图名(即加上的前缀和后缀)
10. 视图解析器将解析的逻辑视图名传给DispatcherServlet
11. DispatcherServlet根据视图解析器解析视图结果,调用具体的视图
12. 最终把相关的前端页面呈现给用户

话说了一大堆,可大多数人还是很懵的,接下来通过一段代码对上面的图片和文字加深理解

2. SpringMVC的代码实现

说在前面,这段代码在我们开发中基本上不会使用,完全是为了契合上面的原理所写。
[1] 创建一个Maven项目(可以是导入web模块的也可以是普通项目 ps:普通项目后面有一个bug需要改)===>这里以普通项目进行讲解
[2] 在pom.xml导入依赖

   <!--依赖-->
    <dependencies>
        <!--junit的测试包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--springMVC的包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--servlet层的包-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <!--jsp的包-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
        </dependency>
        <!--jstl表达式的包-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

[3] 添加web.xml文件
由于是普通Maven项目,需要添加web框架的支持
在这里插入图片描述
这是我们后期编写完成后的目录结构
在这里插入图片描述
[4] 编写web.xml文件
1.这里的核心主要是配置我们的前端控制器DispatcherServlet(Spring底层已经帮我们比编写好了),它需要一个springMVC配置文件(springmvc-servlet.xml)的注入
2.在给这个控制器加映射的时候,我们一般使用的路径是 / 而不是 /* ,因为后者会处理 .jsp的请求,这样我们在调用视图解析器的时候。也会给jsp文件加上相应的前后缀,这样会产生映射错误。

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
         version="4.0">

    <!--1.注册DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--关联一个springmvc的配置文件 [servlet-name] -servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别:1-->
        <load-on-startup>1</load-on-startup>
    </servlet>


    <!-- / 匹配所有的请求,不包括 .jsp -->
    <!-- /* 匹配所有的请求,包括 .jsp -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

[3] 编写SpringMVC的配置文件
springmvc-servlet.xml
主要功能有三个:

  • 配置处理器映射器HandlerMapping (这里就是处理我们用户发送的url请求,去获取相应的控制器的名字)
  • 配置处理器适配器HandlerAdapter (这里既是把请求交给相应名字的控制器处理)
  • 配置视图解析器 ViewResolver
    作用:
    1.获取了ModelAndView的数据
    2.解析ModelAndView视图的名字
    3.拼接名字,找到对应的视图 /WEB-INF/jsp/hello.jsp
<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--处理器映射器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!--处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <!--视图解析器: DispatcherServlet给它的ModelAndView
        1.获取了ModelAndView的数据
        2.解析ModelAndView视图的名字
        3.拼接名字,找到对应的视图 /WEB-INF/jsp/hello.jsp
    -->
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

[4] 编写处理器(处理用户的url请求)
HelloController (这里是通过实现Controller接口来完成的,但我们开发中一般不这么使用,这里是为例把逻辑解释清楚)
作用:把视图和数据封装成ModelAndView对象(模型和视图),并返回给我们前端控制器DispatcherServlet,然后它在通过视图解析器完成相关页面的渲染,并返回给用户

package com.gs.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//注意:这里我们导入Controller接口
public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        //ModelAndView 模型和视图
        ModelAndView mv = new ModelAndView();

        //封装对象,就在ModelAndView中,Model
        mv.addObject("msg","HelloSpringMVC!");
        //封装要转发的视图,放在ModelAndView中
        mv.setViewName("hello");  // /WEB-INF/jsp/hello.jsp

        return mv;
    }
}

[5] 配置处理器
在springmvc-servlet.xml加上

<!--Handler-->
<bean id="/hello" class="com.gs.controller.HelloController"/>

这样我们编写完后,运行时是会报错的,主要是因为这个普通项目并没有导入我们的相关jar包,我们可以手动添加该目录(web项目就不会有这种错误)
在这里插入图片描述
这时访问:http://localhost:8080/hello
在这里插入图片描述

小结

SpringMVC的执行原理,说难不难,说易不易,我们还是要多通过图解和文字,并结合相关代码反复对应记忆,这样我们才能真正做到知其然不知其所以然。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章