程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> struts2 18攔截器詳解(十八)

struts2 18攔截器詳解(十八)

編輯:關於JSP

AnnotationValidationInterceptor      AnnotationValidationInterceptor攔截器處於defaultStack第十七的位置,主要是用於數據校驗的,該攔截器繼承自ValidationInterceptor攔截器增加了在方法上使用注解取消校驗功能。ValidationInterceptor又繼承自MethodFilterInterceptor。前面繼承自MethodFilterInterceptor的攔截器中都沒有講MethodFilterInterceptor,在AnnotationValidationInterceptor配置中傳遞了一個名為excludeMethods的參數,這個參數就是提交到MethodFilterInterceptor中的,用於指定哪些方法是不需要進行校驗的。所以這裡先講解MethodFilterInterceptor攔截器,下面是MethodFilterInterceptor的intercept源碼: [java]   @Override   public String intercept(ActionInvocation invocation) throws Exception {       if (applyInterceptor(invocation)) {           return doIntercept(invocation);       }        return invocation.invoke();   }        這裡在執行invocation.invoke();之前調用了applyInterceptor判斷是否要應用上該攔截器,下面看一下applyInterceptor方法: [java]   protected boolean applyInterceptor(ActionInvocation invocation) {       String method = invocation.getProxy().getMethod();       //真正判斷的方法是MethodFilterInterceptorUtil.applyMethod方法,把排除的方法集合與包含的方法集合與Action要執行的方法名傳入       //該方法把字符串轉成了正則表達式對該方法進行匹配,邏輯不難,但判斷代碼比較多,所以講到這吧...       boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);       if (log.isDebugEnabled()) {           if (!applyMethod) {               log.debug("Skipping Interceptor... Method [" + method + "] found in exclude list.");           }       }       return applyMethod;   }        所以所有繼承自MethodFilterInterceptor的攔截器都可以設置excludeMethods與includeMethods參數用於指定哪些方法要應用上該攔截器,哪些方法不需要應用上該攔截器,對於AnnotationValidationInterceptor就是哪些方法要進行校驗與哪方法不需要進行校驗。AnnotationValidationInterceptor在defaultStack中的配置為:   [html]  <interceptor-ref name="validation">       <param name="excludeMethods">input,back,cancel,browse</param>   </interceptor-ref>        即排除input,back,cancel,browse這四個方法外,其它執行的Action方法都要進行校驗。 現在假設要進行校驗,所以會執行AnnotationValidationInterceptor的doIntercept方法,下面是該方法源碼: [java]   protected String doIntercept(ActionInvocation invocation) throws Exception {       //獲取當前執行的Action       Object action = invocation.getAction();       if (action != null) {//如果Action不為null           Method method = getActionMethod(action.getClass(), invocation.getProxy().getMethod());//獲取Action要執行的方法           //獲取Action中加了SkipValidation注解的方法集合           Collection<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethods(action.getClass(), SkipValidation.class);           if (annotatedMethods.contains(method))               return invocation.invoke();//如果當前執行的方法有SkipValidation注解則不進行校驗,調用下一個攔截器              //檢測是否有覆蓋父類標有SkipValidation注解的方法           Class clazz = action.getClass().getSuperclass();//獲取父類字節碼           while (clazz != null) {               annotatedMethods = AnnotationUtils.getAnnotatedMethods(clazz, SkipValidation.class);//獲取父類標有SkipValidation注解的方法集合               if (annotatedMethods != null) {//如果方法不為null                   //如果當前要執行的方法是覆蓋了父類的方法,而父類方法標有SkipValidation注解,則當前方法也不進行校驗                   for (Method annotatedMethod : annotatedMethods) {                       if (annotatedMethod.getName().equals(method.getName())                               && Arrays.equals(annotatedMethod.getParameterTypes(), method.getParameterTypes())                               && Arrays.equals(annotatedMethod.getExceptionTypes(), method.getExceptionTypes()))                           return invocation.invoke();//調用下一個攔截器                   }               }               clazz = clazz.getSuperclass();//獲取父類字節碼           }       }       //如果要進行校驗,繼續調用父類的doIntercept方法       return super.doIntercept(invocation);   }        從上面可以看到如果當前Action執行的方法上面如果標注有SkipValidation注解或者其覆蓋的方法上標注有SkipValidation注解就不會對該方法進行校驗,執行完成後還調用了父類ValidationInterceptor的doIntercept方法,下面該方法源碼: [java]  @Override   protected String doIntercept(ActionInvocation invocation) throws Exception {       doBeforeInvocation(invocation);//調用doBeforeInvocation方法       return invocation.invoke();//調用下一個攔截器   }   doBeforeInvocation(invocation)方法源碼:   protected void doBeforeInvocation(ActionInvocation invocation) throws Exception {       Object action = invocation.getAction();//獲取當前執行的Action       ActionProxy proxy = invocation.getProxy();//獲取ActionProxy對象          //the action name has to be from the url, otherwise validators that use aliases, like       //MyActio-someaction-validator.xml will not be found, see WW-3194       String context = proxy.getActionName();//獲取Action名稱       String method = proxy.getMethod();//獲取執行Action的方法名稱       //省略...       //declarative默認為true       if (declarative) {          if (validateAnnotatedMethodOnly) {//validateAnnotatedMethodOnly默認為false              actionValidatorManager.validate(action, context, method);          } else {              actionValidatorManager.validate(action, context);//所以執行這裡          }      }           //如果Action實現了Validateable接口,ActionSupport實現了Validateable接口       if (action instanceof Validateable && programmatic) {//programmatic默認為true           Exception exception = null;            //強轉           Validateable validateable = (Validateable) action;           if (LOG.isDebugEnabled()) {               LOG.debug("Invoking validate() on action "+validateable);           }           try {//調用有validate,validateDo前綴的方法               PrefixMethodInvocationUtil.invokePrefixMethod(                               invocation,                                new String[] { VALIDATE_PREFIX, ALT_VALIDATE_PREFIX });           }           catch(Exception e) {               // If any exception occurred while doing reflection, we want                // validate() to be executed               LOG.warn("an exception occured while executing the prefix method", e);               exception = e;           }           //alwaysInvokeValidate默認為true,總是調用Action的validate方法           if (alwaysInvokeValidate) {               validateable.validate();           }           if (exception != null) {                // rethrow if something is wrong while doing validateXXX / validateDoXXX                throw exception;           }       }   }        因為struts2提供了聲明式校驗的功能,即使用XML文件對提交過來的數據進行校驗,而這種聲明式校驗就是由actionValidatorManager.validate(action, context);這句代碼實現的調用ActionValidatorManager的validate方法,其方法內部就是去查找相應的XML校驗文件,解析XML校驗文件生成com.opensymphony.xwork2.validator.Validator檢驗器對象,然後對象提交的數據進行校驗,如果校驗有些數據不合法則會將相應的錯誤信息通過addFieldError添加字段錯誤信息打印到控制台。因為聲明式校驗功能涉及尋找XML校驗文件,解析XML校驗文件生成校驗器對象,再使用校驗器對象進行校驗數據,裡面還添加了校驗器緩存,所以裡面的代碼量很大,在這只能 講大概原理,具體細節有興趣可以自己去研究。      如果Action繼承自ActionSupport類(通常),則實現了Validateable接口,接下來就會調用帶有validate或validateDo前綴的校驗方法,就是通過PrefixMethodInvocationUtil這個工具類調用的,這個工具類前面我們已經遇到過了,在講解PrepareInterceptor攔截器的時候,會調用帶有prepare或prepareDo前綴的方法。帶有validate或validateDo前綴的校驗方法如果同時存在的話只會執行帶有validate前綴的方法,這是PrefixMethodInvocationUtil 這個工具類內部代碼決定的。ValidationInterceptor的alwaysInvokeValidate屬性默認為true,所以Action的validate方法總是會調用的,即validateable.validate();這句代碼會執行。在validate方法中使用代碼進行校驗。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved