com.easyjf.web.WebForm:负责封装用于用户端显示的数据,是在视图及程序之间传输、处理数据的媒介
WebForm起到了一个VO和TO的作用,将表单数据或者请求中的参数都包装其中,并且返回页面上需要合成的数据也在其中。
WebForm的生命周期 :
首先,当一个请求到达时,框架首先解析出请求的IWebAction,并从Action中得到对应的WebForm的名字。然后直接调用FrameworkEngine.creatWebForm(request, formName)来得到需要的WebForm.当WebForm中填满了表单数据后,框架会解析出cmd值和传入的参数,也放入WebForm中。到此,框架对WebForm的处理已经结束,将WebForm就会传入到IWebAction中。在IWebAction中处理完并返回了Page后,框架会得到WebForm中的那个合成页面值的Map,并添加到Velocity的上下文对象中进行页面模版的合成,最后form被丢弃,WebForm完成一次生命周期。了解生命周期的主要目的是在于对在WebForm中存在的数据的生命周期的理解。每一次都会有一个新的WebForm产生,但是值得注意的是,WebForm在将数据保存到Velocity上下文时,不光要保存使用addResult方法和addPo方法放入的值,还要向Velocity上下文中保存textElement中的数据,意味着重复的数据可以不用在Action中重复的添加,这在应用中需要特别注意。该项特性和带环境的页面导向、不带环境的页面导向配合使用,会大大的简化一些情况下的操作。
@FormPO注解:
inject:
指定可通过toPo自动注入的属性,默认为全部可自动注入,如果设置了该值,则表示除指定可注入的属性以外,其它所有属性都为不能自动注入;需要注入的属性使用逗号(,)作为分逗符。比如:
@FormPO(inject="name,bornDate")
public class Person
即在Person类(或者Command对象)中,当使用toPO方法拷贝值的时候,只有name和bornDate属性被拷贝,其余如果有符合的属性,都不准被拷贝。这在很大的层度上提高了应用的安全性。
disInject:
指定不可通过toPO自动注入的属性,当试图通过toPO更新该属性时,将会被忽略,并在日志中提示相关信息。在EasyJWeb中,一个模型(域)对象的属性默认情况下全部都是可注入的,我们可以通过disInject来指定不可注入的属性。多个不可注入的属性使用逗号(,)作为分隔。 如上面inject示例,也可以写成下面的形式:
@FormPO(disInject="id,loginTimes")
public class Person
控制addPo属性的可见性:
前文在介绍WebForm的时候,提到了addPo方法,在这个方法中,其实也有控制标签:
disRead:
指定为disRead的属性在addPo方法中不会被添加到Velocity上下文中。
下面,给一个这些标签的使用的一个范例:
@Entity
@FormPO(name = "person",inject="name,sex,mail,intro",disInject="age",disRead="serialVersionUID,id")
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Column(length = 32)
private String name;
@Column(length = 6)
private String sex;
@Column(length = 40)
private String mail;
private int age;
@Column(length = 200)
public String intro;
}
在这个例子中,如果调用WebForm.toPo(Person.class),那么Person中的name、sex、mail将会拷贝,而age不会被拷贝,并且调用WebForm.addPo()方法时,Person的serialVersionUID和id将不会被添加到Velocity上下文中。关于更多@FormPO标签的用法,请参见API doc。
toPo(map, obj)方法 :map为form.getTextElement(), obj为要转换的对象
1、若obj为Map类型则直接复制,返回
2、分析obj的@Overrides注解信息,该注解用于属性名的替换,如
@Overrides({@OverrideProperty(name="name",newName="xm"),@OverrideProperty(name="bornDate",newName="csrq")})
public class Person {
private String name;
private Date bornDate;
}
3、通过com.easyjf.beans.BeanWrapper包装器获得类的属性并依次检查其可注入性:首先保证属性的可写性(可写属性或有可写方法:wrapper.isWritableProperty(name), property.getWriteMethod())
4、获得属性的验证对象:通过Validator,Field及FormPO标签中的validators标签中的标签来判断验证对象配置(返回列表结构为List<Map<Annonation,
List<Validator>>>。针对字段的Field、Validator标签、针对方法的Field、Validator标签以及针对FormPO的标签等分别放在存放在返回列表中),多个则取列表顺序最后一个,并生成验证对象ValidatorObject返回。
5、检测@FormPO注解的inject和disInject,判断属性是否可注入,可以则再检测属性的@Field注解的writeable值是否为true。
允许注入则依次检测设置方法或属性的@POLoad,@InnerProperty,@MultiPOLoad,@OverrideProperty注解,获得注入属性别名,然后根据注解注入:
①@POLoad :从持久(或业务)层加载特定id值,类型为clz的对象。 该标签用来加载关联 ,我们在表单中只能存放关联对象的id,而在赋值的时候需要通过这个id从持久层中加载这个对象,然后设置到指定的属性中,
public class BBSDoc {
@Id
private Long id;
@POLoad(name="dirId")
private BBSDir dir;
}
②@InnerProperty:内嵌属性加载,根据属性名实例化内嵌对象,利用包装器分析内嵌对象的属性:若属性可写,检查如address.city以及city这样的字段,在包装器中赋值。 设置内部属属性,嵌套属性该标签主要用于辅助WebForm.toPo方法来给复杂的属性对象赋值,主要用于内嵌属性。 地址信息的Address
public class Address {
private String province;
private String city;
}
public class Employee {
private String name;
@InnerProperty
private Address address1;
@InnerProperty(overrides={@OverrideProperty(name="province",newName="province2"),@OverrideProperty(name="city",newName="city2")});
private Address address2;
}
③@MultiPOLoad:自动加载关联的List对象,适用于OneToMany关联。form中传入id数组或ids字串(,隔开),对每一个id利用POLoadDao从持久层加载特定id值,类型为clz的对象。返回对象的list(@MultiPOLoad的targetClz需要手动设置)
public class Father {
@MultiPOLoad(targetClz="Son")
List<Son> sons;
}
// form传入1,2,3或者[1,2,3]表示son的id,则自动注入
④普通对象加载:如果需要验证,则执行。利用com.easyjf.beans.BeanUtils.convertType(Object value, Class<?> type)将form中传入value转化成type类型的对象。
6、执行验证,若验证出错,则不改变PO对象的值,即不加入到属性名与对象值映射map中,最后返回该map
7、如果validateRollback为false且验证不出错,则利用包装器将属性名与对象之注入到obj中
addPo(obj, form.getTextElement)
1、若obj是map类型,则直接复制
2、利用包装器获得属性,检查其可读性(FormPO是否有disread以及Field的readable),将名与值添加到form中
附件是一个topo示例