将动作与数据模型相分离
动作是Struts中最常接触到的,也是编写的最多的。在这里讲的是,我们如何将动作与动作中的数据模型分开。一句话,也就是不要把过于零散的数据放到动作中。
我们的动作中常常会包含一些数据属性,我在这里举个例子,比如说用户注册,需要用户提供用户名username和密码password,那么我们可能会这么写一个处理用户登录的动作
public class RegisterAction extends ActionSupport {
private String username;
private String password;
//...getter and setter
//...some methods below
}
上述代码就没有很好地体现将数据模型与动作分离开来,我们应该这么写
public class User implements Serializable {
private String username;
private String password;
//...getter and setter
}
把我们的数据尽可能地封装成类,以达到一个粒度适中的程度。
public class RegisterAction extends ActionSupport {
private User user;
//...getter and setter
}
在Struts中,为了能让数据模型与动作分离,为我们提供了两个接口ModelDriven和Preparable。
ModelDriven
这个接口其实是一个泛型,原型如下:
public interface ModelDriven<T> {
public T getModel();
}
如果需要将数据封装后传递到后台,那么就实现这个接口。
public class RegisterAction extends ActionSupport implements ModelDriven<User> {
private User user;
public User getModel()
{
return new User();
}
//...getter and setter
}
假设数据是从JSP页面传过来,那么利用OGNL可以将数据填充到user对象中,在实现了ModelDriven接口后,会先调用getModel方法,再进行属性的填充。为什么在getModel方法内只是简单的生成一个对象呢?因为这个对象等一下要被拦截器填充属性。
Preparable
在一个web应用中,不可能只有数据从前台传向后台,也会有大量的数据从后台传往前台,那么后台的数据往往是从数据库查询出来的,这时候就要去实现preparable接口。动作其实是前后台数据交互的一个中转站,Preparable接口原型:
public interface Preparable {
public void prepare() throw Exception;
}
这里做一个查询所有系统用户的例子
public class ListAction extends ActionSupport implements Preparable {
private List<User> users;
public void prepare() throws Exception {
users = UserDAO.list("from User");
}
//...getter and setter
}
这样在前台再利用struts标签库<s:iterator value="[0].users" var="user">来遍历输出动作内的users属性。
总结
其实上述的ModelDriven接口和Preparable接口,如果实现了,struts是分别通过使用ModelDriven拦截器和Preparable拦截器来完成任务的。最后我们需要知道的还要一点,就是prepare方法和getModel方法的调用顺序。两者的调用都在动作的属性注入之前,换句话说,就是你的Action类在调用这两个方法的时候,属性都是没有准备好的(如果是引用类型话,值为null;如果是值类型的话,值为该值类型默认值)。