從SpringBoot到SpringMVC

CodeSheep發表於2019-02-19

概述

用久了SpringBoot,深受其約定大於配置的便利性 “毒害” 之後,我想回歸到SpringMVC時代,看看SpringMVC開發模式中使用者是如何參與的。本文就來體驗一下SpringMVC時代開發的流程。

注: 本文首發於 My 公眾號 CodeSheep ,可 長按掃描 下面的 小心心 來訂閱 ↓ ↓ ↓

CodeSheep · 程式羊

SpringMVC架構模式

SpringMVC請求處理流程

一個典型的SpringMVC請求流程如圖所示,詳細分為12個步驟:

  1. 使用者發起請求,由前端控制器DispatcherServlet處理
  2. 前端控制器通過處理器對映器查詢hander,可以根據XML或者註解去找
  3. 處理器對映器返回執行鏈
  4. 前端控制器請求處理器介面卡來執行hander
  5. 處理器介面卡來執行handler
  6. 處理業務完成後,會給處理器介面卡返回ModeAndView物件,其中有檢視名稱,模型資料
  7. 處理器介面卡將檢視名稱和模型資料返回到前端控制器
  8. 前端控制器通過檢視解析器來對檢視進行解析
  9. 檢視解析器返回真正的檢視給前端控制器
  10. 前端控制器通過返回的檢視和資料進行渲染
  11. 返回渲染完成的檢視
  12. 將最終的檢視返回給使用者,產生響應

整個過程清晰明瞭,下面我們將結合實際實驗來理解這整個過程。


SpringMVC專案搭建

實驗環境如下:

  • IntelliJ IDEA 2018.1 (Ultimate Edition)
  • SpringMVC 4.3.9.RELEASE
  • Maven 3.3.9

這裡我是用IDEA來搭建的基於Maven的SpringMVC專案,搭建過程不再贅述,各種點選並且下一步,最終建立好的專案架構如下:

基於Maven的SpringMVC專案

新增前端控制器配置

使用了SpringMVC,則所有的請求都應該交由SpingMVC來管理,即要將所有符合條件的請求攔截到SpringMVC的專有Servlet上。

為此我們需要在 web.xml 中新增SpringMVC的前端控制器DispatcherServlet:

    <!--springmvc前端控制器-->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:mvc-dispatcher.xml</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
複製程式碼

該配置說明所有符合.action的url,都交由mvc-dispatcher這個Servlet來進行處理


編寫SpringMVC核心XML配置檔案

從上一步的配置可以看到,我們定義的mvc-dispatcher Servlet依賴於配置檔案 mvc-dispatcher.xml,在本步驟中我們需要在其中新增三個方面的配置

  • 0x01. 新增處理器對映器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
複製程式碼

SpringMVC的處理器對映器有多種,這裡的使用的BeanNameUrlHandlerMapping其對映規則是將bean的name作為url進行處理

  • 0x02. 新增處理器介面卡
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
複製程式碼

SpringMVC的處理器介面卡也有多種,這裡的使用的SimpleControllerHandlerAdapter是Controller實現類的介面卡類,其本質是執行Controller中的handleRequest方法。

  • 0x03. 新增試圖解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
複製程式碼

這裡配置了InternalResourceViewResolver檢視解析器後,其會根據controller方法執行之後返回的ModelAndView中的檢視的具體位置,來載入對應的介面並繫結資料


編寫控制器

這裡模擬的是一個列印學生名單的Service,我們編寫的控制器需要將查詢到的學生名單資料通過ModelAndView渲染到指定的JSP頁面中

public class TestController implements Controller {

    private StudentService studentService = new StudentService();

    @Override
    public ModelAndView handleRequest( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        List<Student> studentList = studentService.queryStudents();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("studentList",studentList);
        modelAndView.setViewName("/WEB-INF/views/studentList.jsp");
        return modelAndView;
    }
}

class StudentService {
    public List<Student> queryStudents() {
        List<Student> studentList = new ArrayList<Student>();

        Student hansonwang = new Student();
        hansonwang.setName("hansonwang99");
        hansonwang.setID("123456");

        Student codesheep = new Student();
        codesheep.setName("codesheep");
        codesheep.setID("654321");

        studentList.add(hansonwang);
        studentList.add(codesheep);

        return studentList;
    }
}
複製程式碼

編寫檢視檔案

這裡的檢視檔案是一個jsp檔案,路徑為:/WEB-INF/views/studentList.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>學生名單</title>
</head>
<body>
    <h3>學生列表</h3>
    <table width="300px;" border=1>
        <tr>
            <td>姓名</td>
            <td>學號</td>
        </tr>
        <c:forEach items="${studentList}" var="student" >
            <tr>
                <td>${student.name}</td>
                <td>${student.ID}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>
複製程式碼

結合本步驟和上一步驟,檢視和控制器都已編寫完成,由於我們之前配置的處理器對映器為:BeanNameUrlHandlerMapping,因此接下來我們還需要在mvc-dispatcher.xml檔案中配置一個可被url對映的controller的bean,供處理器對映器BeanNameUrlHandlerMapping查詢:

<bean name="/test.action" class="cn.codesheep.controller.TestController" />
複製程式碼

實驗測試

啟動Tomcat伺服器,然後瀏覽器輸入:

http://localhost:8080/test.action
複製程式碼
實驗結果

資料渲染OK。

備註:當然本文所使用的全是非註解的配置方法,即需要在XML中進行配置並且需要遵循各種實現原則。而更加通用、主流的基於註解的配置方法將在後續文章中詳述。

呼,長舒一口氣,這麼個小Demo用SpringMVC完成的話,各種XML配置了半天,真麻煩啊,算了,還是回SpringBoot好了!


後記

作者更多的SpringBt實踐文章在此:


如果有興趣,也可以抽點時間看看作者一些關於容器化、微服務化方面的文章:


CodeSheep · 程式羊

相關文章