從struts2攔截器到自定義攔截器


攔截器可謂struts2的核心了,最基本的bean的注入就是通過默認的攔截器實現的,一般在struts2.xml的配置中,package內直接或間接繼承了struts-default.xml,這樣struts2默認的攔截器就會作用.下面詳細的說明一下:

Interceptor攔截器類似於過濾器,是可以在action執行前后執行的代碼。是我們做web開發時經常用的技術。比如:權限控制、日志等。我們也可以將多個Interceptor連在一起組成Interceptor棧。

Struts2攔截器,每個攔截器類只有一個對象實例,即采用單例模式,所以引用這個攔截器的Action都共享這一攔截器類的實例,因此,在攔截器中如果使用類變量,要注意同步問題。

實現原理 : Struts2攔截器的實現原理相對簡單,當請求struts2的action時,Struts 2會查找配置文件,並根據其配置實例化相對應攔截器對象,然后串成一個列表,最后一個一個地調用列表中的攔截器。

攔截器和過濾器的區別:

1. 攔截器和過濾器的概念非常類似。 

2. 過濾器隸屬於web容器,可以過濾一切請求(包括action、servletjsphtml等等)。

3. 而攔截器隸屬於struts2框架,只能攔截action(無法攔截對jsp的請求)。 

4. 過濾器內部采用函數回調來實現。攔截器采用動態代理來實現!

 

攔截器在struts2中的應用:

 

 

對於Struts2框架而言,正是大量的內置攔截器完成了大部分操作。比如: 

 

– 像params攔截器將http請求中參數解析出來賦值給Action中對應的屬性。 

 

– Servlet-config攔截器負責把請求中HttpServletRequest實例和HttpServletResponse實例傳遞給Action

 

– …

 

struts-default.xml中有一個默認的引用,在默認情況下(也就是<action>中未引用攔截器時)會自動引用一些攔截器。

常用攔截器:token

作用:防止表單重復提交攔截器

使用方法:配置struts2.xml+重復提交處理+jsp頁面表單內插入<s:token></s:token>標簽;其中struts.xml的配置是核心

(1)先來看一下最基本的struts.xml的配置:

 

1 <package name="test" namespace="/" extends="struts-default">
2         <action name="testValidate" class="com.bjsxt.struts.test.TestValidateAction">
3          <interceptor-ref name="token"></interceptor-ref>
4              <result name="success">/ok.jsp</result>
5              <result name="input">/testFormLabel.jsp</result>
6              <result name="invalid.token">/tokenInvalid.jsp</result>
7         </action>
8 </package>

 

說明:

1.代碼第三行代表引入一個struts2自帶的攔截器token,此操作會使默認的攔截器失效,即無法使用其他功能,自定義攔截器再詳細說明;

2.代碼第六行為基本固定的格式,result的name屬性值是固定的,后面的/tokenInvalid.jsp可以根據需求自己定義

3.此token攔截器會對該action下的所有請求作用,最關鍵的一點!即:所有該action的請求都會經過token的攔截處理,自定義攔截器時再說明;

(2)form表單中需加入<s:token></s:token>標簽:

1 <s:form action="testValidate" >
2         <s:textfield name="uname" ></s:textfield>
3         <s:token></s:token>        
4         <s:submit></s:submit>
5 </s:form>    

說明:不一定是s標簽的表單,普通表單中插入<s:token></s:token>也可以實現攔截的效果.

(3)處理措施,我的是跳到一個錯誤頁面:testFormLabel.jsp

1 <%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
2 <h1>表單不能重復提交!!</h1>

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

 自定義攔截器:

 

      作為“框架(framework)”,可擴展性是不可或缺的,因為世上沒有放之四海而皆准的東西。雖然,Struts 2為我們提供如此豐富的攔截器實現,但是這並不意味我們失去創建自定義攔截器的能力,恰恰相反,在Struts 2自定義攔截器是相當容易的一件事。

      大家在開始着手創建自定義攔截器前,切記以下原則:
  攔截器必須是無狀態的,不要使用在API提供的ActionInvocation之外的任何東西。要求攔截器是無狀態的原因是Struts 2不能保證為每一個請求或者action創建一個實例,所    以如果攔截器帶有狀態,會引發並發問題。

 條件:

  1. 直接或間接實現接口com.opensymphony.xwork2.interceptor.Interceptor或者繼承類com.opensymphony.xwork2.interceptor.AbstractInterceptor 

  2.通過<interceptor>元素來定義攔截器 

     3.通過<interceptor-ref>元素來使用攔截器

   4.自定攔截器的java類並重寫public String intercept(ActionInvocation ai) throws Exception

注意:如果為Action指定了一個攔截器,則系統默認的攔截器棧將會失去作用。為了繼續使用默認攔截器,所以上面配置文件中手動引入了默認攔截器

 步驟:

  1.新建一個class,用於實現自定義攔截器功能,這兒就實現最為普遍的登陸驗證,即防止未經登陸的情況下,訪問action;先說一下原理:

  首先,用戶登陸后,經過action驗證用戶名和密碼是否正確,如果正確則在session作用域內存放user對象,否則跳到登陸頁面並提示用戶名或密碼不正確,而且session作用域中user的值是沒有設置的.然后,由於在該action下使用了自定義的攔截器(struts.xml配置),訪問該action的所有請求都會被攔截,驗證session中user屬性的值,如果值不存在,則跳到登陸頁面並提示無權操作,否則執行invoke方法,即請求會被action正常響應,並返回相應的結果.

代碼體現如下:

自定義攔截器類:

 1 package com.bjsxt.struts2.exercise.interceptor;
 2 
 3 import java.util.Map;
 4 
 5 import com.bjsxt.struts2.exercise.vo.Users;
 6 import com.opensymphony.xwork2.Action;
 7 import com.opensymphony.xwork2.ActionContext;
 8 import com.opensymphony.xwork2.ActionInvocation;
 9 import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
10 
11 public class LoginInterceptor extends MethodFilterInterceptor{
12     @Override
13     protected String doIntercept(ActionInvocation invocation) throws Exception {
14         //獲取session對象(經過struts2包裝過)
15         Map session = ActionContext.getContext().getSession();
16         //獲取session作用域內是否有值
17         Users user = (Users) session.get("user");
18         if(user!=null){//合法訪問
19             return invocation.invoke();
20         }else{//user為空說明未經過登陸,保存錯誤提示信息,跳到登陸頁面
21             ActionContext.getContext().put("noright", "請先登陸再進行操作!");
22             return Action.LOGIN;
23         }
24     }
25 }

user類:

 1 package com.bjsxt.struts2.exercise.vo;
 2 
 3 public class Users {
 4     private Integer id;
 5     private String name;
 6     private String password;
 7     public Integer getId() {
 8         return id;
 9     }
10     public void setId(Integer id) {
11         this.id = id;
12     }
13     public String getName() {
14         return name;
15     }
16     public void setName(String name) {
17         this.name = name;
18     }
19     public String getPassword() {
20         return password;
21     }
22     public void setPassword(String password) {
23         this.password = password;
24     }
25 } 

 

2.配置struts.xml,使自定義攔截器作用:

 

 1 <package name="move" namespace="/move" extends="struts-default">
 2         <interceptors>
 3             <interceptor name="loginInteceptor" class="com.bjsxt.struts2.exercise.interceptor.LoginInterceptor"></interceptor>
 4         </interceptors>
 5         <global-results>
 6             <result name="login" >/jsp/movebooking/login.jsp</result>
 7         </global-results>
 8         <action name="moveBookingAction" class="com.bjsxt.struts2.exercise.action.MoveBookingAction" >
 9             <interceptor-ref name="loginInteceptor">
10                 <param name="excludeMethods">addMoveInfo</param>
11             </interceptor-ref>
12             <interceptor-ref name="token">
13                 <param name="includeMethods">addMoveInfo</param>
14             </interceptor-ref>
15             <interceptor-ref name="defaultStack"></interceptor-ref>
16             <result name="queryList" >/jsp/movebooking/movelist.jsp</result>
17             <result name="queryInfo" >/jsp/movebooking/moveinfo.jsp</result>
18             <result name="update" >/jsp/movebooking/updateinfo.jsp</result>
19             <result name="afterupdate" type="redirectAction" >moveBookingAction!queryMoveList</result>
20             <result name="success">/jsp/movebooking/success.jsp</result>
21             <result name="invalid.token">/jsp/movebooking/tokenInvalid.jsp</result>
22         </action>
23         
24         <action name="userAction" class="com.bjsxt.struts2.exercise.action.UserAction">
25             <result name="success" type="redirectAction" >moveBookingAction!queryMoveList</result>
26             <result name="failed" type="redirect">/jsp/movebooking/login.jsp
27             </result>
28         </action>
29     </package>

 

說明:

  (1)使用自定義攔截器會使默認攔截器失效,所以需要手動引入:代碼第15行;當然上述代碼引入攔截器的方式也可以采用攔截器棧的方式,就不貼了;

  (2)注意攔截器的順序,一般情況下,默認攔截器都是放在最后面的,權限驗證與token相比較,我覺得先驗證是否登陸更加必要;

  (3)interceptor-ref內可以定義param元素,即實現對特定方法的攔截;但是注意,使用方法攔截器必須直接或間接實現AbstractInerceptor接口或者繼承

MethodFilterInterceptor類,並重寫doIntercept方法.param標簽內有兩個屬性:

      excludeMethods:排除的方法

      includeMethods:包含的方法

在本配置文件中,由於token攔截器的作用范圍為moveBookingAction下所有請求,而我在測試的時候就發現,該action下的所有請求都會被攔截到重復提交的錯誤頁面,原理尚不明白,有高手敬請指導(只有需要被作用的請求對應的jsp頁面的form表單內加入了token標簽),所以被逼無奈對token攔截的方法只限定在addMoveInfo方法中!

 

 

3.使用的action類和幾個jsp頁面:

UserAction:

 1 package com.bjsxt.struts2.exercise.action;
 2 
 3 import com.bjsxt.struts2.exercise.service.UserService;
 4 import com.bjsxt.struts2.exercise.vo.Users;
 5 import com.opensymphony.xwork2.Action;
 6 import com.opensymphony.xwork2.ActionContext;
 7 import com.opensymphony.xwork2.ActionSupport;
 8 
 9 public class UserAction extends ActionSupport{
10     private UserService userService  =new UserService();
11     private Users user;
12     public String queryUser() throws Exception{
13         user = userService.queryUser(user);
14 //        將user存到session中,實現攔截器攔截未經登陸直接請求的url的功能
15         ActionContext.getContext().getSession().put("user", user);
16         if(user!=null){
17             return Action.SUCCESS;
18         }else{
19             ActionContext.getContext().getSession().put("wrong", "用戶名或密碼錯誤!");
20             return "failed";
21         }
22     }
23     
24     public Users getUser() {
25         return user;
26     }
27 
28     public void setUser(Users user) {
29         this.user = user;
30     }
31 
32 }    

MoveBookingAction:

 1 package com.bjsxt.struts2.exercise.action;
 2 
 3 import com.bjsxt.struts2.exercise.service.MoveBookingService;
 4 import com.bjsxt.struts2.exercise.util.MyPageUtil;
 5 import com.bjsxt.struts2.exercise.vo.MoveBookingVo;
 6 import com.opensymphony.xwork2.ActionSupport;
 7 
 8 public class MoveBookingAction extends ActionSupport{
 9     private MoveBookingService moveBookingService = new MoveBookingService();
10     private MyPageUtil pu;
11     private Integer pageNum;
12     private MoveBookingVo moveBookingVo;
13     private String[] phone;
14     /**
15      * 搬家列表
16      * @return
17      * @throws Exception
18      */
19     public String queryMoveList() throws Exception{
20         pu = moveBookingService.queryMoveList(pageNum);
21         return "queryList";
22     }
23     
24     /**
25      * 搬家信息詳情
26      * @return
27      * @throws Exception
28      */
29     public String queryMoveInfo() throws Exception{
30         moveBookingVo = moveBookingService.queryMoveInfo(moveBookingVo);
31         return "queryInfo";
32     }
33     
34     /**
35      * 搬家詳情,跳到update頁面
36      * @return
37      * @throws Exception
38      */
39     public String queryForUpdate() throws Exception{
40         moveBookingVo = moveBookingService.queryMoveInfo(moveBookingVo);
41         return "update";
42     }
43     
44     /**
45      * 修改搬家信息
46      * @return
47      * @throws Exception
48      */
49     public String updateMoveInfo() throws Exception{
50         moveBookingService.updateMoveInfo(moveBookingVo);
51         return "afterupdate";
52     }
53     /**
54      * 搬家預約
55      * @return
56      * @throws Exception
57      */
58     public String addMoveInfo() throws Exception{
59         moveBookingVo.setStatus("0");
60         moveBookingVo.setPhone(phone[0]+phone[1]);
61         moveBookingService.addMoveInfo(moveBookingVo);
62         return "success";
63     }
64     
65     public MyPageUtil getPu() {
66         return pu;
67     }
68     public void setPu(MyPageUtil pu) {
69         this.pu = pu;
70     }
71     public Integer getPageNum() {
72         return pageNum;
73     }
74     public void setPageNum(Integer pageNum) {
75         this.pageNum = pageNum;
76     }
77     public MoveBookingVo getMoveBookingVo() {
78         return moveBookingVo;
79     }
80     public void setMoveBookingVo(MoveBookingVo moveBookingVo) {
81         this.moveBookingVo = moveBookingVo;
82     }
83 
84     public String[] getPhone() {
85         return phone;
86     }
87 
88     public void setPhone(String[] phone) {
89         this.phone = phone;
90     }
91 }

 

login.jsp:

 1 <body>
 2           <font size="5"><b>管理員登陸</b></font><br>
 3           <form id="f1" action="move/userAction!queryUser">
 4               <input type="hidden" id="flag" name="flag" value="${flag }"/>
 5               用戶名:
 6                   <input id="uname" name="user.name" onclick="clearMsg()" />
 7               密碼:
 8                   <input id="pwd" type="password" name="user.password" onclick="clearMsg()" />
 9               <input type="button" style="background-color: lightgray;width: 100px;" value="登陸" onclick="submit_form()"/>
10           </form>
11           <div id="div" style="color: red">${wrong }${noright }</div>
12   </body>

tokenInvalid.jsp:

1  <body>
2     <h1>請勿重新提交</h1>
3   </body>

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM