ModelDriven 和 Preparable 拦截器

  • 首先了解Params 拦截器

作用:Parameters 拦截器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中. 如果某个字段在模型里没有匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对象

把表单的值赋给栈顶对象的属性   此时栈顶对象即为 Action

在实际的使用中我们想  把 Action 和 Model 清晰地隔离开是有必要的: 有些 Action 类不代表任何Model 对象, 它们的功能仅限于提供显示服务

问题:所以我要在Params 拦截器之前需要把一个Model压入栈顶,以便于在执行到Params 拦截器的时候栈顶对象是个Model 从而对Action中的表单域中对象model属性进行赋值。

这就需要我们使用ModelDriven拦截器

  • ModelDriven 拦截器

如果 Action 类实现了 ModelDriven 接口,该拦截器将把 ModelDriven 接口的 getModel() 方法返回的对象置于栈顶

public class EmployeeAction extends ActionSupport implements ModelDriven<Employee>{

private EmployeeService employeeService;

public void setEmployeeService(EmployeeService employeeService) {

this.employeeService = employeeService;

}

public String save() {

employeeService.save(employee );

return "save-success" ;

}

private Employee employee;

//该拦截器将把 ModelDriven 接口的 getModel() 方法返回的对象置于栈顶

@Override

public Employee getModel() {

return employee ;

}

}

当用户触发 save请求时, ModelDriven 拦截器将调用 EmployeeAction 对象的 getModel() 方法, 并把返回的模型(Employee实例)压入到 ValueStack 栈.

接下来 Parameters 拦截器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中. 因为此时 ValueStack 栈的栈顶元素是刚被压入的模型(Employee)对象, 所以该模型将被填充. 如果某个字段在模型里没有匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对象

查看ModelDriven 底层源代码:

核心代码:

public class ModelDrivenInterceptor extends AbstractInterceptor {

@Override

public String intercept(ActionInvocation invocation) throws Exception {

Object action = invocation.getAction();

//判断action是否实现 ModelDriven的接口

if (action instanceof ModelDriven) {

ModelDriven modelDriven = (ModelDriven) action;

//获取值栈

ValueStack stack = invocation.getStack();

//在这里调用了action中实现的MOdelDriven方法 返回一个对象

Object model = modelDriven.getModel();

if (model !=  null) {

//把返回的对象压入栈顶

stack.push(model);

}

if (refreshModelBeforeResult ) {

invocation.addPreResultListener( new RefreshModelBeforeResult(modelDriven, model));

}

}

return invocation.invoke();

}

}

注意:表单元素的name属性要和对应的model的属性名一至

  • Preparable 拦截器

Struts 2.0 中的 modelDriven 拦截器负责把 Action 类以外的一个对象压入到值栈栈顶
而 prepare 拦截器负责准备为 getModel() 方法准备 model  但Preparable 拦截器没有在struts-default中这就需要我们使用 paramsPrepareParamsStack 拦截器栈

使用 paramsPrepareParamsStack 拦截器栈

paramsPrepareParamsStack 从字面上理解来说, 这个stack的拦截器调用的顺序为:首先 params,然后 prepare,接下来 modelDriven,最后再 params
Struts 2.0的设计上要求 modelDriven 在 params 之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在 prepare之前运行params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。

流程如下:
1. params拦截器首先给action中的相关参数赋值,如id
2. prepare拦截器执行prepare方法,prepare方法中会根据参数,如id,去调用业务逻辑,设置model对象
3. modelDriven拦截器将model对象压入value stack,这里的model对象就是在prepare中创建的
4. params拦截器再将参数赋值给model对象
5. action的业务逻辑执行

实例代码:

public class EmployeeAction extends ActionSupport implements Preparable,ModelDriven<Employee>{
      1. params拦截器首先给action中的相关参数赋值,如id
          private int id;

     private EmployeeService employeeService;

     public void setEmployeeService(EmployeeService employeeService) {
           this.employeeService = employeeService;
     }
      //所以当触发save action方法时会在Preparable的拦截器中自动查找action中是否包含
                    prepareSave()或prepareDoSave() 方法如果包含这个方法就先执行prepareSave()
                                        prepareDoSave()
     public String save() {
          System. out.println(employee );
           employeeService.save(employee );
           return "save-success" ;
     }
     //通过观察源码执行过程得知
    // PrepareInterceptor 拦截器将调用 prepare() 方法,prepareActionMethodName()方法 或 prepareDoActionMethodName ()方法
     private Employee employee;
     public void prepareSave(){
          //所以在这里进行初始化Model的类
           employee= new Employee();
     } 

     @Override
     public Employee getModel() {
           return employee ;
     }
    //  若 Action 实现 Preparable 接口,则 Action 方法需实现 prepare() 方法
//2. prepare拦截器执行prepare方法,prepare方法中会根据参数,如id,去调用业务逻辑,设置model对象 但是一般这个方法都不进行执行具体的方法内容
//PrepareInterceptor 拦截器会根据 alwaysInvokePrepare 属性决定是否执行prepare()方法
     @Override
     public void prepare() throws Exception {}
}

源码实现:
public class PrepareInterceptor extends MethodFilterInterceptor {

PrepareInterceptor 拦截器根据 firstCallPrepareDo  属性决定获取 prepareActionMethodName 

、 prepareDoActionMethodName的顺序。默认情况下先获取 prepareActionMethodName (),

 如果没有该方法,就寻找prepareDoActionMethodName()。
 如果找到对应的方法就调用该方法

    private final static String PREPARE_PREFIX = "prepare";
    private final static String ALT_PREPARE_PREFIX = "prepareDo";
     // 拦截器会根据 alwaysInvokePrepare 属性决定是否执行prepare()方法
    private boolean alwaysInvokePrepare = true;

    private boolean firstCallPrepareDo = false;

    public void setAlwaysInvokePrepare(String alwaysInvokePrepare) {
        this.alwaysInvokePrepare = Boolean.parseBoolean(alwaysInvokePrepare);
    }

    public void setFirstCallPrepareDo(String firstCallPrepareDo) {
        this.firstCallPrepareDo = Boolean.parseBoolean(firstCallPrepareDo);
    }

    @Override
    public String doIntercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();

        if (action instanceof Preparable) {
            try {
                String[] prefixes;
               // firstCallPrepareDo = false;
                if (firstCallPrepareDo ) {
                    prefixes = new String[] {ALT_PREPARE_PREFIX , PREPARE_PREFIX};
                } else {
                    prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX };
                }
               //会先执行prefixes 数组在PrefixMethodInvocationUtil的invokePrefixMethod
                    方法中
                PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
            }
            catch (InvocationTargetException e) {
                 throw e;
            }
          //拦截器会根据 alwaysInvokePrepare 属性决定是否执行prepare()方法
            if (alwaysInvokePrepare ) {
                ((Preparable) action).prepare();
            }
        }

        return invocation.invoke();
    }
//执行prefixes 数组在PrefixMethodInvocationUtil类中
默认执行方法
private static final String DEFAULT_INVOCATION_METHODNAME = "execute";

public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) {
          //得到请求的action类对象
          Object action = actionInvocation. getAction();
          //得到请求的action类对象请求的方法名
          String methodName = actionInvocation.getProxy().getMethod();
          //如果方法名称为NUll就赋值默认的execute方法
           if (methodName == null) {

             methodName = DEFAULT_INVOCATION_METHODNAME;
          }
          //得到前缀方法 也就是prepareSave()或prepareDoSave() 方法如果包含这个方法就先执 行prepareSave()prepareDoSave()

          也就是在请求方action的方法加上prepareActionMethodName()方法 或 prepareDoActionMethodName ()方法  通过getPrefixedMethod 这个方法进行的装配
          Method method = getPrefixedMethod (prefixes, methodName, action);
          //如果包含prepareSave()或prepareDoSave() 方法如果包含这个方法就先执 行prepareSave()prepareDoSave()就进行调用这个对应的方法

           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);
        for (String prefixe : prefixes) {
          //在这里进行配置成 prepareActionMethodName()方法 或 prepareDoActionMethodName
            String prefixedMethodName = prefixe + capitalizedMethodName;
            try {
                return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
            }
            catch (NoSuchMethodException e) {

                }
            }
        }
           return null ;
     }

以上就是ModelDriven 和 Preparable 拦截器的使用和源码的原理 个人感觉写的比较繁琐了
时间: 2024-11-06 03:51:46

ModelDriven 和 Preparable 拦截器的相关文章

Struts2内置拦截器的简要介绍

标记有(*)要着重了解: (1)alias(别名拦截器):允许参数在跨越多个请求时使用不同别名,该拦截器可将多个Action采用不同名字链接起来,然后用于处理同一信息. (2)autowiring(自动装配拦截器):主要用于当Struts2和Spring整合时,Struts2可以使用自动装配的方式来访问Spring容器中的Bean. (3)(*)chain(链拦截器):构建一个Action链,使当前Action可以访问前一个Action的请求信息,一般和<result type="chai

[原创]java WEB学习笔记6:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

调查管理系统 -(6)自定义Struts2的拦截器&amp;自定义UserAware接口&amp;Action中模型赋值问题&amp;Hibernate懒加载问题

1.对于一些功能,如我的调查或新建调查等,只有用户登录后才能进行操作,因此必须对用户是否登录进行判断.当用户登录后才能使用相应的功能,如果没有登录则需为用户导航到登录页面让其进行登录.这个功能可以通过自定义Struts2的拦截器来完成. 2.当用户登录之后,由于是将用户的信息保存在session中的.这样当一些Action中需要用到当前登录的用户的信息时需要手动的从session中获取,不太方便,因此我们声明了一个UserAware接口(即用户关注,类似于Struts2中的SessionAwar

Struts2默认拦截器栈及内建拦截器使用详解

Struts2内建拦截器介绍: alias (别名拦截器):允许参数在跨越多个请求时使用不同别名,该拦截器可将多个Action采用不同名字链接起来,然后用于处理同一信息. autowiring (自动装配拦截器):主要用于当Struts2和Spring整合时,Struts2可以使用自动装配的方式来访问Spring容器中的Bean. chain (链拦截器):构建一个Action链,使当前Action可以访问前一个Action的属性,一般和<result type="chain"

Struts2 的 Validation 拦截器

struts2校验有两种实现方法:     1. 手工编写代码实现(基本验证)     2. 基于XML配置方式实现(验证框架) 手工编写代码实现(基本验证) I:首先 创建一个EmployeeAction类继承于ActionSupport 对应的页面表单元素就一个empId public class EmployeeAction extends ActionSupport { private Integer empId; public void setEmpId(Integer empId)

从源代码剖析modelDriven拦截器和params拦截器和拦截器prepare 和paramsPrepareParamsStack拦截器栈(使您的Struts2代码更加简洁——怎样培养框架设计能力

源代码文件出处:Web App Libraries/struts2-core-2.3.15.3.jar/struts-default.xml 拦截器modelDriven: <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> 拦截器params: <interceptor name="par

[原创]java WEB学习笔记64:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) ModelDriven拦截器 paramter 拦截器

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

ModelDriven拦截器的用法

流程: 1.当用户请求某个action执行某个功能时(如addInfo),如果此Action实现了ModelDriven这个接口,则ModelDriven的拦截器首先会拦截当前操作的请求,通过此Action的getModel方法,将ModelDriven<PersonInfo>中的实体类PersonInfo压入到ValueStack的栈顶. 2.然后Parameters拦截器将拦截到的请求参数,根据表单字段映射到ValueStack栈顶对象的属性上,如果栈顶对象没有此表单字段,则继续寻找下一个

Struts2拦截器的使用 (详解)

这位仁兄的写的不错,我照抄过来了:http://www.blogjava.net/i369/articles/162407.html 如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈defaultStack,如下(这里我是引用了struts2自带的checkbox拦截器):<interceptor-ref name="checkbox">  <param name=&q