Struts2学习总结(十):paramsPrepareParams拦截器栈

 1. paramsPrepareParamsStack:

   <interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
            </interceptor-stack>

  •    和defaultStack都是拦截器栈,struts-default默认使用defaultSack
  •    可以在struts.xml文件通过以下方式修改默认的拦截器栈:

   <default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>

2.拦截器栈中的使用顺序:

params->prepare->model-driven->params

    Struts2.0的设计上要求modelDriven在params之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在prepare之前调用params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。

流程:

  • params拦截器首先给action的相关参数赋值
  • prepare拦截器执行prepare方法,prepare方法会根据参数,如id,去调用业务逻辑,设置model对象
  • model-diven拦截器将model对象压入值栈,这里的model对象就是在prepare中创建
  • params拦截器将参数值赋给model对象
  • action的逻辑执行

3.PrepareInterceptor拦截器(prepare)

该拦截器的功能主要是在Action的execute方法之前执行一些业务逻辑。要使拦截器拦截有效,Action要实现Prepareable接口。

源码解释如下:

public String doIntercept(ActionInvocation invocation) throws Exception {
	//获取 Action 实例
    Object action = invocation.getAction();

	//判断 Action 是否实现了 Preparable 接口
    if (action instanceof Preparable) {
        try {
            String[] prefixes;
            //根据当前拦截器的 firstCallPrepareDo(默认为 false) 属性确定 prefixes
            if (firstCallPrepareDo) {
                prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
            } else {
                prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
            }
            //若为 false, 则 prefixes: prepare, prepareDo
            //调用前缀方法.
            PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
        }
        catch (InvocationTargetException e) {

            Throwable cause = e.getCause();
            if (cause instanceof Exception) {
                throw (Exception) cause;
            } else if(cause instanceof Error) {
                throw (Error) cause;
            } else {
                throw e;
            }
        }

        //根据当前拦截器的 alwaysInvokePrepare(默认是 true) 决定是否调用 Action 的 prepare 方法
        if (alwaysInvokePrepare) {
            ((Preparable) action).prepare();
        }
    }

    return invocation.invoke();
}
(1)首先获取当前Action实例,然后判断Action是否实现了Prepareable接口
(2)根据bool值得到一个数组确认了前缀数组[“prepare”,"parepareDo"]的一个字符串数组(这两个字符串已经在源代码确定,不可修改)
(3)然后执行前缀方法(该方法可能为空),进入方法后:

PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes) 方法: 

public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
	//获取 Action 实例
	Object action = actionInvocation.getAction();
	//获取要调用的 Action 方法的名字(update)
	String methodName = actionInvocation.getProxy().getMethod();
	
	if (methodName == null) {
		// if null returns (possible according to the docs), use the default execute 
        methodName = DEFAULT_INVOCATION_METHODNAME;
	}
	
	//获取前缀方法
	Method method = getPrefixedMethod(prefixes, methodName, action);
	
	//若方法不为 null, 则通过反射调用前缀方法
	if (method != null) {
		method.invoke(action, new Object[0]);
	}
}
(4)进入方法后:
   (4.1)获取当前的Action,和当前的Action方法
   (4.2判断当前的methodName是否为空
    (4.3)然后获取一个前缀方法:getPrefixedMethod:

  •  让目标方法首字母变成了大写
  •  遍历前缀数组,把前缀拼接到目标方法前
  •   尝试从Action中获取拼接好的方法,如果有就返回,没有生成一个NoSuchMethodException的异常
   (5)返回到getPrefixedMethod()方法,返回后判断拼接好的方法是否为空,然后接着执行method.invoke方法
   (6)回到doIntercept()方法,有一个alwaysInvokePrepare为false,就不会执行实现了Prepareable的Action的prepare()方法

PrefixMethodInvocationUtil.getPrefixedMethod 方法: 

public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
	assert(prefixes != null);
	//把方法的首字母变为大写
	String capitalizedMethodName = capitalizeMethodName(methodName);
    
    //遍历前缀数组
    for (String prefixe : prefixes) {
        //通过拼接的方式, 得到前缀方法名: 第一次 prepareUpdate, 第二次 prepareDoUpdate
        String prefixedMethodName = prefixe + capitalizedMethodName;
        try {
        	//利用反射获从 action 中获取对应的方法, 若有直接返回. 并结束循环.
            return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
        }
        catch (NoSuchMethodException e) {
            // hmm -- OK, try next prefix
            if (LOG.isDebugEnabled()) {
                LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());
            }
        }
    }
	return null;
}
实现此拦截器的步骤:

  •     Action实现Prepareable接口,该接口有一个要实现的方法prepare()方法
  •    让需要执行的逻辑放在prepare()方法中,或者如果自己定义的方法叫做xxx,可以加上prepareXxx()方法或prePareDoXxx()方法
    上面出现了三个方法prepare(),prepareXxx(),prepareDoXxx()。拦截器执行的顺序为:PrepareInterceptor 拦截器根据 firstCallPrepareDo  属性决定获取 prepareActionMethodName 、prepareDoActionMethodName的顺序。先寻找prepareXxx()方法,如果没有该方法,就寻找prepareDoXxx()方法,最后执行prepare()方法。如果prepareXxx(),prepareDoXxx()同时存在,只会执行prepareXxx()方法。prepare()最后执行,并且是一定会执行。
    prepare()方法用于你定义的所有方法之间进行预处理,而prepareXxx()与prepareDoXxx()方法只能用于xxx方法之前的预处理
可以在struts.xml文件里配置,不再调用 prepare方法
代码示例:
<interceptors>
     <interceptor-stack name="mycustomStack">
         <interceptor-ref name="paramsPrepareParamsStack">
             <param name="prepare.alwaysInvokePrepare">false</param>
         </interceptor-ref>
     </interceptor-stack>
</interceptors>





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值