OGNL 全称 Object-Graph Navigation Language(对象图导航语言),用来获取和设置 Java 对象属性,需要写在 Struts2 标签里才生效。
它访问的对象都放在 OGNL 的 context 里。context 是 Map,存一组 key-value,实际对应 ActionContext。
Http 请求进到 Struts2 后,框架会创建 ActionContext、ValueStack 和对应的 Action;Action 放进 ValueStack,ValueStack 再放进 ActionContext。在 JSP 里访问 context 数据要用 #;ValueStack 是根对象,访问 Action 属性不用加 #。
一、OGNL 介绍
记住这条链就够用:
ognl 上下文(context) <=> ActionContext <- ValueStack <- action 对象
值栈 ValueStack 里常见对象:action 实例、request、session、application、response、parameters 数组、attr 等。
二、主要功能
-
-
附带便捷能力:方法调用、静态方法和属性调用、数值运算等。
三、如何取数据
OGNL 从两个地方取数据:一是 Action 实例属性,二是 ValueStack(值栈)。会先从前一个取,取不到再到值栈。值栈里存了 request、session、application、response、action 实例、parameters 数组等。
1. 取 Action 实例的属性
Action 属性可以直接在 Struts2 标签里用属性名拿到,不要加 #:
<s:property value="name"/>
<s:property value="user.password"/>
2. 取 ValueStack 中的数据
Struts2 提供三种写法:#、%{}、${}。# 和 %{} 要放到 Struts2 标签里才生效:
<s:property value="#name"/>
<s:property value="%{'hello struts2'}"/>
% 的用途是:标签属性被当成字符串时,告诉运行环境 %{} 里是 OGNL 表达式:
<s:url value="%{#myMap['key1']}"/>
最常用的还是 #:
| 写法 |
含义 |
| #session.name2 / #application.name3 |
取 session、application 里的 attribute,要加前缀 |
| #name |
取 request 范围 attribute,不要加 request 前缀(加上反而取不到);默认只从 request 取,不会自动再到 session / application |
| #parameters.name[0] |
取请求参数,必须加 parameters,结果是数组,第一项加下标;相当于 request.getParameterValues(“name”)[0] |
| #attr.name |
按 request → session → application 顺序找 attribute,找到就停 |
| #{‘foo1′:’bar1’} |
用 # 构造 Map |
| books.{?#this.price<100} |
过滤和投影(projecting)集合 |
<s:property value="#session.name2"/>
<s:property value="#application.name3"/>
<s:property value="#name"/>
<s:property value="#parameters.name[0]"/>
<s:property value="#attr.name"/>
<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<s:property value="#foobar['foo1']" />
<s:radio list="#{'0':'男','1':'女'}" name="sex" label="性别" value="%{user.sex}"></s:radio>
$ 有两种用途:国际化资源文件里引用 OGNL;以及在 Struts2 配置文件里引用:
<action name="saveUser" class="userAction" method="save">
<result type="redirect">listUser.action?msg=${msg}</result>
</action>
四、代码实例
Action 侧往 context / 值栈里塞数据:
/**
* 通过 ognl 表达式从 ognl 上下文(context)获取值显示到 jsp 页面
* ognl 表达式只使用在 struts2 标签中
* ognl 上下文(context) <=> ActionContext <- ValueStack <- action 对象
*
* 值栈 ValueStack 包含如下对象:
* action 实例、request、session、application、response、parameters 数组 attr...
*/
public class OgnlAction extends BaseServletAction {
private String name;
private User user = new User();
private List<User> list = new ArrayList<User>();
@Override
public String execute() throws Exception {
ActionContext actionContext = ActionContext.getContext();
ValueStack valueStack = actionContext.getValueStack();
valueStack.push("ognl名称");
name = "张三";
user.setName("李四");
user.setPassword("abcd");
list.add(new User("王二", "456"));
list.add(new User("小明", "123"));
actionContext.put("number", "request=1001");
session.setAttribute("age", "session=23");
return SUCCESS;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
public List<User> getList() { return list; }
public void setList(List<User> list) { this.list = list; }
}
JSP 侧对照取值:
<body>
<!-- 显示 valuestack 值栈内容 -->
<s:property value="name"/>
<s:property value="user.name"/>
<s:property value="user.password"/>
<hr>
<s:iterator value="list" var="u">
<s:property value="#u.name"/><br>
</s:iterator>
<s:property value="#number"/>
<s:property value="#session.age"/>
<%-- ognl 从 action 对象中取属性值 --%>
<s:property value="name" default="默认值" />
<s:property value="user.username" default="默认值" />
<br>用户名:
<s:property value="userLists[1].username" default="默认值" />
密码:
<s:property value="userLists[1].password" default="默认值" />
<br>
<%-- ognl 从 ServletAPI request session .... 对象中取属性值 --%>
<s:property value="#request.age" default="request默认值" />
<s:property value="#session.sex" default="session默认值" />
<!-- request > session > application -->
<s:property value="#attr.age" default="attr默认值" />
<%-- ognl 从 valueStack 中取属性值 --%>
<s:property value="stack2.username" default="valueStack默认值" />
${stack2.password}
<br> ${user.username}
<br>
<s:form action="ognltag.jsp" method="post">
<s:textfield label="用户名" name="user_name"></s:textfield>
<s:password label="密码" name="pass_word"></s:password>
<s:submit value="提交"></s:submit>
</s:form>
<s:property value="#parameters.user_name"/>
<s:property value="#parameters.pass_word"/>
<s:debug></s:debug>
</body>
一句话总结:Action 属性直接写属性名,context 里的数据加 #;#session / #parameters / #attr 各管一层范围,%{} 只在标签属性被当成字符串时把 OGNL 打开。