要想理解Struts2参数接收的原理,首先需要了解OGNL的原理及OGNL跟值栈的结合。
OGNL:对象视图导航语言. 像${user.addr.name} 这种写法就叫对象视图导航.
OGNL不仅仅可以视图导航.支持比EL表达式更加丰富的功能.
OGNL的上下文对象(OGNL Context)
一、Root
任何对象都可以作为Root,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象。
二、Context
上下文环境Context是一个Map类型的对象,其储存了一系列键值对。
//准备OGNLContext
OgnlContext oc=new OgnlContext();
//准备Root
User rootUser =new User("Tom",18);
//准备Context
Map<String,User> context=new HashMap<String,User>();
context.put("user1",new User("Jack",18));
context.put("user2",new User("root",22));
//将rootUser作为root部分
oc.setRoot(rootUser);
//将context这个Map作为Context部分
oc.setValues(context);
OGNL表达式语法:
一、基本取值
1、取出root中的内容只需要直接书写对象的属性名即可:
//取出root中user对象的属性
String name=(String) Ognl.getValue("name",oc,oc.getRoot());
Interger age=(Integer) Ognl.getValue("age",oc,oc.getroot());
2.访问Context中的对象,需要使用"# "号加上对象名称,即#"对象名称"的形式。
//取出context中键为user1对象的属性
String name=(String) Ognl.getValue("#user1.name",oc,oc.getRoot());
Integer age=(Integer) Ognl.getValue("#user1.age",oc,oc.getRoot());
二、赋值
//将root中user对象的name属性赋值
Ognl.getValue("name='jerry'",oc,oc.getRoot());
//将context中user1对象的属性赋值
Ognl.getValue("#user1.name='佩奇',oc,oc.getRoot());
//将context中user1对象的属性赋值并返回值
String name=(String) Ognl.getValue("#user1.name='Giao哥',#user1.name",oc,oc.getRoot());
三、调用方法
//调用root中user对象的setName方法
Ognl.getValue("setName('路飞')",oc,oc.getRoot());
//调用context中user1对象的getName方法
String name=(String) Ognl.getValue("#user1.getName()",oc,oc.getRoot());
OGNL与Struts2的结合
一、值栈(ValueStack)
CompoundRoot root;
transient Map<String,Object> context;
public class compoundRoot extends ArrayList{
}
观察Struts2源代码可知:ValueStack也包含着两部分:root和context
ValueStack中的root实际上对应着OGNL中的root,而context则对应着OGNL中的context。
其中root是一个由ArrayList模拟的栈
接着我们来看ValueStack中栈和context各放置着什么东西。
1、默认情况下,栈(root)中放置当前访问的Action对象
2、Context放置着ActionContext
Struts2中,每次请求时都会创建一个与请求对应的ActionContext对象,ActionContext实质上是个Map,其中放置着原生ServletContext,request域,application域、session域、param参数、attr域、valueSatck(ValueStack对象与ActionContext对象是互相引用的)等对象,我们可以把他看成一个request域(Struts2中并不推荐使用原生request域)
//取得原生request域(不推荐)
Map<String,Object> requestScope=(Map<String,Object>) ActionContext.
getContext().get("request");
//直接在ActionContext中放置(推荐)
ActionContext.getContext().put("name","requestTom");
//session域=>Map
Map<String,Object> sessionScope=ActionContext.getContext().getSession();
sessionScope.put("name","sessionTom");
//application域=>Map
Map<String,Object> applicationScope=ActionContext.getContext().getApplication();
applicationScope.put("name","applicationTom")
二、参数接收
了解了OGNL与值栈的原理后,我们来了解Struts2中参数接受的原理:
1、属性驱动
前台提交:
用户名:<input type="text' name="name" />
2、对象驱动
前台提交:
用户名:<input type="text" name="user.name" />
3、模型驱动
前台提交:
用户名:<input type="text" name="name" />
其中属性驱动与对象驱动无需赘述,我们来看模型驱动的实现:
public class DemoAction extends ActionSupport implements ModelDriven<User>{
//准备user成员变量
private User user=new User();
public String execute() throws Exception{
System.out.println(user);
return SUCCESS;
}
@Override
public User getModel(){
return user;
}
}
这种做法在params拦截器赋值前将user对象压到了栈顶,因此表单页只需直接像属性驱动一样书写属性即可。
个人学习心得,难免有错误遗漏,欢迎指正讨论!