Struts2框架學習總結(從入門到精通)
文章目錄
- 一、Struts2入門
- 二、Struts2資料操作
- 結果頁面的配置
- 在action獲取表單提交的資料
- struts2提供獲取表單資料方式(減少了程式碼,替代了上面的方式例如:ServletActionContext)
- struts2獲取資料封裝到集合中
- 擴充套件-表示式封裝和模型驅動比較
- 案例-新增客戶功能
- 三、Struts2值棧
- OGNL概述
- OGNL入門案例
- 什麼是值棧
- 獲取值棧物件
- 值棧內部結構
- 向值棧放資料
- 從值棧獲取資料
- EL表示式獲取值棧資料(為什麼能取到)
- OGNL的#、%使用
- 案例-顯示所有資訊列表(用值棧來存資料,以前用的域物件)
- 四、Struts2攔截器(interceptor)
- 五、一些實用小細節
一、Struts2入門
struts2概述
- javaee三層中的web層
- 在struts1和webwork基礎上的全新的框架
- 解決一些問題
①當功能很多,會建立很多的servlet,那麼維護起來不方便,在javaweb階段我們是通過BaseServlet的的底層反射來實現的
- struts2版本
目前比較穩定的版本 - web層框架
①struts2
②springMVC
struts2入門案例
- 從lib目錄中匯入jar包,但是裡面可能上百個jar包,你可以從app目錄(裡面是一些案例,最好從blank案例中拿)中找到裡面的web-inf->lib下的jar包進行copy
關於jar包詳情可參考:https://blog.csdn.net/For_ZZHacker/article/details/85675995 - 建立action(這裡的action就相當於javaweb學的servlet)
① 每次訪問servlet的時候都會預設執行service方法(寫一個servlet:寫一個類的時候需要繼承httpservlet類,然後重寫裡面的方法(例如doget,dopost),然後再web.xml中配置訪問servlet的路徑)
② 每次訪問action的時候都會預設執行execute方法(同樣需要配置action的訪問路徑,見下一步)
- 配置action類的訪問路徑
① 建立struts2的核心配置檔案,該配置檔案的名稱和位置是固定的,跟hibernate的配置檔案一樣。位置在src下面,檔名稱叫struts.xml
② 引入dtd的約束
訪問路徑為:http://127.0.0.1:8080/專案名/hello.action
(action可加可不加,常用瀏覽器例如火狐,谷歌,IE沒問題,雜牌瀏覽器還是加上後面的action有可能會出錯)
注意:此時訪問會出現404問題,一個可能是伺服器啟動報異常了,另一個就是沒有配置過濾器!!! - 配置struts2的過濾器(在web.xml中配置)
(struts2已經幫我們封裝好了過濾器,我們只需要配置一下即可)
此時再去訪問就會訪問成功!!! - 小總結:通過一個案例我們知道了使用框架我們可以少些很多的程式碼,他給我們封裝了許多程式碼,但是我們需要去配置運用這些封裝好了的類。
另外:struts.xml裡面有許多的action,web.xml就定義了一個過濾器
struts2底層執行過程
-
幾個概念
過濾器是在啟動伺服器的時候建立的,servlet預設是在第一次訪問的時候建立的
框架的學習反射是重點!!!!
-
檢視過濾器原始碼
裡面有init方法,doFilter方法,destroy方法
①過濾器在伺服器啟動的時候就會執行,建立過濾器時候執行init方法
- init方法中載入struts2自帶的配置檔案和自己建立的配置檔案(struts.xml,web.xml)
- 現在再來看一下第二個載入的配置檔案是什麼
小總結:我們開發的時候只需要關心struts.xml,web.xml這兩個需要自己配的配置檔案即可
struts2相關配置
struts2的核心配置檔案struts.xml
最大的標籤是<struts>
裡面有3個常用標籤從大到小<package><action><results>
,以及裡面的屬性.
① package標籤
- 類似一個程式碼包,區別不同的action,要配置action,必須首先寫package標籤,在package標籤中才能配置action
- package標籤屬性
- name屬性:用來區分不同的package,隨便起名
- extends屬性:就是個繼承的意思
- namespace屬性:不寫預設也是“/”,最好寫上。
② action標籤
- action標籤主要配置action的訪問路徑
- action的標籤屬性
- name屬性:區分不同的action;package標籤中的namespace屬性和這裡的name屬性構成了訪問路徑
- class屬性:全路徑=包名+類名,通過反射的原理去執行該類的
- method屬性:
③ result標籤
- 根據你的action中的方法返回值,將頁面定位到指定的頁面或action上
- result標籤的屬性
- name屬性:和你方法的返回值要一樣
裡面的“/”代表的是當前專案的根目錄
- type屬性:
有4個值:dispatcher(預設),redirect,chain,redirectAction
dispatcher(預設)和redirect:result標籤中“/”代表的是專案根路徑,不寫就代表當前路徑下
chain和redirectAction:result標籤中“/”沒有任何意義,不需要寫,寫了就是多餘,也就是隻能從當前路徑去指定頁面!!!
chain:只能轉發到同一名稱空間下的Action
redirect:可以重定向到action中去,也可以重定向到顯示頁面中去
轉發後頁面變了,但是位址列並沒變,本質來講轉發就是同一個請求,重定向是又一次新的請求(相當於2次請求)
struts2常量配置
- struts2框架,幫我們實現一部分功能,struts2裡面有常量,在常量裡面封裝一部分功能。
- struts2預設的常量位置(記住)
- 修改struts2預設常量值
① 常用方法
該標籤寫<struts>
下面,和<package>
標籤同級
② 還有2種方式(瞭解)
- 常用常量
分模組開發
- 每個人自己的模組配置檔案單獨開發,最後合併引入到核心配置檔案中就行,這樣就不會將我們的核心配置檔案給弄亂了。
struts2的action建立
action的編寫方式
- action編寫的3種方式
- 建立類,實現Action介面方式(將一些常用的返回值定義為常量例如SUCCESS=“success”),不常用
- 建立類,繼承類ActionSupport,常用
當然也可以用那些常量,因為也實現了interface Action
struts2的action方法訪問(重點)
- 一共三種方式實現
第一種:使用action標籤的method屬性,在這個屬性裡面寫執行的action的方法,不寫預設執行execute()方法
第二種:使用萬用字元的方式實現
第三種:動態訪問實現(不用)
- 一個錯誤演示
- 一個action訪問不同方法的例子
- 普通方式
- 使用萬用字元的方式
- 又是一個struts2應用的案例
二、Struts2資料操作
結果頁面的配置
- 全域性結果頁面
使用global-results
標籤將result
標籤寫這裡面,global-results
標籤位於package
標籤裡面,此時action
標籤預設就有global-results
標籤中包含的result
標籤
- 區域性結果頁面
- result標籤type屬性
在action獲取表單提交的資料
- 使用ActionContext類獲取
- 一個例子來演示
- 建立表單,提交表單到action裡面
- 使用ServletActionContext類獲取
- 使用介面注入方式獲取(實現不同的介面,例如ServletRequestAware接口裡面有個方法可以設定出request物件)
讓action實現介面,為了得到request物件,需要新建一個成員變數來進行賦值的,然後在execute方法中才能使用
ware:器皿,物品—》容器
request用的多,session經典案例是用在登入的時候,context用的少
struts2提供獲取表單資料方式(減少了程式碼,替代了上面的方式例如:ServletActionContext)
原始的寫法獲取表單資料並封裝到實體類中(麻煩費勁,但是有效穩定)
- 屬性封裝(會用即可)
- 模型驅動封裝(重點)
- 表示式封裝(也可以認為是屬性封裝的特例,因為寫法原理一樣)
struts2獲取資料封裝到集合中
- 封裝到list集合
- 封裝到map集合
擴充套件-表示式封裝和模型驅動比較
相同點:都封裝到實體類中
不同點:模型驅動只能封裝到同一個實體類物件中,表示式封裝可以封裝到不同實體類中
案例-新增客戶功能
三、Struts2值棧
OGNL概述
- web階段用EL表示式在jsp頁面中來獲取域物件裡面的值
- ognl表示式比EL表示式功能更強大
(1)在struts2裡面操作值棧資料
(2)一般把ognl在struts2操作:和struts2標籤一起使用操作值棧
EL表示式,OGNL表示式(從表單獲取資料三種方式中的表示式方式(隸屬於屬性封裝方式))
html標籤,jstl標籤,struts2標籤
- OGNL不是struts2的一部分,單獨的專案,經常和struts2一起使用
(1)使用ognl時候首先匯入jar包,struts2提供了ognl的jar包
OGNL入門案例
什麼是值棧
獲取值棧物件
值棧內部結構
下圖中root部分是個棧,棧裡面有2個元素,因為沒有操作值棧,所以棧頂元素是當前值棧所在action的一個引用(為了方便操作的),當你往棧裡面放東西就會放到棧頂的位置上。
向值棧放資料
1 向值棧放資料多種方式
第一種 獲取值棧物件,呼叫值棧物件裡面的 set 方法
第二種 獲取值棧物件,呼叫值棧物件裡面的 push方法
第三種 在action定義變數,生成變數的get方法(好處是減少空間的分配了)
向值棧放物件
向值棧放list集合
從值棧獲取資料
1 使用struts2的標籤+ognl表示式獲取值棧資料
(1)<s:property value=”ognl表示式”/>
獲取字串
1 向值棧放字串
2 在jsp使用struts2標籤+ognl表示式獲取
獲取物件
獲取list集合
第三種方式使用struts2的iterator標籤類似於jstl的foreach標籤
想使用context裡面的資料需要加個“#”,將資料放到context這樣的操作目的是為了方便取值,不佔用root部分,提高效率
這裡注意一下application,其實就是ServletContext物件,記得這個applicatIon域中是共享的
foreach+EL表示式的方式(需要jstl.jar包和standard.jar,並且在開頭引入c標籤taglib uri是jstl/core)
其他操作
ognl的陣列獲取值的寫法先寫下標,再寫陣列名,中間有點號,值棧的棧頂就是0號位置,依次向下排,所有的都會放到這個top陣列,不是隻有push這種沒有key的。
注意:很多種寫法都用<s:property value="ognl表示式">
來獲取,實質上這個標籤是從棧頂先來尋找符合的值,找到就直接顯示,不管後面符合該表示式的值了。
EL表示式獲取值棧資料(為什麼能取到)
如果資料在值棧中雖然能取到,但是效能很低,因為有多餘操作,例如先去域物件中找等等。
先看例子:能夠取到值棧中的資料
先解釋一個詞wrap:包起來,穿外衣,纏繞—》本質就是增強的意思
原始碼裡面會有這個詞,以及wrapper可以理解為包裝器和增強器
EL表示式中就是對request進行了增強,本質就是對getAttubute進行了增強
看原始碼首先從struts2的過濾器中開始看-----》找到裡面有個doFilter方法—》再看到這個doFilter方法中的request被增強了使用wrapRequest(oldRequest)方法
最後這個選中的ActionContext.put,又將標誌值(看好了不是attribute,只是一個標誌而已)放到了值棧的第二部分context中去了,其實這個context中包含request物件的引用,Httpsession物件的引用,servletContext物件的引用等等(也因此可以用ognl表示式獲取到域物件中的資料),此時put進去就和這些域物件平起平坐了。
ActionContext.getContext.put(String,Object)是把物件放到了StackContext中,這個物件跟request,session等一樣,它們平起平坐,但這些都不是root物件(這些是context物件),所以要通過#訪問。
request.setAttribute(String,Object)就是把值放到request範圍,而StackConext裡含有request物件,所以可以通過#request.*來訪問。
OGNL的#、%使用
#使用
%使用
注意是表單標籤
上面這個圖就相當於html中的input標籤,所以一般不用ognl的表單標籤,因為效能低,不如直接用html的表單標籤
案例-顯示所有資訊列表(用值棧來存資料,以前用的域物件)
首先想到3種方式set,put,直接定義成員變數方式,第三種最常用
四、Struts2攔截器(interceptor)
攔截器的概述
- 攔截器是struts2裡面的概念
- struts2框架封裝的功能都是在攔截器裡面
- 在沒有自定義攔截器的情況下,每次執行action,預設只會執行預設的攔截器
下圖是常量的位置:
下圖是struts2裡面預設攔截器的位置:
這個檔案結構跟自己定義的struts.xml結構差不多
其中的package標籤名字就是struts-default,還定義了result-type,預設是dispatcher
這裡還指定了預設的攔截器棧
在這個檔案中<interceptors>
裡面定義了大量的<interceptor>
這些就是定義的攔截器,還有一些攔截器棧
下圖這些只是引用<interceptor-ref>
,真正的定義攔截器是在上面定義的
4. 攔截器的執行時間:
在action建立之後,執行action中的方法之前 ,執行的攔截器,可以通過在預設的隨便一個攔截器上打個斷點來驗證,會發現先到攔截器中的斷點,再到action中的具體方法中的斷點上
追蹤一個攔截器看一下(就拿這個模型驅動的攔截器來演示一下):
這裡是xml檔案,用ctrl+滑鼠左鍵不能連線到,先選中用ctrl+shift+t來找到該類
百度解釋攔截器:
一、概述:
java裡的攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的程式碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中攔截器用於在某個方法或欄位被訪問之前,進行攔截然後在之前或之後加入某些操作。
二、原理:
大部分時候,攔截器方法都是通過代理的方式來呼叫的。Struts 2的攔截器實現相對簡單。當請求到達Struts 2的ServletDispatcher時,Struts 2會查詢配置檔案,並根據其配置例項化相對的攔截器物件,然後串成一個列表(list),最後一個一個地呼叫列表中的攔截器。Struts2攔截器是可插拔的,攔截器是AOP的一種實現。Struts2攔截器棧就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或欄位時,Struts2攔截器鏈中的攔截器就會按其之前定義的順序被呼叫。
三、定義一個攔截器
自定義一個攔截器需要三步:
1 .自定義一個實現Interceptor介面(或者繼承自AbstractInterceptor)的類。
2 .在struts.xml中註冊上一步中定義的攔截器。
3 .在需要使用的Action中引用上述定義的攔截器,為了方便也可將攔截器定義為預設的攔截器,這樣在不加特殊宣告的情況下所有的Action都被這個攔截器攔截。
四、與過濾器的區別:
過濾器可以簡單理解為“取你所想取”,忽視掉那些你不想要的東西;攔截器可以簡單理解為“拒你所想拒”,關心你想要拒絕掉哪些東西,比如一個BBS論壇上攔截掉敏感詞彙。
1.攔截器是基於java反射機制的,而過濾器是基於函式回撥的。
2.攔截器不依賴於servlet容器,而過濾器依賴於servlet容器。
3.攔截器只對action起作用,而過濾器幾乎可以對所有請求起作用。
4.攔截器可以訪問action上下文、值棧裡的物件,而過濾器不能。
5.在action的生命週期裡,攔截器可以多起呼叫,而過濾器只能在容器初始化時呼叫一次。
攔截器底層原理
1 攔截器底層使用兩個原理
第一個 aop思想(aop的底層是動態代理)
(0)後面在spring裡面把aop做更深層次分析
(1)文字描述:
Aop是面向切面(方面)程式設計:有個基本功能,需要擴充套件功能,不通過修改原始碼方式擴充套件功能。
(2)畫圖分析:
第二個 責任鏈模式
(1)在java中有很多的設計模式,責任鏈模式是其中的一種
(2)責任鏈模式和過濾鏈很相似的
責任鏈模式:
要執行多個操作,有新增、修改、刪除三個操作。
首先執行新增操作,新增操作執行之後 做類似於放行操作,執行修改操作,修改操作執行之後做類似於放行操作,執行刪除操作
過濾鏈:一個請求可有多個過濾器進行過濾,每個過濾器只有做放行才能到下一個過濾器
2 aop思想和責任鏈模式如何應用到攔截器裡面?
(1)文字描述:
-
攔截器在action物件建立之後,action的方法執行之前執行
-
在action方法執行之前執行預設攔截器,執行過程使用aop思想,在action沒有直接呼叫攔截器的方法,使用配置檔案方式進行操作
-
在執行攔截器時候,執行很多的攔截器,這個過程使用責任鏈模式
– 假如執行三個攔截器,執行攔截器1,執行攔截器1之後做放行操作,執行攔截器2,執行攔截器2之後做放行,執行攔截器3,執行攔截器3之後放行,執行action的方法
(2)畫圖分析
3 檢視原始碼
原始碼主要步驟:
重要概念
1 過濾器和攔截器區別
(1)過濾器:伺服器啟動時建立,過濾器理論上可以任意內容,比如html、jsp、servlet、圖片路徑
(2)攔截器:攔截器只可以攔截action
2 Servlet和action區別
(1)servlet預設第一次訪問時候建立,建立一次,單例項物件
(2)action每次訪問時候建立,建立多次,多例項物件
自定義攔截器
自定義登入攔截器
1 需求:在專案中,有很多的action的超連結,實現只有是登入的狀態,才可以點選action的超連結實現功能,如果不是登入狀態,點選action超連結返回到登入頁面
2 登入的狀態:使用session域物件實現
(1)登入成功之後,把資料放到session裡面
(2)判斷session是否有值,可以知道是否是登入狀態
3 實現登入的基本功能
(1)查詢資料庫判斷使用者名稱和密碼
此時可以在jsp頁面用EL表示式來獲取到session域中的資訊
4 新增登入攔截器功能
(1)判斷是否登入:判斷session裡面是否有名稱是username的值
(2)攔截器實現過程
第一步 建立類,繼承MethodFilterInterceptor類
第二步 重寫MethodFilterInterceptor類裡面的方法寫攔截器邏輯
第三步 配置action和攔截器關係(註冊攔截器)
(1)在要攔截的action標籤所在的package標籤裡面宣告攔截器
(2)在具體的action標籤裡面使用宣告的攔截器
(3)struts2裡面執行很多的預設攔截器,但是如果在action裡面配置自定義攔截器,
問題:預設的攔截器不會執行了,如果沒有到預設攔截器中的功能也可以不引用。
解決:把預設攔截器手動使用一次
5 配置的攔截器,會對action裡面所有的方法都進行攔截
(1)在action裡面有login的登入的方法,這個方法不需要攔截,如果這個方法都攔截,問題是,永遠登入不進去了
(2)解決:讓login方法不進行攔截
這裡就是為什麼要繼承MethodFilterIntercepor類的原因了,如果繼承的是AbstractInterceptor類需要用反射的方法才讓實現讓一些方法不攔截,而繼承這個類直接就可以使用配置的方式來實現,如下:
- 直接通過配置方式讓action裡面某些方法不進行攔截,多個方法用逗號分隔
6 如果登入狀態,直接到功能頁面,如果不是登入顯示登陸頁面
登入之後出現小問題:
原因:
解決:設定開啟的位置是在父視窗中開啟,這個target在以前a標籤中見過