Struts2 之 modelDriven & prepare 拦截器详解 (3)

ModelDriven 拦截器使用 getModel() 方法将对应的对象压入栈顶,例如 add() 方法执行的时候 getModel() 方法执行后其栈顶为 employee 对象,这样便可以利用 params 拦截器将表单对应的字段属性值赋给栈顶对象对应的属性值

源码解析(ModelDriven 拦截器的 intercept 方法)

public String intercept(ActionInvocation invocation) throws Exception { //获取 Action 对象: EmployeeCurd 对象, 此时该 Action 已经实现了 ModelDriven 接口 //public class EmployeeAction implements RequestAware, ModelDriven<Employee> Object action = invocation.getAction(); //判断 action 是否是 ModelDriven 的实例 if (action instanceof ModelDriven) { //强制转换为 ModelDriven 类型 ModelDriven modelDriven = (ModelDriven) action; //获取值栈 ValueStack stack = invocation.getStack(); //调用 ModelDriven 接口的 getModel() 方法 //即调用 EmployeeAction 的 getModel() 方法 /* public Employee getModel() { employee = new Employee(); return employee; } */ Object model = modelDriven.getModel(); if (model != null) { //把 getModel() 方法的返回值压入到值栈的栈顶. 实际压入的是 EmployeeCurd 的 employee 成员变量 stack.push(model); } if (refreshModelBeforeResult) { invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); } } return invocation.invoke(); }

CURD 操作进阶之 PrepareInterceptor 拦截器

以上实现存在的问题:

在进行删除操作的时候会传入 empId,而 getModel() 方法判断到 empId 不为空,会从 Map 集合中去获取一个 Employee 对象置于栈顶,而对于 delete 操作不需要对象

在显示所有员工的时候 getModel() 方法会创建一个空的 Employee 对象置于栈顶,而对于此操作也是没有必要的

解决方案 - 使用 PrepareInterceptor 拦截器

实现

Action 类实现 Preparable 接口

查看源码

public String doIntercept(ActionInvocation invocation) throws Exception { // 获取 Action 对象 Object action = invocation.getAction(); // 判断其是否实现了 Prepareable 拦截器 if(action instanceof Preparable) { try { // 存取前缀,不是 prepare 就是 prepareDo String[] prefixes; // 判断 firstCallPrepareDo 属性,其默认为 false if(this.firstCallPrepareDo) { // 若 firstCallPrepareDo为 true, prefixes 的值为 prepareDoXxx,prepareXxx prefixes = new String[]{"prepareDo", "prepare"}; } else { // 若 firstCallPrepareDo为 false,prefixes 的值为 prepareXxx ,prepareDoXxx prefixes = new String[]{"prepare", "prepareDo"}; } // 执行 invokePrefixMethod() 方法,方法名为 prefixes 数组的值 PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes); } catch (InvocationTargetException var5) { Throwable cause = var5.getCause(); if(cause instanceof Exception) { throw (Exception)cause; } if(cause instanceof Error) { throw (Error)cause; } throw var5; } // 判断 alwaysInvokePrepare 属性的值,其默认为 true。 // 若其值为 true 则每次都会调用 Action 的 prepare() 方法, if(this.alwaysInvokePrepare) { ((Preparable)action).prepare(); } } return invocation.invoke(); } public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException { // 获取 Action 实例 Object action = actionInvocation.getAction(); // 获取要调用的 Action 的方法的名字 String methodName = actionInvocation.getProxy().getMethod(); if(methodName == null) { methodName = "execute"; } // 获取前缀方法 Method method = getPrefixedMethod(prefixes, methodName, action); if(method != null) { // 若方法不为空则通过反射调用该前缀方法 method.invoke(action, new Object[0]); } } // 获取前缀方法 public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) { assert prefixes != null; // 把方法的首字母变为大写 String capitalizedMethodName = capitalizeMethodName(methodName); String[] arr$ = prefixes; int len$ = prefixes.length; int i$ = 0; // 遍历前缀数组 while(i$ < len$) { String prefixe = arr$[i$]; // 通过拼接的方式得到前缀加方法名,第一次为 prepareUpdate 第二次为 prepareDoUpdate String prefixedMethodName = prefixe + capitalizedMethodName; try { // 通过反射从 action 对象中调用方法,并返回 return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY); } catch (NoSuchMethodException var10) { if(LOG.isDebugEnabled()) { LOG.debug("cannot find method [#0] in action [#1]", new String[]{prefixedMethodName, action.toString()}); } ++i$; } } return null; }

结论

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygyjf.html