Struts2中的OGNL表达式和ValueStack

文章目录

  • OGNL 是干什么用的
    • 示例代码一
    • 示例代码二
      • 使用OGNL获取JavaBean对象的属性值
      • 获取集合属性中元素的属性的值
  • XWork 中对 OGNL 的扩展
    • 示例代码
  • Struts2 对 OGNL 的封装
  • OGNL 可以用在哪些地方
  • OGNL 的结构示意图
  • XWork 对 OGNL 改造后的结构示意图
  • Struts 2 对 OGNL 改造后的结构示意图
  • OGNL 如何将请求参数的值赋给 Action 对象的属性?
  • OGNL 如何获取属性值?
  • 参考

OGNL 是干什么用的

Object Graph Navigation Language,中文名叫对象导航图语言,缩写为 OGNL,类似于 EL 表达式,是表达式语言中的一种。

标准的 OGNL 涉及到 3 个概念:OGNL 引擎、JavaBean 对象、Map 对象。

JavaBean 对象:OGNL 操作的对象,这些对象中含有 setter/getter 方法。通常取名为 root。
Map 对象:用于存放和整个系统有关的公共数据,通常取名为 context。

当有了 OGNL 引擎,我们就可以访问各种各样的 root 对象(比如 Foo 对象、Emp 对象、Dept 对象等),在访问中有一些数据是每一次访问都需要用到的,这些数据就可以保存在 context 对象中。

ognl.jar 工具包提供了一个 OGNL 引擎,这个引擎会解析 OGNL 字符串表达式,从而让 OGNL 引擎去读取和设置对象的属性。

把 Java 对象看成一张地图,如果这个 Java 对象的属性很多而且层次复杂,例如属性值是对象,这个对象又是集合,集合中又都是集合,里面的集合中的元素是对象,对象又有属性,属性值又是对象,这样的结构相当复杂,如果你要去访问其中的属性值,OGNL 可以提供类似地图导航仪的功能帮助我们找到指定的属性值或者方法。

支持类的静态方法调用和静态变量的访问。表达式的格式为:@[类全名(包括包路径)]@[方法名 | 值名]

例如:

调用类的静态方法:

@java.lang.String@format('foo %s', 'bar')

访问类的静态变量:

@tutorial.MyConstant@APP_NAME

示例代码一

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,而 CopyOnWriteArrayList 实现自 List,所以 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 对象和 Map 对象封装到 ValueStack 对象中。

Struts2 在请求到来时,首先会创建一个 ValueStack,接着再创建 Action 对象。Struts2 会把当前被请求的 Action 放入 CompoundRoot 对象的栈顶,请求结束后,Action 对象会被清除掉。并把内部创建的 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 语境中和 JSP 语境中均可以使用,但是在 JSP 语境中使用,必须结合Struts2 的标签来使用,无法独立使用。

OGNL 的结构示意图

在这里插入图片描述

XWork 对 OGNL 改造后的结构示意图

在这里插入图片描述

Struts 2 对 OGNL 改造后的结构示意图

在这里插入图片描述

ValueStack 有两个属性 root 和 context,root 是 CompoundRoot 实例,而 CompoundRoot 是继承自 CopyOnWriteArrayList 的子类,context 是 ActionContext 的实例,而 ActionContext 是 OgnlContex 的子类,OgnlContext 是 Map 的实现类。

对象 context 中有个属性,名称也叫 root,该属性也引用 CompoundRoot 实例。

请求到达 Struts 2 的控制器时,ValueStack 对象就创建出来了,接着创建 Action 对象,并将 Action 对象存储到 ValueStack 中的成员变量 root 所指向的 CompoundRoot 对象中。

OGNL 如何将请求参数的值赋给 Action 对象的属性?

先从 Request 对象获取请求参数的值,然后执行以下的代码:

Ognl.setValue("name",action,"liaowenxiong")

setValue 方法会查找 action 对象是否存在 setName 方法,存在在调用该方法,并将 liaowenxiong 作为参数传入该方法中,如果不存在则啥也不做。

OGNL 如何获取属性值?

ValueStack vs = ActionInvocation.getStack();
vs.findValue("ognl表达式");
vs.findValue("imageStream");
Object obj = Ognl.getValue("OGNL表达式",root,context);

参考

https://www.cnblogs.com/cenyu/p/6233942.html
https://tech.souyunku.com/?p=23119
https://www.cnblogs.com/dkz1/p/8024675.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333477.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matlab画图五角星标记,Matlab---画图线型、符号及颜色

Matlab 画图线形、颜色、数据点形状的选择1&#xff0c;线形- Solid line (default)-- Dashed line: Dotted line-. Dash-dot line2&#xff0c;颜色r Redg Greenb Bluec Cyanm Magentay Yellowk Blackw White3&#xff0c;数据点的形状 Plus signo Circle* Asterisk. Pointx C…

php 淘宝客接口开发,如何使用PHP的curl函数调用维易淘客接口

《如何使用PHP的curl函数调用维易淘客接口》要点&#xff1a;使用curl调用维易淘客接口高佣转链维易淘客接口是用GET方式调用的&#xff0c;直接用GET调用即可&#xff0c;以下用PHP为例&#xff1a;使用curl调用维易淘客接口高佣转链&#xff1a;$apihttp://api.vephp.com/hca…

querydsl 转字符串_QueryDSL中包含通配符的字符串的精确匹配

querydsl 转字符串在我们最近的一个项目中&#xff0c;我们的客户要求一个搜索字段&#xff0c;该字段可以搜索名字&#xff0c;姓氏和电子邮件地址&#xff0c;唯一的通配符是星号“ *”&#xff0c;表示部分匹配。 听起来很简单&#xff0c;但这使我们陷入了混乱。 在我们的项…

Java中,我自己定义的某个类,去实现某个接口,是否必须实现该接口的全部抽象方法呢?

不一定&#xff0c;关键要看子类是否是抽象类。 如果子类是非抽象类&#xff0c;则必须实现接口中的所有方法&#xff1b;如果子类是抽象类&#xff0c;则可以不实现接口中的所有方法&#xff0c;因为抽象类中允许有抽象方法的存在&#xff01; 一、抽象类定义 抽象类往往用…

堆栈溢出 java_堆栈溢出回答了我们所不知道的Java首要问题

堆栈溢出 java您不应该错过的堆栈溢出问题集合&#xff1a; 这不是秘密&#xff1b; 我们都使用堆栈溢出。 它拥有生命&#xff0c;宇宙和几乎所有与代码相关的答案。 该平台为开发人员&#xff0c;工程师和其他人员提供了一个找到他们所面临问题的答案的地方&#xff0c;或者…

Java 的面向接口编程

假设有这样的代码&#xff1a; F f new G(); f.do(); f.cook(); ...F 是一个接口&#xff0c;G 是 F 的一个实现类&#xff08;也叫具体类/派生类&#xff09;。 如果现在需要另外一个实现类 H 采用其他技术实现接口 F 的所有抽象方法&#xff0c;那么只要修改一条代码&…

mysql 表数据diff,mysqldiff使用笔记

背景手上有个项目&#xff0c;有三个环境:本地开发,测试环境,线上环境&#xff0c;历史原因怀疑数据库表字段可能出现不匹配&#xff0c;所以寻找合适的工具比较数据库表结构。找到了mysqldiff。准备工具正好手上有台windows机器&#xff0c;使用windows版本测试安装mysqldiff是…

java超出gc开销_通过这5个简单的技巧减少GC开销

java超出gc开销编写代码的五种简单方法&#xff0c;可以提高内存效率&#xff0c;而无需花费更多时间或降低代码可读性 垃圾回收会为您的应用程序增加多少开销&#xff1f; 您可能不知道确切的数字&#xff0c;但您确实知道总有改进的余地。 尽管自动GC是最有效的过程&#x…

JSTL(Java 标准标签库)

文章目录JSTL 简介JSTL 可以使用在哪里JSTL 使用步骤使用标签if 语句选择语句迭代遍历语句URL重写设置属性值删除属性值异常捕获导入其它 JSP 页面重定向输出指定的值JSTL 简介 Java Standard Taglib(Java 标准标签库)。 JSTL 是一种代替 JSP 中的 Java 代码的技术。sun 公司…

php hash代码下载,PHP中的哈希表 hash_insert

[php]代码库int hash_insert(HashTable *ht, char *key, void *value){// check if we need to resize the hashtableresize_hash_table_if_needed(ht); // 哈希表不固定大小&#xff0c;当插入的内容快占满哈表的存储空间// 将对哈希表进行扩容&#xff0c; 以便容纳所有的元素…

跟踪React流–将Spring Cloud Sleuth与Boot 2结合使用

Spring Cloud Sleuth在OpenZipkin Brave的基础上增加了对Spring工具的支持&#xff0c; 从而使Spring Boot应用程序的分布式跟踪变得异常简单。 这是关于使用此出色的库添加对分布式跟踪的支持所需内容的简要介绍。 考虑两个应用程序–一个使用上游服务应用程序的客户端应用程…

JDK命令之java -- 用来执行字节码文件,即用来执行Java程序

文章目录一、命令介绍二、用法格式三、常用选项四、常用选项详解-client&#xff0c;-server-hotspot-classpath,-cp-classpath-Dvalue-verbose[:class|gc|jni]-verbose:gc-verbose:jni-version-showversion-ea[:...|:] 和 -enableassertions[:...|:]-da[:...|:] 和 -disableas…

php中双引号的区别,PHP中单引号和双引号的区别

好久没有写博客了&#xff0c;都忘了积累知识啦……现在开始全新的生活&#xff0c;重拾记录的习惯。今天要写的就是PHP中单引号和双引号的区别。在PHP中&#xff0c;我们可以使用单引号或者双引号来表示字符串。不过我们作为开发者&#xff0c;应该了解其中的区别。一、字符串…

sbe 详解_内部简单二进制编码(SBE)

sbe 详解SBE是用于金融行业的非常快速的序列化库&#xff0c;在本博客中&#xff0c;我将介绍一些使其快速发展的设计选择。 序列化的全部目的是对消息进行编码和解码&#xff0c;并且有很多可用的选项&#xff0c;例如XML&#xff0c;JSON&#xff0c;Protobufer&#xff0c;…

php调用swf文件上传,swfupload-jquery-plugin AJAX+PHP 文件上传

var listitem>file.name (Math.round(file.size/1024) KB)>>>Pending;$(#log).append(listitem);$(this).swfupload(startUpload);})//绑定开始上传文件事件.bind(uploadStart, function(event, file){$(#log li#file.id).find(p.status).text(Uploading...);$(#lo…

aws lambda使用_使用AWS Lambdas扩展技术堆栈

aws lambda使用面对现实吧。 调试性能问题很困难&#xff0c;但是更难解决。 假设您发现了有害的代码&#xff0c;这些代码正在拖慢您的应用的运行速度。 最终会有一段时间&#xff0c;您发现此代码减速是同步的或线性执行的。 解决这些有问题的代码段的最有效方法之一就是将最…

Java声明定义抽象类/接口/继承/实现

文章目录声明定义抽象类声明定义接口派生类、抽象类、接口的继承要点声明定义抽象类 public abstract class CRMSystem {public abstract Client add(Client newGuy); //添加用户方法public abstract Event add(Event e, Client guy); //重载添加事件、用户方法public abstrac…

cuba开发_使用CUBA进行开发–与Spring相比有很大的转变?

cuba开发阅读另一个供内部公司使用的Web项目的要求时&#xff0c;您&#xff08;至少是我自己&#xff09;通常会看到一个很普通的集合&#xff1a;定义明确的数据存储结构&#xff08;或有时是现有的旧数据库&#xff09;&#xff0c;大量的数据输入形式&#xff0c;非常复杂的…

imagettftext php7,mac php7 imagettftext

Mac OS X 自带PHP环境gd库安装扩展freetype问题&#xff1a; “Call to undefined function imagettftext()”解决方法&#xff1a;curl -s [http://php-osx.liip.ch/install.sh](https://link.jianshu.com/?thttp://php-osx.liip.ch/install.sh) | bash -s 7.3sudo vim ~/.ba…

图片授权模式

RM、RF、PE是3种不同的图片授权模式&#xff0c;由图片卖家设定&#xff0c;图片买家根据自己的需要来进行选择。这三种模式是图片行业在发展过程中&#xff0c;经过对图片用户需求的不断总结而确定的。摄影师可以根据自己的销售意愿&#xff0c;在编辑图片的时候&#xff0c;对…