OGNL表達式
Struts2的一個關鍵特性就是它可以對Action攜帶的數據進行讀寫訪問,例如在前面我們在表單中使用username指定數據傳遞給Action的username屬性,在<s:property>元素中使用username來獲取用戶的名字,這是通過表達式語言(Expression Language,EL)來實現的,這種表達式語言就是OGNL。
OGNL的全稱是Object Graph Navigation Language(對象圖導航語言),它是一種強大的表達式語言,讓你通過簡單一致的表達式語法來讀取和設置Java對象的屬性值,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉換等功能。
一、為什麽要使用OGNL
視圖層的表達式語言通常是用來簡化數據的訪問操作,取代Java腳本代碼,提供更清晰的視圖層實現。例如,在JSP頁面中使用JSP2.0內置的表達式語言獲取user對象的username屬性,可以簡寫為${user.username},如果換作Java腳本代碼,則需要寫為:
<%@ page language="java" import="java.util.*,com.bim.pojo.User" pageEncoding="gbk"%>
<%
User user = (User)request.getAttribute("user");
String username = user.getUsername();
out.print(username);
%>
哪一種方法更為簡捷,相信大家已經一目了然了。
既然JSP2.0已經內置了一種表達式語言,那麽為什麽還要使用OGNL呢?
相對於其它的表達式語言而言,OGNL的功能更為強大,它提供了很多高級而必須的特性,例如強大的類型轉換功能,靜態或實例方法的執行,跨集合投影(projection),以及動態lambda表達式定義等。
二、 OGNL的原理--ActionContext
ActionContext:是Struts的核心數據區,是Action和頁面進行數據交換的“共享數據區”,也叫做Action的OGNL上下文
(補充:上下文是一種非常泛化的概念,大致意思就是“與現在這個工作相關的周圍環境”。一般存儲了該環境的一些屬性值。 )
ActionContext的結構:包含值棧和非值棧。當Action被請求時會被創建Action對象,且會把該對象放到值棧中。
值棧的概念:值棧是OGNL表達式的根對象; Struts總是將當前訪問的Action對象存放在棧頂;OGNL表達式對值棧中的任何對象直接訪問,而不需要使用“#”標記 (Struts提供了一個特殊的OGNL PropertyAccessor接口,此接口可以自動查找值棧內的、從棧頂到棧底的所有對象,直到找到對象為止 )
怎麽訪問值棧中的值:根對象可以缺省#。OGNL直接訪問屬性:user.userName
怎麽訪問非值棧區的中的值: #key,如#request.loginID
根對象的屬性直接訪問案例
userInert.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <[email protected] prefix="s" uri="/struts-tags"%> <% String path = request.getContextPath();%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘MyJsp.jsp‘ starting page</title> </head> <body> <form action="userAction" method="post"> <table> <tr> <td> 用戶名: </td> <td> <input type="text" name="user.userName"> </td> </tr> <tr> <td> 用戶所在組名: </td> <td> <input type="text" name="user.group.groupName"> </td> </tr> <tr> <td> 用戶所在組的機構編號: </td> <td> <input type="text" name="user.group.org.orgId"> </td> </tr> <tr> <td> 用戶所在組的機構名字: </td> <td> <input type="text" name="user.group.org.orgName"> </td> </tr> <tr> <td> <input type="submit" name="submit" value="添加"> </td> <td> <input type="reset" name="reset" value="取消"> </td> </tr> </table> </form> </body> </html>
|
userShow.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <[email protected] prefix="s" uri="/struts-tags"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘userShow.jsp‘ starting page</title> </head> <body> <s:debug></s:debug> <form action="userAction" method="post"> <table> <tr> <td> 用戶名: </td> <td> <s:property value="user.userName" /> </td> </tr> <tr> <td> 用戶所在組名: </td> <td> <s:property value="user.group.groupName" /> </td> </tr> <tr> <td> 用戶所在組的機構編號: </td> <td> <s:property value="user.group.org.orgId" /> </td> </tr> <tr> <td> 用戶所在組的機構名字: </td> <td> <s:property value="user.group.org.orgName" /> </td> </tr> <tr> <td> <input type="submit" name="submit" value="確認"> </td> <td> <input type="reset" name="reset" value="取消"> </td> </tr> </table> </form> <br> </body> </html>
|
Struts.xml
<action name="userAction" class="com.inspur.actions.UserAction"> <result name="show">/user/userShow.jsp</result> </action> |
Web.xml
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
userAction.java
package com.inspur.actions; import com.inspur.pojo.User; import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport{ private User user;
public User getUser() { return user; }
public void setUser(User user) { this.user = user; } @Override public String execute() throws Exception{ return "show"; } }
|
User.java
package com.inspur.pojo; public class User { private String userName; private Group group; get/set…… }
|
Ogr.java
package com.inspur.pojo; public class Org { private String orgId; private String orgName; get/set…… }
|
Group.java
package com.inspur.pojo; public class Group { private String groupName; private Org org; get/set…… } |
非根對象的屬性使用“#”訪問 案例(只寫出了部分代碼)
Login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <[email protected] prefix="s" uri="/struts-tags" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>login page</title> </head> <body> <form action="loginAction"> <font color="red"><s:property value="#request.msg"/></font> <table align="center"> <tr><td>用戶名:<input type="text" name="uname"></td></tr> <tr><td>密 碼:<input type="password" name="upass"></td></tr> <tr><td><input type="submit" value="登錄"></td></tr> </table> </form> </body> </html> |
LoginAction.java
public String login(){ //第一種方式:actioncontext類 ActionContext context = ActionContext.getContext(); Map<String, String> requestMap = (Map<String, String>) context.get("request"); Map<String, Object> sessionMap = (Map<String, Object>) context.getSession(); if("ross".equals(this.uname) && "111".equals(this.upass)){ sessionMap.put("uname", uname); return SUCCESS; }else{ requestMap.put("msg", "登錄名或密碼錯誤"); return ERROR; } } |
Index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <[email protected] prefix="s" uri="/struts-tags" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用戶登錄成功界面</title> </head> <body> <p> 歡迎您,<s:property value="#session.uname"/>,用戶登錄成功! </p> </body> </html>
|
Struts.xml
<!-- 配置請求和Action組件的映射關系 --> <action name="loginAction" class="com.inspur.actions.LoginAction" method="login"> <result name="success">/index.jsp</result> <result name="error">/login.jsp</result> <result name="input">/login.jsp</result> </action> |
三、OGNL訪問數組、list、map、set
訪問數組元素:array[0]
訪問List元素:{‘name1‘,‘name2‘}[0]
訪問map元素:mymap[‘key’]或者mymap.key
訪問set中元素:userSet
案例代碼:
頁面生成數組和list: <tr> <td>用戶的愛好: </td> <td> 籃球<input type="checkbox" name="likes" value="籃球"> 足球<input type="checkbox" name="likes" value="足球"> 羽毛球<input type="checkbox" name="likes" value="羽毛球"> </td> </tr> <tr> <td>用戶熟悉的計算機語言: </td> <td> Java<input type="checkbox" name="language" value="java"> c<input type="checkbox" name="language" value="c"> c#<input type="checkbox" name="language" value="c#"> </td> </tr>
Action裏: private String likes[]; private List<String> language; private Map<String,String> books = new HashMap<String,String>(); private Set<String> set = new HashSet<String>(); get/set…… public String execute() throws Exception{ books.put("1","紅樓夢"); books.put("2","三國演義"); set.add("tom"); set.add("joy"); return "show"; }
頁面顯示 數組: 取所有元素<s:property value="likes" /> 取第一個元素<s:property value="likes[0]" />
List: 取所有元素<s:property value="language" /> 取第一個元素<s:property value="language[0]" />
Map: 取所有元素<s:property value=" books" /> 取第一個元素<s:property value=" books[‘1‘]" /> <p><s:property value="books.1" /></p> 取所有key值<p><s:property value="books.keys" /></p> 取所有value值<p><s:property value="books.values" /></p>
Set: 取所有set值<p><s:property value="set" /></p> 取set大小<p><s:property value="set.size" /></p> |
四、投影和選擇
投影:OGNL提供了一種簡單的方式在一個集合中對每一個元素調用相同的方法,或者抽取相同的屬性,並將結果保存為一個新的集合,稱為投影。例如,users是一個包含了user對象的列表,那麽#users.{name}將返回所有人的名字和列表。在投影期間,使用#this變量來引用叠代中的當前元素
選擇:OGNL提供了一種簡單的方式來使用表達式從集合中選擇某些元素,並將結果保存到新的集合中,稱為選擇。如#users.{?#this.salary>3000}將返回薪水大於3000 的所有人的列表。#users.{^#this.salary>3000}將返回第一個薪水大於3000人。#users.{$#this.salary>3000}將返回最後一個薪水大於3000的人。
案例
//Action裏面定義一個list放入user對象: private List<User> userList = new ArrayList(); //給user對象添加一個年齡屬性,並書寫對應構造方法 userList.add(new User("rechel",28)); userList.add(new User("joy",32));
頁面顯示: <h4>訪問類方法</h4> <s:property value="new com.inspur.actions.UserAction().showString()"/> <h4>選擇所有用戶的名字</h4> <s:property value="userList.{userName}"/> <!-- 驗證--> <hr> <h4>選擇年齡>30的用戶信息</h4> <s:property value="userList.{?#this.age>30}"/> <h4>選擇年齡>30的用戶信息中用戶名</h4> <s:property value="userList.{?#this.age>30}.{userName}"/> <h4>選擇第一個年齡>30的用戶信息中用戶名</h4> <s:property value="userList.{^#this.age>30}.{userName}"/> <h4>選擇最後一個年齡>30的用戶信息中用戶名</h4> <s:property value="userList.{$#this.age>30}.{userName}"/> |
OGNL表達式