OGNL 表达式/ValueStack
文章目錄
- OGNL 是干什么用的
- 示例代碼一
- 示例代碼二
- 使用OGNL獲取JavaBean對象的屬性值
- 獲取集合屬性中元素的屬性的值
- XWork 中對 OGNL 的擴展
- 示例代碼
- Struts2 對 OGNL 的封裝
- OGNL 可以用在哪些地方
- OGNL 的結構示意圖
- Struts 2 如何改造 OGNL
- OGNL 如何將請求參數的值賦給 Action 對象的屬性?
- OGNL 如何獲取屬性值?
OGNL 是干什么用的
OGNL 中文名稱叫“對象圖形導航語言”,類似于 el 表達式,是表達式語言中的一種。
標準的 Ognl 涉及到 3 個概念:Ognl 引擎、root 對象、context 對象。
root 對象:Ognl 操作的對象,其實就是一些類似 JavaBean 的對象,含有 setter/getter 方法。
context 對象:就是一個Map,用于存放一個和整個系統都相關的公共數據。
當有了 Ognl 引擎,我們就可以訪問各種各樣的 root 對象(比如 Foo 對象、Emp 對象、Dept 對象等),在訪問中有一些數據是每一次訪問都需要用到的,這些數據就可以保存在 context 對象中。
ognl.jar 工具包提供了一個 ognl 引擎,這個引擎會解析 ognl 字符串表達式,從而讓 ognl 引擎去讀取和設置對象的屬性。
把 Java 對象看成一張地圖,如果這個 Java 對象的屬性很多而且層次復雜,例如屬性值是對象,這個對象又是集合,集合中又都是集合,里面的集合中的元素是對象,對象又有屬性,屬性值又是對象,這樣的結構相當復雜,如果你要去訪問其中的屬性值,ognl 可以提供類似地圖導航儀的功能幫助我們找到指定的屬性值或者方法
示例代碼一
Bar:
package priv.lwx.jstl.bean;/*** description** @author liaowenxiong* @date 2022/2/12 15:44*/public class Bar {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} }BarTest:
package priv.lwx.jstl.bean;import ognl.Ognl; import ognl.OgnlException; import org.junit.jupiter.api.Test;import java.util.HashMap; import java.util.Map;/*** description** @author liaowenxiong* @date 2022/2/12 15:45*/public class BarTest {@Testpublic void test() throws OgnlException {// 自定義一個context對象Map ctx = new HashMap<>();ctx.put("num", 10);// root對象Bar root = new Bar();root.setName("bar");System.out.println(Ognl.getValue("name", root));//不加"#",表示從業務對象root中取數據System.out.println(Ognl.getValue("name", ctx, root));//加"#",表示從公共對象context中取數據System.out.println(Ognl.getValue("#num", ctx, root));} }示例代碼二
使用OGNL獲取JavaBean對象的屬性值
Foo:
package priv.lwx.jstl.bean;import java.util.List; import java.util.Map;/*** description** @author liaowenxiong* @date 2022/2/11 22:10*/public class Foo {private Integer id;private String name;private String[] array;private List<String> list;private Map<String, String> map;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String[] getArray() {return array;}public void setArray(String[] array) {this.array = array;}public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;} }FooTest:
package priv.lwx.jstl.bean;import ognl.Ognl; import org.junit.jupiter.api.Test;import java.util.Arrays; import java.util.HashMap;/*** 使用OGNL獲取JavaBean對象的屬性值** @author liaowenxiong* @date 2022/2/11 22:13*/public class FooTest {@Testpublic void test() throws Exception {Foo foo = new Foo();foo.setId(100);foo.setName("Java");foo.setArray(new String[]{"one", "two", "three"});foo.setList(Arrays.asList("A", "B", "C"));HashMap<String, String> map = new HashMap<>();map.put("one", "Java");map.put("two", "JavaJava");map.put("three", "JavaJavaJava");foo.setMap(map);/*** Ognl引擎訪問對象的格式:* Ognl.getValue("OGNL表達式", root對象); root對象是Ognl要操作的對象**/System.out.println(Ognl.getValue("id", foo));System.out.println(Ognl.getValue("name", foo));// 獲取數組、集合中指定下標值的元素(root對象的數組和集合屬性)System.out.println(Ognl.getValue("array[1]", foo));System.out.println(Ognl.getValue("list[1]", foo));// 獲取Map集合中的數據(root對象的Map屬性)System.out.println(Ognl.getValue("map.one", foo));System.out.println(Ognl.getValue("map['two']", foo));// 基本運算System.out.println(Ognl.getValue("id+100", foo));// System.out.println(Ognl.getValue("\"What is \"+name", foo));// System.out.println(Ognl.getValue("\'What is \'+name", foo));System.out.println(Ognl.getValue("'What is '+name", foo));System.out.println(Ognl.getValue("'name:'+name+' id:'+id", foo));System.out.println(Ognl.getValue("id>50", foo));// 調用方法System.out.println(Ognl.getValue("name.toUpperCase()", foo));System.out.println(Ognl.getValue("list.size()", foo));// 方法的參數也可以使用屬性System.out.println(Ognl.getValue("map.three.lastIndexOf(name)", foo));// 調用靜態方法,以取出的屬性值作為參數System.out.println(Ognl.getValue("@java.util.Arrays@toString(array)", foo));// Ognl中只能創建List對象和Map對象// 創建List對象Object obj = Ognl.getValue("{1,2,3}", null);System.out.println(obj.getClass().getName());System.out.println(obj);// 創建Map對象obj = Ognl.getValue("#{'one':'Java','two':'JavaJava'}", null);System.out.println(obj.getClass().getName());System.out.println(obj);} }獲取集合屬性中元素的屬性的值
Emp:
package priv.lwx.jstl.bean;import java.math.BigDecimal; import java.util.Date;/*** description** @author liaowenxiong* @date 2022/2/12 13:40*/public class Emp {private Integer id;private String name;private BigDecimal salary;private Date hireDate;public Emp() {}public Emp(Integer id, String name, BigDecimal salary, Date hireDate) {this.id = id;this.name = name;this.salary = salary;this.hireDate = hireDate;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public BigDecimal getSalary() {return salary;}public void setSalary(BigDecimal salary) {this.salary = salary;}public Date getHireDate() {return hireDate;}public void setHireDate(Date hireDate) {this.hireDate = hireDate;} }Dept:
package priv.lwx.jstl.bean;import java.util.List;/*** description** @author liaowenxiong* @date 2022/2/12 13:39*/public class Dept {private Integer id;private String name;private List<Emp> empList;public Dept() {}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Emp> getEmpList() {return empList;}public void setEmpList(List<Emp> empList) {this.empList = empList;} }DeptTest:
package priv.lwx.jstl.bean;import ognl.Ognl; import ognl.OgnlException; import org.junit.jupiter.api.Test;import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List;/*** 獲取集合屬性中元素的屬性的值** @author liaowenxiong* @date 2022/2/12 14:49*/public class DeptTest {@Testpublic void test() throws OgnlException {Dept dept = new Dept();List<Emp> emps = new ArrayList<>();emps.add(new Emp(100, "emp1", new BigDecimal(10000), new Date()));emps.add(new Emp(200, "emp2", new BigDecimal(15000), new Date()));emps.add(new Emp(300, "emp3", new BigDecimal(12000), new Date()));dept.setEmpList(emps);dept.setName("dept1");// 獲取集合屬性中元素的屬性的值String name = (String) Ognl.getValue("empList[0].name", dept);BigDecimal salary = (BigDecimal) Ognl.getValue("empList[0].salary", dept);System.out.println("name:" + name + "," + "salary:" + salary);/*** list.{attr}表示把list中的每一個元素的attr屬性值取出,組合為一個ArrayList,并返回*/Object obj = Ognl.getValue("empList.{salary}", dept);System.out.println(obj.getClass().getName());System.out.println(obj);// 過濾(不常用,理解即可)// 找出薪水大于12000的員工姓名obj = Ognl.getValue("empList.{?#this.salary >= 12000}.{name}", dept);System.out.println(obj.getClass().getName());System.out.println(obj);} }XWork 中對 OGNL 的擴展
上面關于 OGNL 的應用是標準的、通用的用法。而在 XWork 中,OGNL 操作的對象不再是簡單的 JavaBean 對象,而是一個 CompoundRoot 對象,而這個 CompoundRoot 實際上是繼承自 CopyOnWriteArrayList,所以 CompoundRoot 對象其實就是集合。
CompoundRoot 的數據存取規則參照“棧”的規則,在這個對象中可以存放多個 JavaBean 對象,如果 OGNL 表達式是 “name”, 會從 CompoundRoot 的棧頂開始依次查找含有 name 屬性的對象,找到了就不再繼續查找,而是調該對象的 getName() 方法獲取屬性 name 的值。
示例代碼
Bar:
package priv.lwx.struts2.ognl.entity;/*** description** @author liaowenxiong* @date 2022/2/12 16:43*/public class Bar {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} }BarTest:
package priv.lwx.struts2.ognl.entity;import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor; import com.opensymphony.xwork2.util.CompoundRoot; import ognl.Ognl; import ognl.OgnlException; import ognl.OgnlRuntime; import org.junit.Test;/*** description** @author liaowenxiong* @date 2022/2/12 16:44*/public class BarTest {@Testpublic void test() throws OgnlException {// 創建一個CompoundRoot對象CompoundRoot root = new CompoundRoot();Bar bar1 = new Bar();bar1.setName("bar1");root.push(bar1);Bar bar2 = new Bar();bar2.setName("bar2");root.push(bar2);// 定制OGNL的Root機制為CompoundRoot機制OgnlRuntime.setPropertyAccessor(CompoundRoot.class,new CompoundRootAccessor());String name = (String) Ognl.getValue("name", root);System.out.println(name);} }Struts2 對 OGNL 的封裝
Struts2 是在 XWork 的基礎上進行擴展得到的框架,而 Struts2 在 XWork 對 Ognl 進行擴展的基礎上,又進行了擴展。將 CompoundRoot 對象和 context 對象封裝到 ValueStack 對象中。
Struts2 在請求到來時,首先會創建一個 ValueStack,接著再創建 Action 對象。Struts2 會把當前被請求的 Action 放入 CompoundRoot 對象的棧頂,并把內部創建的 PageContext、Request、Session、ServletContext 等對象的引用地址全部存放在 context 對象中。
Struts2 會把 ValueStack 存放在 Request 中,屬性名稱為 struts.valueStack。
我們可以通過 Ognl 表達式訪問 CompoundRoot 對象棧頂的 Action。
可以在 JSP 文件中使用 Struts2 的 <s:debug/> 標簽來查看 ValueStack 的內容:
<%@ page import="java.util.*" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/struts-tags" prefix="s" %> <html> <head><title>Title</title> </head> <body> <%--s:debug標簽用于看valueStack,用于調試--%> <s:debug/> </body> </html>OGNL 可以用在哪些地方
ognl 是一種字符串表達式,在 Java 語境中和 HTML 語境中均可以使用,但是在 HTML 語境中使用,必須結合Struts2 的標簽來使用,無法獨立使用。
OGNL 的結構示意圖
根據 OGNL 表達式去 Root 區或者 Context 區找數據。訪問不同區域的數據,OGNL 表達式的語法有區別,Context 區需要在 key 前面加上 # 才能訪問。
Struts 2 如何改造 OGNL
Struts 2 把 OGNL 工具中的結構改動了一下,把原來 Root 區換成 ObjectStack 區,這樣就可以放入更多的 Object 對象。
ValueStack 有兩個屬性 root 和 context,root 是 CompoundRoot 實例,而 CompoundRoot 是繼承自 ArrayList 的子類,context 是 ActionContext 的實例,而 ActionContext 是 OgnlContex 的子類,OgnlContext 是 Map 的實現類。
對象 context 中有個屬性,名稱也叫 root,該屬性也引用 CompoundRoot 實例。
請求到達 Struts 2 的控制器時,ValueStack 對象就創建出來了。
OGNL 如何將請求參數的值賦給 Action 對象的屬性?
先從 Request 對象獲取請求參數的值,然后執行以下的代碼:
ognl.setValue("name",action,"liaowenxiong")上面的代碼,ognl 表達式會定位到屬性 name,然后把字符串“liaowenxiong”賦值給屬性 name。
OGNL 如何獲取屬性值?
ValueStack vs = ActionInvocation.getStack(); vs.findValue("ognl表達式"); vs.findValue("imageStream"); ognl.geValue("imageStream");總結
以上是生活随笔為你收集整理的OGNL 表达式/ValueStack的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端 JS 如何在一个页面中局部加载其它
- 下一篇: 嵌入式linux和linux区别(lin