一、struts2中的攔截器(框架功能核心)
1、過(guò)濾器VS攔截器
過(guò)濾器VS攔截器功能是一回事。過(guò)濾器是Servlet規(guī)范中的技術(shù),可以對(duì)請(qǐng)求和響應(yīng)進(jìn)行過(guò)濾。
攔截器是Struts2框架中的技術(shù),實(shí)現(xiàn)AOP(面向切面)的編程思想,是可插拔的, 可以對(duì)訪問(wèn)某個(gè) Action 方法之前或之后實(shí)施攔截。
攔截器棧(Interceptor Stack): 將攔截器按一定的順序聯(lián)結(jié)成一條鏈. 在訪問(wèn)被攔截的方法時(shí), Struts2攔截器鏈中的攔截器就會(huì)按其之前定義的順序被依次調(diào)用
Struts2執(zhí)行原理 - 底層分析
2、自定義攔截器
struts2定義了一個(gè)攔截器接口Interceptor接口。
Interceptor接口里面有三個(gè)抽象方法
•init: 該方法將在攔截器被創(chuàng)建后立即被調(diào)用, 它在攔截器的生命周期內(nèi)只被調(diào)用一次. 可以在該方法中對(duì)相關(guān)資源進(jìn)行必要的初始化
•interecept: 每攔截一個(gè)動(dòng)作請(qǐng)求, 該方法就會(huì)被調(diào)用一次.
•destroy: 該方法將在攔截器被銷毀之前被調(diào)用, 它在攔截器的生命周期內(nèi)也只被調(diào)用一次.
Struts 會(huì)依次調(diào)用程序員為某個(gè) Action 而注冊(cè)的每一個(gè)攔截器的 interecept 方法.每次調(diào)用 interecept 方法時(shí), Struts 會(huì)傳遞一個(gè) ActionInvocation 接口的實(shí)例.
ActionInvocation: 代表一個(gè)給定動(dòng)作的執(zhí)行狀態(tài), 攔截器可以從該類的對(duì)象里獲得與該動(dòng)作相關(guān)聯(lián)的 Action 對(duì)象和 Result 對(duì)象. 在完成攔截器自己的任務(wù)之后, 攔截器將調(diào)用 ActionInvocation 對(duì)象的 invoke 方法前進(jìn)到 Action 處理流程的下一個(gè)環(huán)節(jié).
還可以調(diào)用 ActionInvocation 對(duì)象的 addPreResultListener 方法給 ActionInvocation 對(duì)象 “掛” 上一個(gè)或多個(gè) PreResultListener 監(jiān)聽(tīng)器. 該監(jiān)聽(tīng)器對(duì)象可以在動(dòng)作執(zhí)行完畢之后, 開(kāi)始執(zhí)行動(dòng)作結(jié)果之前做些事情
自定義攔截器步驟:
a、編寫一個(gè)類,實(shí)現(xiàn)com.opensymphony.xwork2.interceptor.Interceptor接口,或者繼承
com.opensymphony.xwork2.interceptor.AbstractInterceptor類。(適配器模式),一般都選擇繼承AbstractInterceptor(攔截器會(huì)駐留內(nèi)存)。因?yàn)锳bstractInterceptor 類實(shí)現(xiàn)了 Interceptor 接口. 并為 init, destroy 提供了一個(gè)空白的實(shí)現(xiàn)
編寫兩個(gè)攔截器InterceptorDemo1 ,和InterceptorDemo2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
package com.itheima.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class InterceptorDemo1 extends AbstractInterceptor { //動(dòng)作的每次訪問(wèn)都會(huì)調(diào)用該方法 public String intercept(ActionInvocation invocation) throws Exception { System.out.println( "攔截前Demo1" ); String rtvalue = invocation.invoke(); //放行,這里為什么返回string? 因?yàn)樽罱K的結(jié)果返回的Action的Result,而action的結(jié)果是string類型 System.out.println( "攔截后Demo1" ); return rtvalue; } } package com.itheima.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import com.opensymphony.xwork2.interceptor.PreResultListener; public class InterceptorDemo2 extends AbstractInterceptor { //動(dòng)作的每次訪問(wèn)都會(huì)調(diào)用該方法 public String intercept(ActionInvocation invocation) throws Exception { // invocation.addPreResultListener(new PreResultListener() { // // public void beforeResult(ActionInvocation invocation, String resultCode) { // System.out.println("結(jié)果顯示前"); // } // }); System.out.println( "攔截前Demo2" ); String rtvalue = invocation.invoke(); //放行 System.out.println( "攔截后Demo2" ); return rtvalue; } } |
b、需要在struts.xml中進(jìn)行定義,定義攔截器,先定義在使用。
1
2
3
4
5
6
7
8
|
< package name = "p1" extends = "struts-default" > <!-- 定義攔截器:只對(duì)當(dāng)前包有效 --> < interceptors > < interceptor name = "interceprotDemo1" class = "com.itheima.interceptor.InterceptorDemo1" ></ interceptor > < interceptor name = "interceprotDemo2" class = "com.itheima.interceptor.InterceptorDemo2" ></ interceptor > </ interceptors > </ package > |
c、在動(dòng)作配置中就可以使用了
1
2
3
4
5
6
7
8
|
< action name = "action1" class = "com.itheima.action.Demo1Action" method = "execute" > <!-- 使用定義的攔截器。如過(guò)沒(méi)有指定任何的攔截器,默認(rèn)使用default-stack棧中的所有攔截器; 一旦指定了任何一個(gè)攔截器,默認(rèn)的就無(wú)效了 --> < interceptor-ref name = "interceprotDemo1" ></ interceptor-ref > < interceptor-ref name = "interceprotDemo2" ></ interceptor-ref > < result >/success.jsp</ result > </ action > |
實(shí)現(xiàn)動(dòng)作類Demo1Action
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.itheima.action; import com.opensymphony.xwork2.ActionSupport; public class Demo1Action extends ActionSupport { @Override public String execute() throws Exception { System.out.println( "execute執(zhí)行了" ); return SUCCESS; } } |
運(yùn)行結(jié)果
因?yàn)閟truts2中如文件上傳,數(shù)據(jù)驗(yàn)證,封裝請(qǐng)求參數(shù)到action等功能都是由系統(tǒng)默認(rèn)的defaultStack中的攔截器實(shí)現(xiàn)的,所以我們定義的攔截器需要引用系統(tǒng)默認(rèn)的defaultStack,這樣應(yīng)用才可以使用struts2框架提供的眾多功能。
如過(guò)沒(méi)有指定任何的攔截器,默認(rèn)使用default-stack棧中的所有攔截器;一旦指定了任何一個(gè)攔截器,默認(rèn)的就無(wú)效了除了要使用自定義的攔截器之外,還要使用defaultStack,可以這么辦
方法一:(自己使用),只需在action中配置自定義的和defaultStack默認(rèn)的就可以了。
方法二:(大家都用的時(shí)候),如果希望包下的所有action都使用自定義的攔截器, 要使用攔截器棧 interceptor-stack,定義一個(gè)interceptor-stack,然后在action中可以通過(guò)<default-interceptor-ref name=“mydefaultStack”/>把攔截器定義為默認(rèn)攔截器,mydefaultStack名字可以自己取。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<interceptors> <interceptor name= "interceprotDemo1" class = "com.itheima.interceptor.InterceptorDemo1" ></interceptor> <interceptor name= "interceprotDemo2" class = "com.itheima.interceptor.InterceptorDemo2" ></interceptor> <interceptor-stack name= "mydefaultStack" > <interceptor-ref name= "defaultStack" ></interceptor-ref> <interceptor-ref name= "interceprotDemo1" ></interceptor-ref> <interceptor-ref name= "interceprotDemo2" ></interceptor-ref> </interceptor-stack> </interceptors> <action name= "action3" class = "com.itheima.action.LoginAction" method= "login" > <interceptor-ref name= "mydefaultStack" ></interceptor-ref> <result>/success.jsp</result> </action> |
3、Struts2 自帶的攔截器
案例1:檢查用戶是否登錄
1、 編寫頁(yè)面login.jsp
1
2
3
4
5
6
7
|
< body > < form action = "${pageContext.request.contextPath}/login.action" method = "post" > < input type = "text" name = "username" />< br /> < input type = "text" name = "password" />< br /> < input type = "submit" value = "登錄" /> </ form > </ body > |
2、編寫登錄校驗(yàn)的攔截器LoginCheckInterceptor 類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.itheima.interceptor; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class LoginCheckInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { HttpSession session = ServletActionContext.getRequest().getSession(); //通過(guò)ServletActionContext對(duì)象獲得session對(duì)象 Object user = session.getAttribute( "user" ); if (user== null ){ //沒(méi)有登錄 return "login" ; //返回到某個(gè)邏輯視圖 } return invocation.invoke(); //放行 } } |
3、編寫配置文件struts.xml
1
2
3
4
5
6
7
8
9
10
11
12
|
< package name = "p2" extends = "struts-default" > < interceptors > < interceptor name = "loginCheckInterceptor" class = "com.itheima.interceptor.LoginCheckInterceptor" ></ interceptor > < interceptor-stack name = "mydefaultStack" > < interceptor-ref name = "defaultStack" ></ interceptor-ref > < interceptor-ref name = "loginCheckInterceptor" ></ interceptor-ref > </ interceptor-stack > </ interceptors > < action name = "login" class = "com.itheima.action.CustomerAction" method = "login" > < result >/login.jsp</ result > </ action > </ package > |
4、編寫動(dòng)作類CustomerAction
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.itheima.action; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class CustomerAction extends ActionSupport { public String login(){ System.out.println( "登錄" ); ServletActionContext.getRequest().getSession().setAttribute( "user" , "ppp" ); return SUCCESS; } } |
案例2:監(jiān)測(cè)動(dòng)作方法的執(zhí)行效率
編寫時(shí)間監(jiān)測(cè)過(guò)濾器TimerInterceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package com.itheima.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class TimerInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { long time = System.nanoTime(); String rtvalue = invocation.invoke(); System.out.println(rtvalue+ "執(zhí)行耗時(shí):" +(System.nanoTime()-time)+ "納秒" ); return rtvalue; } } |
編寫配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
< package name= "p2" extends = "struts-default" > <interceptors> <interceptor name= "loginCheckInterceptor" class = "com.itheima.interceptor.LoginCheckInterceptor" ></interceptor> <interceptor name= "timerInterceptor" class = "com.itheima.interceptor.TimerInterceptor" ></interceptor> <interceptor-stack name= "mydefaultStack" > <interceptor-ref name= "defaultStack" ></interceptor-ref> <interceptor-ref name= "loginCheckInterceptor" ></interceptor-ref> <interceptor-ref name= "timerInterceptor" ></interceptor-ref> </interceptor-stack> </interceptors> <result name= "login" >/login.jsp</result> </action> </ package > |
從上面可以看出,在一個(gè)action 中可以配置多個(gè)過(guò)濾器。
4、自定義攔截器:能夠指定攔截的方法或不攔截的方法
能夠指定攔截的方法或不攔截的方法,編寫過(guò)濾器時(shí),可以實(shí)現(xiàn)類MethodFilterInterceptor,里面有兩個(gè)字段,通過(guò)注入?yún)?shù)就可以指定那些不攔截,兩個(gè)參數(shù)只要用一個(gè)即可,當(dāng)攔截較少是,可以用includeMethods ,當(dāng)攔截較多是,可以用排除的方法excludeMethods 。
excludeMethods = Collections.emptySet();//排除那些
includeMethods = Collections.emptySet();//包括那些
案例:再續(xù)登錄校驗(yàn)的例子。
1、編寫過(guò)濾器LoginCheckInterceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.itheima.interceptor; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; public class LoginCheckInterceptor extends MethodFilterInterceptor { protected String doIntercept(ActionInvocation invocation) throws Exception { HttpSession session = ServletActionContext.getRequest().getSession(); Object user = session.getAttribute( "user" ); if (user== null ){ //沒(méi)有登錄 return "login" ; //返回到某個(gè)邏輯視圖 } return invocation.invoke(); //放行 } } |
2、編寫配置文件
3、編寫動(dòng)作類CustomerAction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.itheima.action; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class CustomerAction extends ActionSupport { public String add(){ System.out.println( "調(diào)用add的service方法" ); return SUCCESS; } public String edit(){ System.out.println( "調(diào)用edit的service方法" ); return SUCCESS; } public String login(){ System.out.println( "登錄" ); ServletActionContext.getRequest().getSession().setAttribute( "user" , "ppp" ); return SUCCESS; } } |
4、編寫頁(yè)面
addCustomer.jsp
1
2
3
|
< body > 添加客戶 </ body > |
editCustomer.jsp
1
2
3
|
< body > 修改客戶 </ body > |
login.jsp
1
2
3
4
5
6
7
|
<body> <form action= "${pageContext.request.contextPath}/login.action" method= "post" > <input type= "text" name= "username" /><br/> <input type= "text" name= "password" /><br/> <input type= "submit" value= "登錄" /> </form> </body> |
success.jsp
1
2
3
|
< body > oyeah </ body > |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。