在Struts2中如何运用OGNL表达式
今天分享的是Struts2框架中的一种ognl表达式语言,主要分两个目标去学习
1.理解struts2传值的优先级
2.ognl与el的区别
一:ognl表达式语言简介
OGNL的全称是Object Graph Navigation Language(对象图导航语言),它是一种强大的表达式语言,让你通过简单一致的表达式语法来读取和设置Java对象的属性值,调用对象的方法,遍历整个对象的结构图,实现字段类型转换等功能。
1.1:简单对 对象图导航语言举例分析
假如现在项目中有两个实体类:
Class Book(书本类中有以下属性) :
private String bid;
private String bname;
private Category c;
Class Category(书籍分类有以下属性):
private String cid;
private String name;
假如我现在有一个需求:
想在同一个jsp页面中展示书籍以及书籍类别的信息,
像平时的话肯定就是写BookDao然后用list集合接收在jsp中用EL表达式输出出来
${book.bid}/${book.bname}
然而${book.c.bname} 就是对象图导航语言,
二:ognl表达式语言特点
1.支持对象方法调用,形式如:objName.methodName();
2.支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路)]@[方法名 | 值名],例如:
@java.lang.String@add( '11' , 'hahhaha' )
3.支持赋值操作和表达式串联,例如:
number=18, price=100,Total();那么返回1800;
4.访问OGNL上下文(OGNL context)其实就是Map (教室、老师、学生)和ActionContext,
OgnlContext=根对象(1)+非根对象(N)
老师:根对象 1
学生:非根对象 n
非根对象要通过"#key"访问,根对象可以省略"#key"
3.4.1:根对象和非根对象的概括
1、一个上下文中只有一个根对象
2、取跟对象的值,只需要直接通过根对象属性即可
3、非根对象取值必须通过指定的上下文容器中的#key.属性去取。
图解:
ognl取值赋值的方法:
OnglExpression类
package com.ht.text; import ognl.Ognl; import ognl.OgnlContext; import ognl.OgnlException; /** * 用于OGNL表达计算的一个工具类 * */ public class OnglExpression { private OnglExpression() { } /** * 根据OGNL表达式进行取值操作 * * @param expression * ognl表达式 * @param ctx * ognl上下文 * @param rootObject * ognl根对象 * @return */ public static Object getValue(String expression, OgnlContext ctx, Object rootObject) { try { return Ognl.getValue(expression, ctx, rootObject); } catch (OgnlException e) { throw new RuntimeException(e); } } /** * 根据OGNL表达式进行赋值操作 * * @param expression * ognl表达式 * @param ctx * ognl上下文 * @param rootObject * ognl根对象 * @param value * 值对象 */ public static void setValue(String expression, OgnlContext ctx, Object rootObject, Object value) { try { Ognl.setValue(expression, ctx, rootObject, value); } catch (OgnlException e) { throw new RuntimeException(e); } } }
四:值栈ValueStack
valueStack是struts2的值栈空间,是struts2存储数据的空间
根据栈的制度,它是先进后出的数据结构,弹夹 push/pop
之所以把它作为根对象主要是因为 放到值栈中的对象都可视为根对象
4.1:ValueStack简介
4.1.1.ValueStack是一个接口,在struts2中使用OGNL(Object-Graph Navigation Language)表达式实际上是使用实现了ValueStack接口的类OgnlValueStack.
4.1.2.ValueStack贯穿整个action的生命周期,每一个action实例都拥有一个ValueStack对象,其中保存了当前action对象和其他相关对象.
4.1.3.struts2把ValueStack对象保存在名为:struts.valueStack的request域中.即ValueStack作用域为request.当action创建的时候,ValueStack就创建了,action被销毁的时候,ValueStack就销毁了
4.1.4.ValueStack中的数据分两部分存放:root(栈结构,CompoundRoot)和context(map形式,OgnlContext)
(1)其中的root对象是CompoundRoot,CompoundRoot继承了ArrayList,提供了额外的方法:push(),和pop()方法,
用来对root对象中所包含的数据进行存取.正是由于这两个方法,CompoundRoot变成了一个栈结构. struts2中,一个请求在最终到达Action的方法之前,Action对象本身会被压入ValueStack(实际上就是放到ValueStack的CompoundRoot中),所以action对象是CompoundRoot中的一个元素.
(2)其中的context对象是OgnlContext,它实现了map接口,在valuestack的默认实现类中,即OgnlValueStack类中,
调用ongl中的方法:Ognl.createDefaultContext(..)给context赋值,此方法返回的是一个OgnlContext对象.
ValueStack内存结构图如下:
4.2 struts2中传递数据
可以使用作用域,但更多的是利用ValueStack或ActionContext;
然而作用域取值有规律的他是从小到大的
page -> request -> session -> application
ActionContext就相当于一个大容器,同一请求中只创建一个上下文;
ValueStack就是根对象容器,它的取值是从上至下的;
parameters,request ,session ,application就是非根对象容器
注意:
1、ActionContext一次请求创建一次
2、值栈取值从上往下,取到为止,如果已经拿到,不再往下找。
五:ognl与el区别
因为OGNL表达式是struts2的默认表达式语言所以只对struts2标签管用,然而el在html中也可以用
struts2标签用的都是ognl表达式语言,所以它多数都是去栈顶找值,找不到再去作用域
el却相反,它都是去map集合作用域中找
ognl的取值赋值案例示范
public class Demo1 { 2 3 /** 4 * @param args 5 * @throws OgnlException 6 */ 7 public static void main(String[] args) { 8 // 叫小李的员工 9 Employee e = new Employee(); 10 e.setName("小李"); 11 // 张经理的管理 12 Manager m = new Manager(); 13 m.setName("张经理"); 14 15 // 创建OGNL下文,而OGNL上下文实际上就是一个Map对象 16 OgnlContext ctx = new OgnlContext(); 17 18 // 将员工和经理放到OGNL上下文当中去 19 ctx.put("employee", e); 20 ctx.put("manager", m); 21 // 小李是根对象 一个公司有很多老板 只有一个员工小李 22 ctx.setRoot(e);// 设置OGNL上下文的根对象 23 24 /** ********************** 取值操作 *************************** */ 25 // 表达式name将执行e.getName(),因为e对象是根对象(请注意根对象和非根对象表达式的区别) 26 String employeeName = (String) OnglExpression.getValue("name", ctx, e); 27 System.out.println(employeeName); //小李 28 29 // 表达式#manager.name将执行m.getName(),注意:如果访问的不是根对象那么必须在前面加上一个名称空间,例如:#manager.name 30 String managerName = (String) OnglExpression.getValue("#manager.name", 31 ctx, e); 32 System.out.println(managerName); //张经理 33 34 // 当然根对象也可以使用#employee.name表达式进行访问 35 employeeName = (String) OnglExpression.getValue("#employee.name", ctx, 36 e); 37 System.out.println(employeeName); //小李 38 39 /** ********************** 赋值操作 *************************** */ 40 OnglExpression.setValue("name", ctx, e, "小明"); 41 employeeName = (String) OnglExpression.getValue("name", ctx, e); 42 System.out.println(employeeName); //小明 43 44 OnglExpression.setValue("#manager.name", ctx, e, "孙经理"); 45 managerName = (String) OnglExpression.getValue("#manager.name", ctx, e); 46 System.out.println(managerName); //孙经理 47 48 OnglExpression.setValue("#employee.name", ctx, e, "小芳"); 49 employeeName = (String) OnglExpression.getValue("name", ctx, e); 50 System.out.println(employeeName); //小芳 51 } 52 }
控制台上输出结果顺序与下面一致就对了
小李
张经理
小李
小明
孙经理
小芳
ognl在struts2中的应用
创建一个测试类
/** * 此例用于模拟struts2的值栈计算过程 * ValueStack是一个堆栈结构的容器 有压栈操作 先进后出 * @param args */ public String test1(String[] args) { ValueStack vs =ServletActionContext.getContext().getValueStack(); vs.push(new Employee("张雇员", 2000));// 1 vs.push(new Student("小明同学", "s001"));// 0 System.out.println(vs.findValue("name"));//小明 System.out.println(vs.findValue("salary2")); //2000 return "rs"; }
struts-sy.xml配置文件
<action name="/stack_*" class="com.ht.text.Demo7" method="{1}">
<result name="rs">/rs.jsp</result>
</action>
jsp中代码
<a href="${pageContext.request.contextPath }/sy/stack_test1.action?sex=nv">ognl1</a>
输出结果为
小明同学
2000
现在来用实例证明一下ValueStack有压栈,先进后出的赋值套路
创建一个类来写action代码,记得继承ModelDriven接口
private Cal cal1=new Cal(); private String num1; public String getNum1() { return num1; } public void setNum1(String num1) { this.num1 = num1; } public String accept1() { // cal使用的是ModelDriven赋值 System.out.println("cal1:"+cal1); // num使用的是get/set赋值 System.out.println("num1:"+num1); return "rs"; }
jsp代码
<a href="${pageContext.request.contextPath }/sy/demo_accept1.action?num1=20&&num2=5">accept1</a>
输出结果
值栈中cal1变量比num1变量更靠近栈顶,所以她接收到了值,但是前台参数已经赋值,所以num1没有接收到值就为null了
今日分享到此结束,谢谢观看!
推荐阅读
-
正负偏差变量 即 d2+、d2- 分别表示决策值中超出和未达到目标值的部分。而 di+、di- 均大于 0 刚性约束和目标约束(柔性目标约束有偏差) 在多目标规划中,>=/<= 在刚性约束中保持不变。当需要将约束条件转换为柔性约束条件时,需要将 >=/<= 更改为 =(因为已经有 d2+、d2- 用来表示正负偏差),并附加上 (+dii-di+) 注意这里是 +di、-di+!之所以是 +di,-di+,是因为需要将目标还原为最接近的原始刚性约束条件 优先级因素和权重因素 对多个目标进行优先排序和优先排序 目标规划的目标函数 是所有偏差变量的加权和。值得注意的是,这个加权和都取最小值。而 di+ 和 dii- 并不一定要出现在每个不同的需求层次中。具体分析需要具体问题具体分析 下面是一个例子: 题目中说设备 B 既要求充分利用,又要求尽可能不加班,那么列出的时间计量表达式即为:min z = P3 (d3- + d3 +) 使用 + 而不是 -d3 + 的原因是:正负偏差不可能同时存在,必须有 di+di=0 (因为判定值不可能同时大于目标值和小于目标值),而前面是 min,所以只要取 + 并让 di+ 和 dii- 都为正值即可。因此,得出以下规则: 最后,给出示例和相应的解法: 问题:某企业生产 A 和 B 两种产品,需要使用 A、B、C 三种设备。下表显示了与工时和设备使用限制有关的产品利润率。问该企业应如何组织生产以实现下列目标? (1) 力争利润目标不低于 1 500 美元; (2) 考虑到市场需求,A、B 两种产品的生产比例应尽量保持在 1:2; (3)设备 A 是贵重设备,严禁超时使用; (4)设备 C 可以适当加班,但要控制;设备 B 要求充分利用,但尽量不加班。 从重要性来看,设备 B 的重要性是设备 C 的三倍。 建立相应的目标规划模型并求解。 解:设企业生产 A、B 两种产品的件数分别为 x1、x2,并建立相应的目标计划模型: 以下为顺序求解法,利用 LINGO 求解: 1 级目标: 模型。 设置。 variable/1..2/:x;! s_con_num/1...4/:g,dplus,dminus;!所需软约束数量(g=dplus=dminus 数量)及相关参数; s_con(s_con_num);! s_con(s_con_num,variable):c;!软约束系数; 结束集 数据。 g=1500 0 16 15. c=200 300 2 -1 4 0 0 5; 结束数据 min=dminus(1);!第一个目标函数;!对应于 min=z 的第一小部分;! 2*x(1)+2*x(2)<12;!硬约束 @for(s_con_num(i):@sum(variable(j):c(i,j)*x(j))+dminus(i)-dplus(i)=g(i)); !使用设置完成的数据构建软约束表达式; ! !软约束表达式 @for(variable:@gin(x)); !将变量约束为整数; ! 结束 此时,第一级目标的最优值为 0,第一级偏差为 0: 第二级目标: !求 dminus(1)=0,然后求解第二级目标。 模型。 设置。 变量/1..2/:x;!设置:变量/1..2/:x; ! s_con_num/1...4/:g,dplus,dminus;!软约束数量及相关参数; s_con(s_con_num(s_con_num));! s_con(s_con_num,variable):c;! 软约束系数; s_con(s_con_num,variable):c;! 结束集 数据。 g=1500 0 16 15; c=200 300 2 -1 4 0 0 5; 结束数据 min=dminus(2)+dplus(2);!第二个目标函数 2*x(1)+2*x(2)<12;!硬约束 @for(s_con_num(i):@sum(variable(j):c(i,j)*x(j))+dminus(i)-dplus(i)=g(i)); ! 软约束表达式;! dminus(1)=0; !第一个目标结果 @for(variable:@gin(x)); ! 结束 此时,第二个目标的最优值为 0,偏差为 0: 第三目标 !求 dminus(2)=0,然后求解第三个目标。 模型。 设置。 变量/1..2/:x;!设置:变量/1..2/:x; ! s_con_num/1...4/:g,dplus,dminus;!软约束数量及相关参数; s_con(s_con_num(s_con_num));! s_con(s_con_num,variable):c;! 软约束系数; s_con(s_con_num,variable):c;! 结束集 数据。 g=1500 0 16 15; c=200 300 2 -1 4 0 0 5; 结束数据 min=3*dminus(3)+3*dplus(3)+dminus(4);!第三个目标函数。 2*x(1)+2*x(2)<12;!硬约束 @for(s_con_num(i):@sum(variable(j):c(i,j)*x(j))+dminus(i)-dplus(i)=g(i)); ! 软约束表达式;! dminus(1)=0; !第一个目标约束条件; ! dminus(2)+dplus(2)=0; !第二个目标约束条件 @for(variable:@gin(x));! 结束 最终结果为 x1=2,x2=4,dplus(1)=100,最优利润为
-
卷积的意义--我见过最生动易懂的解释--就是在图像处理中,将两组分辨率不同的图像进行卷积处理,从而形成易于处理的平滑图像。卷积甚至可以用在考试作弊中,为了让照片中的两个人同时像,只要对两个人的图像进行卷积处理就可以了,这是一种平滑处理,但我们如何才能真正把这个公式与实际建立一种联系,也就是说我们能不能从生活中找到一个很方便具体的例子来表达这个公式的物理意义呢? 有一个七品县令,喜欢打骂无赖,并有一个惯例:只要不犯大罪,只打一顿就放他回家,以示爱民如子。 有一种无赖,想扬名立万却又不抱多大希望,心想:既然扬不了好名,出了臭名也成啊。怎样才能出恶名呢?炒作!怎么炒作?找名人!他自然而然地想到了自己的长官--县令。 无赖于是在光天化日之下,站在县衙门口撒了泡尿,后果可想而知,自然是被请进堂上挨了板子,然后昂首挺胸地回家,躺了一天,哎!身体并无大碍!第二天照样如此,全然不顾行政长管的仁慈和衙门的尊严,第三天、第四天 ......每天去县衙领板子回来,还兴高采烈,坚持了一个月之久!这个无赖的名声像衙门口的臭气一样传遍了八方! 县太爷噤了噤鼻子,愣愣地望着惊堂木案,皱了皱眉头,思考着一个问题:这三十块大木板怎么会不好用呢?......想想也是,当年这位大人金榜题名的时候,我数学考了满分,所以这道题至少今天得解出来: --人(系统!)会怎么样(系统!)之后会怎么样(输出!)人(系统!)被打之后会怎么样? --有什么用,很疼! --我问的是:会发生什么? --取决于有多疼。就像这个无赖的体质,每天挨一板什么事都不会发生,连哼哼两声都不行,你看他那得意洋洋的样子(输出 0);如果一次连打他十板,他可能会皱着眉头,咬着牙,硬是不哼一声(输出 1);打到二十板,他会疼得脸都变形了,像猪一样哼哼唧唧(输出 3);打到三十板,他可能会像驴一样嚎叫,一把鼻涕一把泪,求你饶他一命(输出 5);打到四十板,他会大小便失禁,勉强哼哼(输出 1);打到五十板,他连哼哼都不能哼一下(输出 0)--死! 县官摊开坐标纸,绘制了一条以挨打次数为 X 轴、哼唱程度(输出)为 Y 轴的曲线: --"呜呼!这条曲线就像一座山,想不通,想不通。为什么那个无赖被打了三十天也不喊救命? --哦,你打的时间间隔(Δτ=24小时)太长了,这样无赖一天承受的痛苦程度,没有叠加,始终是个常数;如果缩短时间间隔(建议Δτ=0。5 秒),那么他的疼痛程度就可以迅速叠加;等到无赖挨了三十下(t=30)时,疼痛程度已经达到他叫喊能力的极限,就会收到最好的惩戒效果,再多挨几下也不会手下留情。 --还是不太明白,为什么疼痛程度会在小时间间隔内叠加? --这跟人(线性时变系统)对木板(脉冲、输入、激发)的反应有关。什么是响应?人收到板子后,疼痛的感觉会在一天内(假设,因人而异)慢慢消失(衰减),而不是突然消失。这样,只要中风的时间间隔较小,每次中风造成的疼痛就没有时间完全衰减,都会对最终的疼痛程度产生不同的影响: t 块大板造成的疼痛程度 = Σ(第 τ 块大板造成的疼痛程度 * 衰减系数)[衰减系数是 (t - τ) 的函数,请仔细品味] 数学表达式为:y(t) = ∫T(τ)H(t-τ)
-
如何轻松设置与运用 CoreDNS 在 Kubernetes (K8s) 中
-
如何在WPS中运用正则表达式和通配符:简单易懂指南
-
在expdp和impdp工具中,如何灵活运用exclude和include功能
-
在PL/SQL中:如何灵活运用动态SQL来调用包里的函数或过程
-
金融科技的高效省力秘籍:打造全面连接、全景覆盖、智能化的数字化运营体系" - 当下金融科技运营:挑战与机遇共存的时代解读 在快速发展的数字技术和企业数字化转型的大背景下,中国金融科技产业步入了提质增效的新阶段。面对市场的起伏变革与不确定性,金融机构需积极拥抱创新,灵活运用新技术,确保在竞争激烈的市场环境中稳固立足。 - 面临的双重考验: 1. 技术迭代压力:持续跟进行业内的科技革新,掌握新兴工具和平台,时刻应对瞬息万变的市场需求是金融科技运营的一大挑战。 2. 安全与隐私挑战:伴随着网络安全风险加剧和数据泄漏频发,如何强化信息安全体系、防范攻击、维护客户资金及隐私安全显得尤为重要。同时,伴随金融科技公司崛起,个人隐私权保障愈发关键。 - 喜人的发展空间: 1. 提升运营效益与降低成本:借助数字化技术,实现流程自动化、信息整合以及数据分析等,有效提升工作效能并缩减运营成本。 2. 扩大市场份额与增收途径:利用数字化手段拓宽销售渠道,优化用户体验,吸引更多用户并带动收入增长。 3. 加强客户联系与提升满意度:通过数字化科技运营,企业能更好地与客户互动沟通,增强客户信任感与忠诚度。 - 构建金融科技降本增效的核心驱动力:实施“全感知、全链接、全场景、智能”的科技运营体系升级路径
-
在React和Vue中,我们是如何玩转router的? - 使用HTML5 History API,React Router利用pushState和replaceState方法在不刷新页面的情况下管理导航历史。它像这样工作: 1. 当URL发生变化时,React Router悄悄地“监听”浏览器地址栏的改动,主要通过popstate事件来察觉url更改。 2. 随着URL的变化,Router会对照预先设定好的JavaScript路由配置对象,依据一套规则找出与当前URL匹配的路径。 3. 一旦找到合适的路线,React Router就会如魔法般地渲染相应的组件到网页上,从而实现了页面内容的实时更新。让我们来看一个React Router实际运用的例子。
-
在layui中如何运用formSelects?
-
在Java中,哪些情况适合用递归?以及如何实际运用递归方法