Strus2在获取表单数据的时候有两种方式:属性驱动模式和模型驱动模式,使用属性驱动模式,需要在Action中声明这些属性,并提供属性的getter和setter方法,这样从前台传过来的参数就会自动set到你声明的属性中。但这种方式不好的地方在于,如果实体属性很多的话,就需要声明一大堆属性以及get(),set()方法。
不过不要紧,Struts2可以采用类似于Struts1中的ActionForm方式收集数据,这样方式叫ModelDriven模式,这种模式会使用咱们定义好的JavaBean来封装这些请求参数,大大减少了JSP和Action的代码。
另外,和Struts1的ActionForm方式不同的是,Struts2中实体类Model不用继承任何父类,而在Struts1中每个Model都必须要继承ActionForm父类,显然这样侵入性更小了。
下面就来看看如何实现ModelDriven(模型驱动模式)?以及ModelDriven的原理解析。
ModelDriven实战
下面以一个示例介绍ModelDriven的使用。
一共需要如下三步:
* 创建User
* Action需要实现ModelDriven接口
* 实现getModel()方法,返回Bean对象
创建User实体
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserAction的部分代码
public class LoginAction implements Action, ModelDriven<User> {
private User user = new User();
public String execute() throws Exception {
if ("admin".equals(user.getUsername()) && "admin".equals(user.getPassword())) {
return SUCCESS;
}else {
return ERROR;
}
}
public User getModel() {
return user;
}
}
然后在struts.xml的配置文件中配置好Action即可,就这么简单。
ModelDriven原理
ModelDriven原理通过两部分介绍
第一部分:拦截器ModelDriven(ModelDrivenInterceptor),它是Struts2缺省拦截器链的一部分,当一个请求经过ModelDrivenInterceptor的时候,在这个拦截器中,会判断当前要调用的Action对象是否实现了ModelDriven接口,如果实现了这个接口,则调用getModel()方法,并将model对象(本例是user对象)压入ValueStack的对象栈,此时Model对象就放在了对象栈的栈顶。
第二部分:拦截器params(ParametersInterceptor),他的作用是将表单的字段映射到ValueStack的对象栈中的对象的各个属性中,映射顺序是从栈顶开始,依次往下,因为此时ValueStack的栈顶元素是刚被压入的Model(本例为User)对象,所以该Model将被首先填充,如果某个字段在Model里没有匹配的属性,Params拦截器将会匹配ValueStack中的下一个对象,直到找到匹配为止。如果没有匹配的对象属性,那么这个字段就会放到ValueStack的map中统一存储。
ModelDriven的原理就是通过这两个拦截器实现的。
下面是该拦截器intercept方法源码:
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();//获取当前正在执行的Action
//如果Action实现了ModelDriven接口
if (action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();//通过getModel方法获取model
if (model != null) {//如果model不为null则把model压入值栈
stack.push(model);
}
if (refreshModelBeforeResult) {//在执行Result之前是否要更新model对象,默认为false
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();//调用下一个拦截器
}
小结
相对于属性驱动模式,模型驱动模式的好处不言而喻,它使得Action代码更加简洁,让我们的Action更加专注于是控制业务逻辑。但是任何事物都没有绝对的好坏之分,当Model中没有封装我们需要的个别特殊属性时,还是需要使用属性驱动模式,所以实际项目中一般会交叉应用。