主頁 > 軟體設計 > SpringBoot請求映射原始碼分析(沒看過原始碼的小白也能懂,比針尖還細)

SpringBoot請求映射原始碼分析(沒看過原始碼的小白也能懂,比針尖還細)

2021-01-17 10:20:27 軟體設計

文章目錄

    • 一.前言
      • 1.Rest風格的請求
      • 2.表單如何發出delete和put請求
      • 3.完整代碼示例:
    • 二.原始碼分析
      • 1.HiddenHttpMethodFilter類中的doFilterInternal方法
      • 2.一步步分析原始碼:
        • 1.第一行代碼
        • 2.第二行代碼
        • 3.第三行代碼
        • 4.第四行代碼
        • 5.第五行代碼
        • 6.第六行代碼
        • 7.第七行代碼
        • 8.第八行代碼

一.前言

1.Rest風格的請求

我們現在一般喜歡用Rest風格的請求,即使用HTTP請求方式動詞來表示對資源的操作,
舉個例子:

  • 比如我們以前對學生資訊進行相關的增刪改查操作,定義的url路徑可能是這樣的:
    • /getStudent 獲取學生資訊
    • /deleteStudent 洗掉學生資訊
    • /editStudent 修改學生資訊
    • /savaStudent 保存學生資訊
      如果這個專案比較大,我們的路徑起名字都感覺很麻煩,
  • 現在我們用Rest風格這樣做:
    • 所有對學生的操作都叫/Student,如何表示對學生的增刪改查呢,使用HTTP請求方式動詞來表示對資源的操作,
    • GET 方式請求表示獲取學生資訊
    • DELETE 方式請求表示洗掉學生資訊
    • PUT 方式請求表示修改學生資訊
    • POST 方式請求表示保存學生資訊
      利用這些不同的請求方式動詞來區分不同的請求,

2.表單如何發出delete和put請求

我們以前用SpringMVC來完成這些事情,我們需要配置一個叫HiddenHttpMethodFilter的Filter;
我們來到WebMvcAutoConfiguration中,可以看到它已經配置了一個HiddenHttpMethodFilter,如下:
在這里插入圖片描述

也就是說默認我們的rest功能是可以用的,但是它通過@ConditionalOnProperty設定配置屬性前綴spring.mvc.hiddenmethod.filter的配置屬性名字enabled默認為false,來默認該功能是不開啟的,我們在組態檔中手動開啟它:

spring:
  mvc:
    hiddenmethod:
      filter:
        enabled: true #選擇性開啟

為什么要配置HiddenHttpMethodFilter呢,因為我們的表單提交的請求方式中只支持GETPOST方式的請求,它不支持DELETEPUT 方式的請求,如下:

我們的表單的method只有兩個選項,get和post:
在這里插入圖片描述
那我們如何用表單發出delete和put請求呢? 我們可以這樣做(為什么這樣做我們之后在原始碼分析中會講到),method還是等于post請求方式,但是添加了一個name="_method"value="DELETE"或者value="put"的input標簽(value中的delete或者put大小寫都可以,之后我們在講解原始碼的程序中會看到SpringBoot會自動把其值全部變成大寫),并且我們把這個input標簽隱藏起來,如下:
在這里插入圖片描述
這里先說一下為什么name="_method",這已經在HiddenHttpMethodFilter類中寫好了,如下:
在這里插入圖片描述
我們也可以呼叫setMethodParam設定它的值,如下:
在這里插入圖片描述
自己新建一個配置類,用@Bean注入物件到容器中,在該方法回傳物件前,呼叫setMethodParam來設定methodParam(也就是name)的值,如下:(這里只是做一個演示,下文的所有代碼中沒有該配置類)

在這里插入圖片描述

3.完整代碼示例:

Controller如下:

@RestController
public class HelloController {
    
//    @RequestMapping(value = "/student",method = RequestMethod.GET)
    @GetMapping("/student")
    public String getUser(){
        return "`GET` 方式請求表示獲取學生資訊";
    }

//    @RequestMapping(path = "/student",method = RequestMethod.POST)
    @PostMapping("/student")
    public String saveUser(){
        return "`POST` 方式請求表示保存學生資訊";
    }

//    @RequestMapping(value = "/student",method = RequestMethod.PUT)
    @PutMapping("/student")
    public String putUser(){
        return "`PUT` 方式請求表示修改學生資訊";
    }

//    @RequestMapping(value = "/student",method = RequestMethod.DELETE)
    @DeleteMapping("/student")
    public String deleteUser(){
        return "`DELETE` 方式請求表示洗掉學生資訊";
    }
}

index.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<h1>SpringBoot Web ,歡迎您!</h1>
測驗REST風格:
<!--method為空默認為get方式請求-->
<form action="/student" method="">
    <input value="GET請求" type="submit">
</form>
<form action="/student" method="post">
    <input value="POST請求"  type="submit">
</form>
<form action="/student" method="post">
    <input name="_method" value="DELETE" type="hidden">
    <input value="DELETE請求" type="submit">
</form>
<form action="/student" method="post">
    <input name="_method" value="put" type="hidden">
    <input value="PUT請求" type="submit">
</form>
<hr>
</body>
</html>

歡迎頁面:
在這里插入圖片描述

點擊測驗get請求:
在這里插入圖片描述

點擊測驗post請求:
在這里插入圖片描述

點擊測驗delete請求:
在這里插入圖片描述

點擊測驗put請求:
在這里插入圖片描述
可以看到這四種方式的請求我們都可以獲取并訪問到,那么底層原始碼是怎么寫的呢,接下來我將具體講解原始碼所做的一些事情,

二.原始碼分析

1.HiddenHttpMethodFilter類中的doFilterInternal方法

上述提到的hiddenHttpMethodFilter()方法中回傳了OrderedHiddenHttpMethodFilter類的物件,把OrderedHiddenHttpMethodFilter物件注冊到容器中:
在這里插入圖片描述
而OrderedHiddenHttpMethodFilter類有繼承了HiddenHttpMethodFilter類:
在這里插入圖片描述
現在我們只需要來看HiddenHttpMethodFilter類了,而HiddenHttpMethodFilter類中的doFilterInternal方法是處理上述程序的主要方法體,我們給doFilterInternal方法打上斷點,如下:
在這里插入圖片描述

2.一步步分析原始碼:

啟動debug來除錯程式,接下來我們來一步步分析:
首先我們訪問我們的歡迎頁面:在這里插入圖片描述
點擊put請求,表單提交會帶上name = value的資訊, 在我們的put表單中,name="_method" value=“put”,如下:
在這里插入圖片描述

所以表單提交時會帶上_method=put的資訊,

1.第一行代碼

表單提交后請求會被HiddenHttpMethodFilter攔截,來到了doFilterInternal方法中,首先拿到我們的原生請求request,把它賦值給一個區域變數requestToUse,如下:
第一行代碼:
在這里插入圖片描述

2.第二行代碼

然后進入if條件判斷中,判斷我們的原生request請求方式是不是POST方式(也就是我們form表單的method屬性是不是post方式)和判斷當前請求是否沒有錯誤,如下:

剛才我們寫的form表單:

在這里插入圖片描述
第二行代碼:
在這里插入圖片描述
因為我們點擊的是put,它的method屬性是post,然后也沒有什么錯誤,我們滿足條件,進入if陳述句體中,

3.第三行代碼

然后呢,接下來它呼叫request.getParameter方法獲取請求引數并把它賦值給區域變數paramValue:
第三行代碼:
在這里插入圖片描述
其中request.getParameter實參的this.methodParam是什么呢?我們點進去看一下,如下:

在這里插入圖片描述

它就是_method字符,這也就解釋了為什么之前我們要在form表單中再添加一個input標簽,其name值為_method,request.getParameter(_method)就或許到了其value值,因為我們剛才點擊put請求,表單提交會帶上name = value的資訊, 在我們的put表單中,name="_method" value=“put”,所以區域變數paramValue得到的值為value的值,為put,

4.第四行代碼

接著往下走,我們來到第四行代碼,這里又是一個if陳述句判斷,StringUtils.hasLength(paramValue)方法它判斷的是字串是否為null或者為為空,顯然我們的paramValue不為null也不為空,為put,滿足if判斷條件,
StringUtils.hasLength方法:
在這里插入圖片描述
第四行代碼:
在這里插入圖片描述

5.第五行代碼

接著往下走,我們的第五行代碼是把我們的paramValue區域變數變成大寫,也就是把put變成大寫的PUT,然后賦值給新的區域變數method,如下:
第五行代碼:
在這里插入圖片描述

6.第六行代碼

又到了if陳述句判斷的地方,這里判斷我們的區域變數method(也就是PUT)是否包含在ALLOWED_METHODS這個List集合中,為什么ALLOWED_METHODS是一個集合呢?我們點進去看一下就知道了:
在這里插入圖片描述
它是這么一個集合,它里面有PUT、DELETE、和PATCH,它們都是列舉型別,我們分別點進去看一下:
在這里插入圖片描述
它們的name方法是得到其名稱,也就是同名的字串,也就得到了PUT,DELETE和PATCH字串,
我們的區域變數method(也就是PUT)在其中,if陳述句為true,
第六行代碼:
在這里插入圖片描述

7.第七行代碼

繼續往下走,接下來遇到了一個new HttpMethodRequestWrapper新建了一個物件來取代原來的原生request,我們點進這個HttpMethodRequestWrapper中看一下:
在這里插入圖片描述
我們發現這個HttpMethodRequestWrapper繼承了HttpServletRequestWrapper,我們點進HttpServletRequestWrapper看一下:
在這里插入圖片描述
發現這個HttpServletRequestWrapper最侄訓是實作了HttpServletRequest,所以呢HttpServletRequestWrapper的子類HttpMethodRequestWrapper他還是一個HttpServletRequest請求,
現在我們回到HttpMethodRequestWrapper類中,具體看其類內部是怎么回事:
我們呼叫了HttpMethodRequestWrapper的構造器,傳遞了兩個引數分別是原生的request請求和method(也就是PUT)請求方式,在構造器中我們把請求方式method賦值給類的屬性method,如下:
在這里插入圖片描述
然后重寫了父類的getMethod方法,回傳我們剛剛賦值的method(也就是PUT ),
呼叫了構造器之后把其創建的物件賦值給了區域變數requestToUse,當我們呼叫requestToUse的getMethod方法時,我們回傳的就是PUT了,這個地方使用了一個包裝設計模式,很巧妙,
第七行代碼:
在這里插入圖片描述

8.第八行代碼

呼叫filter過濾器filterchain的dofilter方法,將把自身接收到的請求request物件和response物件和自身物件即filterchain作為下一個過濾器的dofilter的形參傳遞過去,這樣才能使得過濾器傳遞下去,但是這里的request物件是requestToUse,也就是我們剛剛重寫了getMethod方法的requestToUse,當呼叫getMethod的方法時回傳的是PUT,
第八行代碼:
在這里插入圖片描述

dubug放行后運行結果:
在這里插入圖片描述
上述我們都說的是表單提交的方式發送請求,
如果是客戶端直接發送請求,我們的請求方式可以直接是PUT、DELETE等方式,如果不是POST請求它會只運行第一行代碼和第八行代碼,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/249787.html

標籤:其他

上一篇:MyBatis-Plus快速入門-(干貨滿滿+超詳細)

下一篇:關于one-hot編碼

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more