Struts2的学习(5)-PrepareInterceptor

Prepareble拦截器到底是做什么用的
Struts2.0中的ModelDriven拦截器的getModel()方法负责把要执行的Action类以外的的一个对象放到ValueStack值栈的栈顶。
prepare拦截器就是负责准备为ModelDrven拦截器的getModel()方法准备model。
该拦截器可以在执行当前Action的目标方法前进行一些准备工作来处理一些业务逻辑。
看一下拦截器的执行过程
	<interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <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">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <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>


我这里使用的是params拦截器栈,首先执行params拦截器,接着执行prepare拦截器,在执行ModelDriven拦截器,在执行params拦截器
public String doIntercept(ActionInvocation invocation) throws Exception {  
        // 获取实例  
        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();  
            }  
   }  
我们来看一下执行流程:
  • 首先获取了当前Action的实例,紧接着判断了当前Action是否实现了Prepareble接口。
  • 根据bool值得到一个数组确认了前缀数组(["prepare","prepareDo"]的一个字符串数组);
  • 然后执行前缀方法(该方法可能是空,后面的源代码中大家会看得到),进入方法后的代码 如下:
	public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
		Object action = actionInvocation.getAction();
		
		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);
		if (method != null) {
			method.invoke(action, new Object[0]);
		}
	}


  • 获取了当前action,和当前的action方法
  • 判断当前methodName是不是为空
  • 然后获取了一个前缀方法,getPrefixedMethod
public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
		assert(prefixes != null);
		String capitalizedMethodName = capitalizeMethodName(methodName);
        for (String prefixe : prefixes) {
            String prefixedMethodName = prefixe + capitalizedMethodName;
            try {
                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;
}
  • 第3行,让目标方法首字母编程了大写(比如update,转换后成Update)
  • 紧接着下一行遍历前缀数组,把前缀拼接在目标方法前面(prepareUpdate,prepareDoUpdate)
  • 然后7行,尝试着从当前Action中获取拼接好的方法,如果有就返回,如果没有会生成一个NoSuchMethodException的异常
  • 根据数组前缀的生成方式,去执行这两个方法(只不过是生成的顺序不一样,控制就是在前面的那个bool值)。
  • 再接回刚才的getPrefixedMethod方法,返回后判断这个拼接好的方法是否为空,然后接着执行method.invoke方法(如果两个方法都是空的话, 就都不执行)
  • 回到刚才的doIntercept方法,下面还有一个alwaysInvokePrepare控制的方法
  • alwaysInvokePrepare为false,责不会去执行实现了Prepareble接口的Action的prepare方法;

package com.yu.struts2.app;

import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;

public class EmployeeAction implements RequestAware ,ModelDriven<Employee>, Preparable{

    private Dao dao = new Dao();

    public String list(){
        requestMap.put("emps", dao.getEmployees());
        return "list";
    }

    public String delete(){
        dao.delete(employeeId);
        return "success";
    }

    private Employee employee;

    public String save(){
        // 1.获取请求参数:通过定义对应属性的方式
        // 2.调用Dao的save方法
        dao.save(employee);

        return "success";
    }

    public void prepareSave(){
        employee = new Employee();
    }

    public String edit(){
        // 1.获取传入的employeeId:employee.getEmployeeId()
        // 2.根据employeeId获取Employee对象
        //Employee emp = dao.get(employee.getEmployeeId());

        // 3.把栈顶对象的属性转配好,此时栈顶对象时employee
        // 目前的employee对象只有employeeId属性,其他属性为null
        /*
         *  Struts2表单回显时:从值栈栈顶开始查找匹配的属性,若找到就添加到value属性中
         */
//        employee.setEmail(emp.getEmail());
//        employee.setFirstName(emp.getFirstName());
//        employee.setLastName(emp.getLastName());

        // 不能够进行表单的回显,因为经过重写赋值的employee对象不再是栈顶对象
        //employee = dao.get(employee.getEmployeeId());

        // 手动的把从数据库中获取的Employee对象放到值栈的栈顶。
        // 但此时值栈栈顶及第二个对象均为Employee对象,不够完美
        //ActionContext.getContext().getValueStack().push(dao.get(employee.getEmployeeId()));

        return "edit";
    }

    public void prepareEdit(){
        employee = dao.get(employeeId);
    }

    public String update(){
        dao.update(employee);

        return "success";
    }

    public void prepareUpdate(){
        employee = new Employee();
    }

    private Map<String, Object> requestMap;

    @Override
    public void setRequest(Map<String, Object> arg0) {
        // TODO Auto-generated method stub
        this.requestMap = arg0;
    }

    private Integer employeeId;

    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }

    @Override
    public Employee getModel() {
        // 判断是Create还是Edit。
        // 若为Create,则employee = new Employee();
        // 若为Edit,则employee = dao.get(employeeId);
        // 判定标准为是否有employeeId这个参数。若有该参数,则视为Edit;若没有该参数,则视为Create
        // 若通过employeeId来判断,则需要在modelDriven拦截器之前执行一个params拦截器!
        // 而这可以通过使用paramsPrepareParams拦截器栈实现
        // 需要在struts.xml文件中配置使用paramsPrepareParams作为默认的拦截器栈

//        if(employeeId == null){
//            employee = new Employee();
//        }
//        else
//            employee = dao.get(employeeId);
//        
        return employee;
    }

    /*
     * prepare方法的主要作用:为getModel()方法准备model的
     */
    @Override
    public void prepare() throws Exception {
        System.out.println("prepare...");
    }
}
可以为每一个ActionMethod准备一个prepareXxxx方法,来替换掉实现了Prepareble接口的prepare方法;
alwaysInvokePrepare设置为false,以避免struts框架再次调用prepare方法;
<interceptors>
     <interceptor-stack name="mycustomStack">
         <interceptor-ref name="paramsPrepareParamsStack">
             <param name="prepare.alwaysInvokePrepare">false</param>
         </interceptor-ref>
     </interceptor-stack>
</interceptors>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值