Struts2工作原理(圖解)

加瓦一枚發表於2018-10-17

寫在前面:Struts2主要包含前端控制器FC、Action、ValueStack容器、Result、Interceptor攔截器、Tags標籤6個核心元件,本文主要介紹這幾個元件的合作關係,由此構成Struts2的工作流程,以便更好地理解和使用Struts2。

背景知識
1、Struts2基礎標籤
    1)用於輸出的標籤
        --*<s:property value="name"/>    value的值實際上是OGNL表示式
        --特殊用法
            <s:property />    用於輸出棧頂資料
    2)用於除錯的標籤
        <s:debug/>
        --該標籤僅僅是給程式設計師用的,用於除錯,即用於觀察ValueStack中的資料
        --當程式碼提交給測試、客戶時,要把該標籤刪除
        --該標籤具有互斥性(可以理解為BUG),如果頁面上出現多次這個標籤時,實際上只有第一個有效
    3)用於迴圈的標籤
        a、用於迴圈集合
            --比如Action中有集合屬性List<User> users
            <s:iterator value="users">
                <s:property value="userName"/>
            </s:iterator>
        b、用於迴圈數字
            <s:iterator begin="1" end="3" var="i">
                <s:property value="#i"/>
            </s:iterator>

2、OGNL表示式
    1)類似於EL表示式,但是比EL功能強大
    2)表示式允許我們通過一個字串,來訪問JAVA物件。從而避免了在JSP上巢狀著寫JAVA程式碼。即,表示式可以通過字串間接的幫助我們訪問JAVA物件。
    3)基本原理
        --OGNL表示式將被OGNL引擎解析,這個過程是Struts2自行完成的
        --OGNL引擎允許我們訪問兩種型別的物件,一種是JavaBean型別,稱之為root物件;另一種為Map型別,稱之為context物件。
        --當OGNL表示式以#開頭時,OGNL引擎會訪問context物件,否則會訪問root物件
    4)root物件
        --我們寫OGNL表示式時(不以#開頭的情況),首先要明確誰是root物件,其次從該物件的下級屬性寫起。
        舉例:
        --比如以Action為root物件,Action中有String name, User user屬性,那麼要在頁面顯示這兩個屬性的話,寫法如下:
            <s:property value="name"/>
            <s:property value="user.userName"/>
        --比如以User為root物件,要在頁面上顯示它的名稱,寫法如下:
            <s:property value="userName"/>
    5)context物件
        --OGNL表示式以#開頭,則訪問context物件
        --#後面寫的是context物件的key,context物件是Map型別

3、ValueStack
    1)什麼是ValueStack
        Struts2中並不是直接將OGNL元件搬過來使用,而是使用一個物件容器ValueStack對這個元件進行了改造及封裝,因此我們在Struts2中是通過ValueStack來使用OGNL表示式。並且ValueStack中封裝了Action的資料,上下文等資料,這些資料我們都可以通過OGNL表示式來獲得。
    2)原理
        --結構:ValueStack中封裝了OGNL引擎、context物件、Stack物件。
        --規則:當我們在標籤中寫一個OGNL表示式時,該表示式被Struts2自動的傳遞給ValueStack中的OGNL引擎,引擎會判斷表示式是否以#開頭,若是則直接從context物件中取值,否則向Stack中取值。
        --如何向Stack取值:OGNL表示式從棧頂向下依次取值,它是以棧的每一級物件作為root物件從中取值的,若取到值則直接返回,否則繼續向下取值,直到棧底為止。
    3)*棧頂的變化
        a、預設情況下,棧頂是Action
        *b、在迴圈時,棧頂將發生變化,規則如下:
            --在未迴圈時,棧頂依然是Action
            --在第一次迴圈時,Struts2將迴圈變數(如user)壓入到棧中,因此迴圈變數佔據棧頂位置,而Action處於棧的第二位。
            --在第n次迴圈時,Struts2將第n-1次的迴圈變數從棧頂移除,然後再將本次迴圈的變數壓入棧中,因此本次迴圈的變數佔據棧頂位置,而Action依然處於棧的第二位。
            --當最後一次迴圈結束時,Struts2將最後一次迴圈的變數從棧頂移除,而沒有新的變數壓入棧中,那麼Action再次成為棧頂。
            簡而言之:
                --在迴圈過程中,棧頂是迴圈變數
                --迴圈結束後,棧頂是Action
    4)*總結(OGNL,ValueStack)
        a、在沒有迴圈時,棧頂是Action,即可以以Action為root來寫OGNL表示式
        b、在迴圈時,棧頂是迴圈變數,棧第二位是Action
            --迴圈集合
                棧頂是集合中的物件,那麼可以以該物件為root,來寫OGNL表示式,即直接從該root物件的下級屬性寫起
                舉例:Action中有屬性List<User> users,在頁面上迴圈users
                <s:iterator value="users">
                    <s:property value="userName"/>
                </s:iterator>
                即:迴圈過程中,棧頂是User物件,以它為root來寫OGNL表示式的話,就寫userName
            --迴圈數字
                棧頂是迴圈變數(數字),但是由於我們不能以數字為root(以JavaBean為root)來寫OGNL表示式,因為數字已經是基本型別資料,沒有下級屬性讓我們訪問。如果我們想直接輸出棧頂可以用<s:property/>,如果我們想引用迴圈變數,則需要寫<s:property value="#i"/>,從context物件中依然可以取得這個值。
                舉例:從1迴圈到3
                <s:iterator begin="1" end="3" var="i">
                    <s:property value="#i"/>
                </s:iterator>

工作原理
總結8句話,方便記憶:
        請求提交控制器,根據配置找Action。建立VS棧容器,例項Action放棧頂。
        呼叫Action算輸出,歷經層層攔截器。根據方法返回值,呼叫Result做輸出。

詳細流程如下(結合圖示理解):
1、請求傳入前端控制器FC
2、前端控制器FC根據Struts.xml配置檔案查詢Action
3、建立ValueStack值棧容器
4、建立Action並存入ValueStack棧頂
5、6、7、FC呼叫並執行Action邏輯,此過程可能先被Interceptor攔截器攔截處理
8、9、FC根據Action返回的result通過Result元件跳轉到相應的JSP介面
10、在解析JSP時,若發現OGNL表示式,則向ValueStack容器中的OGNL引擎傳入表示式,按照先前介紹的方式查詢對應的值
11、OGNL引擎返回查詢到的值給JSP,待所有資料載入完成,呈現JSP(通過Tags標籤)介面

Tips:當重新提交請求(比如重新整理介面)時,Action、ValueStack均會被重新建立。


原文:https://blog.csdn.net/daijin888888/article/details/51461043?utm_source=copy 
 

相關文章