ActionForm产生,生命周期,校验深入解析

    在Struts1.3中的ActionForm的产生并不是由RequestProcessor这个类来对客户请求做相应处理了,而是由其子类ComposableRequestProcessor来进行处理,而处理所用到得技术便是Commons Chain了这个开源jar包,关于它的技术实现细节,在我另一篇文章《Struts源码解析》中详细介绍过了,本文主要着重介绍Struts1.3关于ActionForm生成和其生命周期的源码。

   Struts1.3中,配置在chain-config.xml中的CreateActionFormPopulateActionFormValidateActionForm 分别对应着ActionForm的产生,赋值,校验。下面我分别对应这3个类的源码进行详细介绍:

因为这个三个类都在配置链中,所以他们的执行顺序为CreateActionForm—> PopulateActionForm-> ValidateActionForm。所以我将也将按此顺序来说明。

首先CreateActionForm类,它的execute()方法如下图所示:

 

ActionConfig actionConfig = actionCtx.getActionConfig();String name = actionConfig.getName();

这个2个方法是找到ActionMapping,并得到ActionMappingname属性值,如果name为空,这该ActinMpping对应得ActionForm为空。

FormBeanConfig formBeanConfig =actionConfig.getModuleConfig().findFormBeanConfig(name);

根据name值寻找对应的ActionFormBean。(如果大家对于它们之间为什么存在对应关系有所疑问的话,可以查看我的另一篇文章《Struts源码解析》)

 Map scope = actionCtx.getScope(actionConfig.getScope())方法是根据配置文件中所配置的生命周期request,session,application来得到一个对应的生命周期MapactionCtx实际上是为ServletActionContext类,它在ComposableRequestProcessor类中被实例化,但是值得注意的是在调用ServletActionContext构造函数的时候,将会实例化ServletWebContext()类如下代码所示:

调用的构造函数为

public ServletActionContext(ServletContext context,

        HttpServletRequest request, HttpServletResponse response) {

        this(new ServletWebContext(context, request, response));

}

调用ServletActionContextgetScope方法实际上是调用了其父类

ActionContextBasegetScope方法,如下代码所示: 

public Map getScope(String scopeName) {

        if (REQUEST_SCOPE.equals(scopeName)) {

            return this.getRequestScope();

        }

        if (SESSION_SCOPE.equals(scopeName)) {

            return this.getSessionScope();

        }

        if (APPLICATION_SCOPE.equals(scopeName)) {

            return this.getApplicationScope();

        }

        throw new IllegalArgumentException("Invalid scope: " + scopeName);

    }

这样根据在Strus-config.xml配置文件中的所配置的scopeName分别调用相应的getXxxxScope方法,而实现这些方法的类又在ActionContextBase抽象类的子类WebActionContext中(典型的Template模式),如下所示:

public Map getApplicationScope() {

        return webContext().getApplicationScope();

    }

    public Map getRequestScope() {

        return webContext().getRequestScope();

    }

    public Map getSessionScope() {

        return webContext().getSessionScope();

    }

webContext().getXxxxScope()方法调用的是实例ServletActionContext的时候实例化的ServletWebContext类的对应方法

 

举例getRequestScope()方法:

   public Map getRequestScope() {

 

        if ((requestScope == null) && (request != null)) {

            requestScope = new ServletRequestScopeMap(request);

        }

        return (requestScope);

}

最终还回ServletRequestScopeMap类该类是继承了Map接口的一个存储ActionFormBean得容器。

例如我们把ActionFormBean配置成request scope的话。最后将在CreateActionForm中为在ServletRequestScopeMap存取ActionFormBean

我们在看看ServletRequestScopeMapputget方法

    public Object put(Object key, Object value) {

        if (value == null) {

            return (remove(key));

        }

        String skey = key(key);

        Object previous = request.getAttribute(skey);

        request.setAttribute(skey, value);

        return (previous);

    }

        

    public Object get(Object key) {

        return (request.getAttribute(key(key)));

    }

这样大家就很容易看到所谓的request scope实际上就是将ActionFormBean存在HttpServletRequest中。而其他的scope范围就可以依次类推。

Struts在所有的生命周期内都找不到ActionFormBean的话,Struts将自己创建一个新的实例,下图是Struts创建Bean的实例的方法:

 

 

 

 

 

其中注意如果在

1.    如果是在配置文件中配置的是DynaActionForm的话,程序将执行obj = getDynaActionFormClass().newInstance()方法创建DynaActionForm类并同时将属性nametype指定的类的类型注入到DynaActionFormdynaValues中。

其中props[i].initial()还回的还可以是客户指定的bean,八大基本类型,String,或者是对象数组等。所以我们如果要使用上述类型可以在struts-config.xml中设置如下:

<form-bean name="dynActionForm" type="org.apache.struts.action.DynActionForm" >

<form-property name="" type="XXX.XXX.User" initial=""/>

<form-property name="" type="java.lang.String[]" size="10" initial=""/>

<form-property name="" type="XXX.XXX.User[]" size="10" initial=""/>

</form-bean>

其中 initial 为初始值设定。

 2.<form-bean name="" type="" />Type中配置得是普通Bean,既没有继承ActionForm或者是DynaBean的普通pojo的话,Struts将用BeanValidatorForm对其进行包装后,也能对其属性进行注入。

使用方式为:

<form-bean name="user" type="xx.xx.xx.User" />

BeanValidatorForm from = (BeanValidatorForm)actionForm;

User  user = from.getInstance();//得到你配置得bean,属性已经被注入

介绍完ActionForBean是如何创建之后就应该是为其注入属性值了。ActionForBean被创建后,马上就是应该为其属性注入相应的值,而完成这个功能的类为PopulateActionForm

该类核心方法为:

 

 

 

从源码中可以看到完成注入的类是委托给了RequestUtils

RequestUtils的主要功能就是为ActionForm注入。

在该方法中: BeanUtils.populate(bean, properties);就是将所要注入的值注入到所需要的Bean

而主要流程就是

1.       names = request.getParameterNames();

2.       multipart/form-data则经过处理由parameterValue = multipartParameters.get(name);,如果是普通表单由parameterValue = request.getParameterValues(name);

3.       最后由 BeanUtils.populate(bean, properties)将表单值对应注入到bean中。

这里的bean 分几种情况:有只继承ActionForm的,继承DynaActionForm和被BeanValidatorForm包装的bean,下面分别就3种情况对其进行分析:

1.      只继承ActionForm的类只为其属性注入。

2.      如果是DynaActionForm则为其<form-property>中配置的属性注入值。

3.      如果是为BeanValidatorForm的话,则为为普通Pojo相应的属性注入值。

当所有相应的属性都注入到Bean中之后,接下来调用chain链的ValidateActionForm类来对FormBean注入值进行校验。

 

如果在

<action input=" " name="" path=”” scope="" type=" " validate="true" />

Validate如果设置为“true”的话,将调用ActionFormvalidate方法来进行校验。如果检验有错误,将还回ActionErrors,并将ActionErrors保存到ActionContext中。

好了,到此关于StrutsActionForm的生成,如何实现生命周期,如何注入属性值和其如何校验就介绍完毕。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值