在J2EE课上了解了更先进的ModelDriven(模型驱动)方式,也对Struts2的这三种传值方法有了更深刻的认识。
ModelDriven的优势
之前学过直接的属性注入,就是在页面中提交Action所组合的属性的名字;学过域模型注入,就是在页面中提交Action所组合的全小写对象的对象名.属性名
,这个对象也叫领域对象,可以理解成带领自己的这几个域的对象。
在属性注入中,如果属性非常多,比如要提交一个学生的信息,而具体是要哪些字段已经在JavaBean里写过了,在Action里却要重新写一遍,而且还要再次实现getter和setter,代码冗余严重。
在域模型注入中,确实不用再去把这个对象的属性再写一遍了,不过会增加提交页面中表单项目的name
属性的长度,比如user.userName
,而且在Action中要去实现这个对象的getter和setter,有时还是不方便。
使用ModelDriven可以解决这个问题,可以不必去写明要传给的对象名,因为这个对象就在值栈的栈顶,也不需要去在Action类中实现对象的getter和setter方法。
测试程序
login.jsp
提交页面只需要指明要提交到的Action的getModel方法实际返回的对象的属性名。因为在Struts2默认拦截器链中的ModelDrivenInterceptor
拦截器会将实现了模型驱动接口的Action的getModel()
方法返回的对象压入ValueStack
的栈顶,当从上向下扫描时就会先扫描这个对象。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ModelDriven试验</title>
</head>
<body>
<h1>使用ModelDriven模型驱动</h1>
<s:form action="main2">
猫的名字:<s:textfield name="catname" size="20"/>
<br><br>
猫的年龄:<s:textfield name="catage" size="20"/>
<s:submit value="提交"/>
</s:form>
</body>
</html>
MainAction2.java
并不能实现ModelDriven<Cat>
后再去实现ModelDriven<User>
来做到使用多个对象模型驱动,试想,只有返回值不同的getModel()
并不能共存在一个(Action)类中。
如果要做到一个Action里使用多个JavaBean的对象做模型驱动,可以考虑为几个类做继承关系,那么就只要去做父类;也可以考虑用另外一个类去组合这两个类,那么只要去做那个第三方的类。
另外,因为这个领域对象会处于值栈的栈顶,在这个Action中的其它属性和对象的属性尽量不要和模型驱动绑定的对象的属性重名,否则在没有显示指明的情况下,总是去操作栈顶(模型驱动所绑定的)对象的属性。
应当牢记,被压入值栈栈顶的总是getModel()
方法实际返回的对象。
package myAction;
import java.util.Map;
import myBean.Cat;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
//实现ModelDriven(模型驱动)的接口,为其泛型指定这个对象的实现类
@SuppressWarnings("serial")
public class MainAction2 extends ActionSupport implements ModelDriven<Cat> {
// 也需要领域对象,但要做实例化
// 可以在这里实例化,也可以在getModel方法中实例化
// 总之getModel必须返回实例化之后的领域对象,因为要往里面写值了
Cat cat = null;
@Override
public String execute() throws Exception {
// 间接访问Session,存进去
ActionContext axnctxt = ActionContext.getContext();
Map<String, Object> sssn = axnctxt.getSession();
sssn.put("CATNAME", cat.getCatname());
sssn.put("CATAGE", cat.getCatage());
return SUCCESS;
}
// 获取模型驱动的模型
// getModel必须返回实例化之后的领域对象,用三目运算做了下检查
@Override
public Cat getModel() {
return cat == null ? cat = new Cat() : cat;
}
}
main2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>成功</title>
</head>
<body>
<h1>你提交的:</h1>
<h2>猫的名字:${session.CATNAME}</h2>
<h2>猫的年龄:${session.CATAGE}</h2>
</body>
</html>
运行结果
我觉得当一个Action所组合的对象比较多时,还是使用域模型注入比较清晰。或者使用一个类去组合这些领域对象,使用领域对象+域模型注入的方式也比较清晰。不应当为本不具有继承关系的JavaBean为了模型驱动传值方便而去做继承关系。