很久沒有做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
當然在這個攔截器中還可以做其他的事情,比如權限的進一步驗證等,看個人需求。
到這,基本上把攔截器的知識簡單的回顧了。