攔截器的整個過程java
程序是在執行Action以前調用的攔截器,整個過程是這樣子的spring
這裏面注意兩個問題:編程
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { Map<String, Object> extraContext = createContextMap(request, response, mapping, context); // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); try { Configuration config = configurationManager.getConfiguration(); ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
這個字段就是"struts.valueStack"
// if the ActionMapping says to go straight to a result, do it! if (mapping.getResult() != null) { } else { proxy.execute(); } } catch (ConfigurationException e) { }
就看裏面標記的這幾句,這個方法的做用設置好valueStack,而後放到request範圍裏服務器
也就是說經過request能夠獲得valueStack對象;session
so,在視圖上拿valueStack對象的方式就有如下兩種:架構
1.request.getAttribute()app
2.ongl: #request.structs.valueStackjsp
第二個是循環Interceptor的問題,每個Interceptor裏面其實都調用了invoke方法,this
那麼這個調用是怎麼實現的呢,spa
如今作一個模擬就明白了
攔截器原理模擬
使用最簡單的java工程作實驗
而後定義一個Action,表示最後要執行的東東
public class Action {
public void execute() { System.out.println("execute!"); } }
而後最重要的是定義一個ActionInvocation
import java.util.ArrayList; import java.util.List; public class ActionInvocation { List<Interceptor> interceptors = new ArrayList<Interceptor>(); int index = -1; Action a = new Action(); public ActionInvocation() { this.interceptors.add(new FirstInterceptor()); this.interceptors.add(new SecondInterceptor()); }
//首先遍歷每個攔截器,當遍歷完了以後,執行Action的方法 public void invoke() { index ++; if(index >= this.interceptors.size()) { a.execute(); }else { this.interceptors.get(index).intercept(this); } } }
先定義一個接口,至關於攔截器
public interface Interceptor { public void intercept(ActionInvocation invocation) ; }
而後兩個類實現這個接口
public class FirstInterceptor implements Interceptor { public void intercept(ActionInvocation invocation) { System.out.println(1);
//在裏面又返回調用ActionInvocation 的Invoke方法 invocation.invoke(); System.out.println(-1); } }
public class SecondInterceptor implements Interceptor { public void intercept(ActionInvocation invocation) { System.out.println(2); invocation.invoke(); System.out.println(-2); } }
定義主方法
public class Main { public static void main(String[] args) { new ActionInvocation().invoke(); } }
最後的結果是
1
2
execute!
-2
-1
這裏面最關鍵的地方就是轉來轉去用的都是同一個ActionInvocation 對象
流程大概是:
實線表示直接調用,虛線表示方法返回
上圖是完整的調用過程
由於ActionInvocation調用Second是在First內部,只是轉折了一下,因此能夠理解爲First調用了Second
經過Struct官方的圖來理解整個過程
最主要的思想是在執行Action以前攔一下,在執行以後攔一下
從這個圖中,也能夠理解什麼叫作AOP,面向切面編程
原本有沒有攔截器Struct方法都能執行
可是忽然冒出一個攔截器有種在執行以前切上一刀的感受
攔截器的有點是可插入,可抽回
攔截器能夠用在敏感字符處理,在提交的數據進入服務器的時候,首先檢查數據是否是有敏感字符
還能夠用在權限上面
咱們想一下若是沒有攔截器怎麼作權限
有兩種方式:
一個是在Action類中的exection方法裏面進行判斷
一個是在Jsp的頭的session裏面進行判斷
這樣作是要在每個Action和JSP裏面都要寫的啊
固然權限判斷如今有很好的spring security
定義本身的Struct攔截器
這個其實就是重複形成輪子的過程,只要看看別人的輪子是怎麼造出來的就能夠了。
首先:定義一個MyInterceptor類
package com.bjsxt.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class MyInterceptor implements Interceptor { public void destroy() { // TODO Auto-generated method stub } public void init() { // TODO Auto-generated method stub } public String intercept(ActionInvocation invocation) throws Exception { long start = System.currentTimeMillis(); String r = invocation.invoke(); long end = System.currentTimeMillis(); System.out.println("action time = " + (end - start)); return r; } }
而後要把這個攔截器加到配置裏面
在Struct裏面,默認攔截器都是放在/struts-default.xml 裏面,固然咱們不能改人家的代碼。
修改Struct.xml
<package name="test" namespace="/" extends="struts-default">
首先聲明這個攔截器
<interceptors> <interceptor name="my" class="com.bjsxt.interceptor.MyInterceptor"></interceptor> </interceptors> <action name="test" class="com.bjsxt.action.TestAction"> <result>/test.jsp</result> <interceptor-ref name="my"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </action> </package>
在實際開發過程當中,自定義攔截器其實是不多不多用到的。一方面,Struct已經爲咱們寫出來不少攔截器,另外一方面,一旦咱們自定義了攔截器,那麼咱們的代碼就和Struct綁定上了,之後若是再換成其餘架構基本上是沒法實現的。