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的執行原理,說難不難,說易不易,我們還是要多通過圖解和文字,並結合相關代碼反覆對應記憶,這樣我們才能真正做到知其然不知其所以然。

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