17.struts2_PrepareInterceptor拦截器


为了解决上节的问题

I.   在执行删除的时候, employeeId 不为 null, 但 getModel 方法却从数据库加载了一个对象. 不该加载!
II.  指向查询全部信息时, 也 new Employee() 对象. 浪费!

使用PrepareInterceptor拦截器


可以为每一个 ActionMethod 准备 prepare[ActionMethdName] 方法, 而抛弃掉原来的 prepare() 方法
将 PrepareInterceptor  的 alwaysInvokePrepare 属性置为 false, 以避免 Struts2 框架再调用 prepare() 方法.

在struts.xml中设定不执行接口prepa

 <param name="prepare.alwaysInvokePrepare">false</param>


EmployeeAction类

public class EmployeeAction implements RequestAware, ModelDriven<Employee>, Preparable{
	
	private Dao dao = new Dao();
	/**
	 * 使用ModelDriven而不在Aciton中声明employee各个对象
	 */
	private Employee employee; 
	
	public String update(){
		dao.update(employee);
		return "success";
	}
	
	public void prepareUpdate(){
		employee = new Employee();
	}

	public String edit(){	
		return "edit";
	}
	
	public void prepareEdit(){
		employee = dao.get(employeeId);
	}
	
	public String save(){
		dao.save(employee);
		return "success";
	}
	
	/**
	 * 实现Preparable接口后,可以设定前缀方法prepare+methodName,来在getModel之前准备
	 */
	public void prepareSave(){
		employee = new Employee();
	}
	
	public String delete(){
		dao.delete(employeeId);
		return "success";
	}
	
	public String list(){
		request.put("emps", dao.getEmployees());
		return "list";
	}
	
	private Map<String, Object> request;

	@Override
	public void setRequest(Map<String, Object> arg0) {
		this.request = arg0;
	}
	
	//需要在当前EmployeeAction定义id属性,以接收页面请求参数
	private Integer employeeId;
	
	public void setEmployeeId(Integer employeeId) {
		this.employeeId = employeeId;
	}
	
	/**
	 * 在新建和修改时会用到
	 */
	@Override
	public Employee getModel() {
		//若create 就new一个
		
		//若修改,则从数据库取
		
		//判断标准为是否有EmployeeID参数
		//所以在进入DrivelModel拦截器前要先执行params拦截器栈
		//通过paramsPrepaeParams拦截器栈可以实现
		
		return employee;
	}

	@Override
	public void prepare() throws Exception {
		System.out.println("prepare...");
	}
	
}




struts2源代码解析


----------------------------------源代码解析---------------------------------

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();
}

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]);
	}
}

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值