博客 / 詳情

返回

web技術回顧之struts2攔截器

  很久沒有做web項目了,最近公司要做個產品,目前正在做demo,暫時從大數據迴歸到web開發了,發現好多東西都忘光了,而且現在的web開發也比我做web的時候先進了許多,很多技術如雨後春筍般冒了出來,目前也在一點點的學習,在這之前我還是先回顧一下以前的知識點吧,畢竟太久沒用真的生疏了,導致犯了很多低級錯誤,為了以後少犯這種錯,寫幾篇小文章,梳理一下知識點。

  言歸正傳,這次回顧的是struts2攔截器。當然現在web技術已經基本不用struts了,這裏介紹還是希望能多多關注攔截器本身。所以首先引出幾個名詞。

攔截器

  顧名思義,攔截器就是用來攔截的一個組件,在struts中攔截的訪問action的請求。簡單的説,在訪問action之前,都會調用這個組件。利用這個特性,我們可以在攔截器中做很多事情,比如常説的表單校驗,登錄驗證等。

  攔截器符合DRY(don’t repeat yourself)規則。早期的開發,由於經驗缺乏等各種原因,開發人員經常會在很多很多不同的地方調用同樣的方法,大部分人都是粘貼複製,這會對後期的維護工作帶來巨大的隱患。而攔截器可以理解為調用方法的一種改進,因為攔截器可以在目標對象執行以前由系統自動執行,而調用方法則必須顯示的調用才可以。這就使攔截器本身擁有更高層次的解耦性。

攔截器棧

  攔截器棧就是將攔截器按照一定的順序連接在一起的鏈,當滿足攔截的要求時,則會按照實現聲明的順序依次執行攔截器。這使得我們可以處理較為複雜的情況。

  瞭解了這幾個概念後,我們回顧一下在項目中如何使用攔截器,這裏要展現的是自定義攔截器,一般真正的項目都會有自己特定的需求,很少用到struts自帶或者默認的攔截器。

  首先,現在struts.xml中配置攔截器

<package name="Global" extends="struts-default">
    <interceptors>  
        <!-- 定義攔截器 -->
        <interceptor name="loginInterceptor" class="commons.util.LoginInterceptor"></interceptor>  
        <!-- 定義攔截器棧 -->
        <interceptor-stack name="CENNAVIStack">
            <!-- 引用攔截器,在棧中,攔截器的先後順序決定執行的順序 -->
             <interceptor-ref name="loginInterceptor"></interceptor-ref> 
            <interceptor-ref name="defaultStack" />
        </interceptor-stack>  
    </interceptors>
    <!-- 將此攔截器棧設置成package全局攔截器,請求在此package下定義的action都會被攔截 -->  
    <default-interceptor-ref name="CENNAVIStack"></default-interceptor-ref>
    <!-- package全局result(global-results),如果action返回的string在自己的result中沒有找到,就會查找這個全局的 -->
    <global-results>  
        <result name="login" type="redirect">login.html</result>
    </global-results>
</package>

<package name="Global-json" extends="json-default">
    <interceptors>  
        <interceptor name="loginInterceptor" class="commons.util.LoginInterceptor"></interceptor>  
        <interceptor-stack name="PBSStack">
             <interceptor-ref name="loginInterceptor"></interceptor-ref> 
            <interceptor-ref name="defaultStack" />
        </interceptor-stack>  
    </interceptors>  
    <default-interceptor-ref name="PBSStack"></default-interceptor-ref>
</package>

  上面的配置均有註釋,這裏不細説,但要簡單解釋一下一個概念

package

  從語義上講,其實代表了每一個獨立的模塊。在這個模塊中,你可以定義隸屬於這個模塊的行為方式,而與其他的模塊沒有關係。所以,每個package都有獨立的interceptor、result-type和action的定義。

  name屬性的值的package的名字,extends的值説明了繼承哪個包

  其實可以把它看作為一個普通的java類的構造器,你所定義的攔截器、action,等等都是它的屬性。而name就是這個類的對象名,extends就相當於這個類繼承了哪個類。這樣攔截器等等是這個對象的特有的屬性,跟其他對象無關。

再來看struts-default和json-default

struts-default

  struts-default是struts-default.xml中定義的,而我們一般的配置文件都會繼承這個配置文件。

  就攔截器而言,struts-default 包中預定義了很多攔截器,我們繼承了這個包也就可以使用其中的攔截器。當然這個包中也定義了攔截器棧(interceptor-stack)以及默認使用的攔截器棧,默認使用的攔截器棧是defaultStack,內含18個順序排列的攔截器。因此,如果自定義的package繼承了struts-default而又沒有任何攔截器上的修改,該自定義package使用的攔截器棧就是defaultStack。所以一般情況而言都會繼承這個包。

json-default

  struts2的json plugin可以實現struts2和json的完美結合,當我們要使用json 的時候就可以使用這個包。如果繼承了這個包並且配置<result> 標籤,如

<result type="json">
    <param name="root">list</param>
</result>

  而且在action中return了list,那麼struts就可以將list這個對象自動轉換為json格式數據,並返回給前端UI,不用我們再自己寫轉換了,極大程度的方便了開發。

  對於package,我們應該靈活運用,比如定義多個package,配置不同的攔截器,攔截特定的action,來達到特定的目的,比如權限和功能的控制等。

  上面配置配置了自定義的攔截器,接下來看看這個自定義攔截器如何寫:

package commons.util;

import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import org.apache.struts2.ServletActionContext;
import com.cennavi.sys.hbm.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
 * 
 * @ClassName: LoginInterceptor 
 * @Description: TODO(這裏用一句話描述這個類的作用) 
 * @author lzz 
 * @date 2017年3月1日 下午4:05:53 
 *
 */
public class LoginInterceptor extends AbstractInterceptor
{
    @Override
    public void init(){
        //應用啓動的時候會先調用init方法
        System.out.println("init");
    }
    
    private static final long serialVersionUID = 2000108379092059226L;

    public String intercept(ActionInvocation invocation) throws Exception{
        System.out.println("intercept==================");
        Map session = ActionContext.getContext().getSession();
        HttpServletRequest request = ServletActionContext.getRequest(); 
        if(request.getRequestURI().indexOf(Commons.LOGIN_ACTION_URL) >= 1){
            return invocation.invoke();
        }
        
        User user = (User)session.get(Commons.USER_INFO);
        if(user != null) {
            return invocation.invoke();
        }
        return Action.LOGIN;            
    }
}

  上面代碼只是一個示例,真正的系統中會有較多的邏輯,比如會有對ajax請求的處理等等。

  上面代碼的功能是先判斷是不是訪問的登錄的url,如果是則不攔截,直接調用登錄url中的訪問的action,如果不是登錄的url,則獲取session中的user,如果不為空,證明在登錄的時候已經將這個user存放在session中,可以操作,如果為空,則需要重新登錄。其中Action.LOGIN所對應的字符串是“login”,之前我們在struts.xml中有配置

<global-results>  
    <result name="login" type="redirect">login.html</result>
</global-results>

  Action.LOGIN所對應的就是這個配置,一但攔截器返回login,則重定向login.html

  當然在這個攔截器中還可以做其他的事情,比如權限的進一步驗證等,看個人需求。

  到這,基本上把攔截器的知識簡單的回顧了。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.