当前位置: 首页 > 编程日记 > 正文

java struts2值栈ognl_Struts2 (三) — OGNL与值栈

一、OGNL表达式

1.概述

1.1什么是OGNL

​ OGNL是Object-Graph Navigation Language的缩写,俗称对象图导航语言. 它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。

​   Eg: hibernate 查询方式 : 对象导航查询。

​   其实就是查询出来了一个对象之后,通过对象里面的getXXX() 来获取关联的对象。

​   它是一个开源项目,并不是struts发明出来的,只是struts里面默认的表达式是使用OGNL表达式,也就是说OGNL是struts2的默认表达式语言。

1.2 OGNL作用

获取对象的成员(支持对象方法的调用,支持对象对象属性访问,支持静态方法的调用,支持集合对象操作, )

在配置文件里面使用

进行运算

2.OGNL要素

​   OGNL 有三个核心元素 ,我们只有理解这三个核心元素,才能去更好的学习OGNL表达式

2.1表达式 (Expression)

​   表达式用于表示我们到底想执行什么操作 。 比如:想获取成员 ,直接用对象.成员名字就可以得到该成员的值

2.2 根元素 (Root)

​   OGNL 表述的是对象导航语言、那么必须的指明根元素是什么。 好比我们要在树上找果子、必须指定到底是那一棵树是一样的道理。

2.3上下文 (Context)

​   上下文其实就是我们的那个root寄存的位置,它在内存当中其实就是一个Map 。OGNL 有一个类专门用来表示上下文环境 叫做OGNLContext , 它其实就是一个Map.

EG:Map里面存放了很多的User对象, 那么我们必须指明是在哪一个根上面找这些user对象。

我们通过一个例子来描述这三者之间的关系

EG: 一个果农在果园摘苹果

上下文 (Context): 果园, 果园里面有苹果树, 梨树, 桃树....

根元素 (Root): 苹果树

表达式 (Expression): 要摘什么样的苹果(大的, 小的, 熟的, 红的....)

3.OGNL入门

大家在使用OGNL的时候,要在脑海中有一个想像,就是内存中已经有了一个对象,我们需要去操作这个对象,获取里面的成员,或者去调用它的某个方法。那么表达式应该怎么写。这和我们的EL 表达式有异曲同工之妙,都是用于获取对象、然后再关联到具体的某一个成员.当然我们现在给大家在代码里面演示OGNL的一些用法,一般我们使用OGNL 最多的地方还是在jsp页面上。

3.1表达式与根对象【了解】

访问根对象属性

1 /**

2 * OGNL表达式和根对象: 访问属性3 *@throwsOgnlException4 */

5 @Test6 public void fun01() throwsOgnlException{7 //根对象

8 User root = new User("张三", 18);9 //表达式(想得到什么)

10 String expression = "username";11 //通过Ognl方式获得根对象中的表达式结果

12 Object value =Ognl.getValue(expression , root);13 System.out.println("value="+value);14 }

访问根对象方法

1 /**

2 * OGNL表达式和根对象: 访问方法3 *@throwsOgnlException4 */

5 @Test6 public void fun02() throwsOgnlException{7 //根对象

8 User root = new User("张三", 18);9 //表达式(想得到什么)

10 String expression = "getUsername()";11 //通过Ognl方式获得根对象中的表达式结果

12 Object value =Ognl.getValue(expression , root);13 System.out.println("value="+value);14 }

访问静态方法

1 @Test2 //访问静态方法: @类的全限定名@方法名, 并且根对象设置为null

3 public void fun03() throwsException {4 //double random = Math.random();5 //System.out.println(random);6 //String expression = "@java.lang.Math@random()";7 //Object value = Ognl.getValue(expression , null);8 //System.out.println(value);9

10 //Runtime runtime = Runtime.getRuntime();11 //runtime.exec("calc.exe");12 //runtime.exec("shutdown.exe -s -t 3");

13 String expression = "@java.lang.Runtime@getRuntime().exec('calc.exe')";14 Object value = Ognl.getValue(expression , null);15 }

3.2表达式和上下文【了解】

结合上下文访问根对象属性

1 /**

2 * 表达式和上下文 在水果园摘水果3 * 1.表达式:表达式用于表示我们到底想执行什么操作,想得到什么 eg: 摘桃子4 * 2.根对象:具体操作的对象,得到这个对象某某 eg:桃树5 * 3.上下文: 其实就是根对象寄存的位置.其实就是一个Map,也就是说Map里面可以存到很多的对象(根对象和非根对象)6 * eg: 果园, 这里有桃树(根对象), 还有苹果树,梨树...7 *@throwsOgnlException8 */

9 @Test10 public void fun03() throwsOgnlException{11 User user1 = new User("张三", 18);12 User user2 = new User("李四", 19);13 //上下文

14 Map context = new HashMap();15 context.put("user1", user1);16 context.put("user2", user2);17

18 //根对象(指定user1为根对象)

19 Object root =user1;20

21 //表达式(想得到什么)

22 String expression = "username";23 //通过Ognl方式获得根对象中的表达式结果(获得根对象的username的值,也就是user1的)

24 Object value =Ognl.getValue(expression, context, root);25 System.out.println("value="+value);26

27 //获得非根对象的值(user2的)

28 expression = "#user2.username";29 value =Ognl.getValue(expression, context, root);30 System.out.println("value="+value);31 }

​ 翻译上面的getValue方法的含义是: 在上下文 context里面找到一个 根user1 然后取它的name值

​ 如果想要获取user2的数据 因为user2不是根对象,所以要想取它的值,需要写成 #key.name 。 String expression = "#user2.name"

3.3在页面使用Ognl【重点】

​ 要想在页面上(jsp..)使用Ognl, 需要借助struts2的标签才可以使用.

​ 使用标签:

​ 步骤: 1.导入struts2标签库到页面

​     2.使用标签, 把value属性取值所对应的内容输出到浏览器上

调用非静态方法

desw

调用静态方法

默认情况下struts2不允许在页面调用静态方法, 调用之前需要在struts.xml配置常量

在jsp页面上使用:

二、ValueStack值栈

1.概述

1.1什么是值栈

​   value stack : 翻译过来是值栈的意思。

​   回想以前我们在学习servlet的时候,我们要想 servlet操作完成后,生成了一个集合或者对象数据, 在页面上显示,我们通常的做法是。把这个对象或者集合存储在作用域里面,然后到页面上再取出来。

strtus 框架是对我们的servlet进行了包装 ,它内部自己也有一套存值和取值的机制 ,这一套机制就是现在说的值栈。

db545b819159696bfe5f2715d7628c7d.png

8447733.html

2.值栈创建的时机

2.1 Servlet和Action的区别

Servlet: Servlet只会创建一次实例,以后再过来请求,不会创建实例

Action: Action是多例,来一次请求就创建一个Action实例。 创建一次Action的实例,就创建一次ActionContext实例,并且就创建出来一个值栈的实例。

2.2什么时候创建值栈

请求到来的时候才会创建值栈, 当来了请求,会执行前端控制器的doFilter方法,在doFilter方法里面,有如下代码 89行

prepare.createActionContext(request, response);

在createActionContext()这个方法内部

1 //从ThreadLocal里面获取ActionContext实例,一开始是没有的,所以该对象是 null

2 ActionContext oldContext =ActionContext.getContext();3 if (oldContext != null) {4 //detected existing context, so we are probably in a forward

5 ctx = new ActionContext(new HashMap(oldContext.getContextMap()));6 } else{7 ​8 //创建值栈对象 是OgnlValueStack 对象

9 ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();10 ​11 //给值栈里面的上下文区域存东西 。 存request \ response \session \application...

12 stack.getContext().putAll(dispatcher.createContextMap(request, response, null));13 //创建ActionContext的对象。 然后跟值栈关联上

14 ctx = newActionContext(stack.getContext());15 }

3.值栈的内部结构

​ 我们查看值栈的内部结构,其实是想研究值栈存值的时候,是存到了什么地方去的。

ca7407fcdad9ef45a34b5a16e2a0649c.png

值栈其实就是一个类 OgnlValueStack ,我们如果往值栈存值, 其实是存到了这个类中的两个集合去。

CompoundRoot root; //这其实是一个集合 list

transient Map context; //这是OGNL上下文 OGNLContext

//底下还有一行代码

context.setRoot(root);//也就是设置了OGNL上下文的根其实就是一个list集合 。 说的具体一点。 就是那个CompoundRoot对象。

我们使用OGNL表达式取值的时候,都是去上下文里面取值。

8447733.html

​ root 区,根对象。具体类型为CompoundRoot。CompoundRoot实现了List接口,其实就是一个list集合。其实我们存值的话都是存在root区域.

​   context 区:上下文对象。具体类型为OgnlContext。OgnlContext内部操控的是一个Map集合,其实context区可以理解为一个Map集合。

4.获得ValueStack

4.1 通过ActionContext对象的实例获得

​ 由于前面创建好值栈后,让它和ActionContext关联上了,所以我们只要通过ActionContext去获取它即可。

获得值栈代码

ValueStack valueStack = ActionContext.getContext().getValueStack();

4.2通过request域获得ValueStack

​   在执行完我们的Action方法前,struts会把值栈往request对象里面存起来,所以我们使用request对象即可获取到.

在前端过滤器的doFilter()方法里面有 execute.executeAction(request, response, mapping);这行代码,执行Action.

具体源码参见: Dispatcher类中的serviceAction方法 , 位于568行行:request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY,   proxy.getInvocation().getStack());所以后续我们也只要使用request对象然后结合对应的STRUTS_VALUESTACK_KEY 这个key即可获取到值栈

获得值栈代码

ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

5.值栈存取值

5.1 push方式

​   直接放置在栈顶,没有什么key与之对应。所以取值的话,直接写属性名即可。 但是如果push 了多个,并且还想获取的不是栈顶的值,是栈顶下来的某一个位置的值,那么可以采用[0] \ [1] 这种做法

42b66fcd9dba5c33f8ed0783daa0f620.png

存值Java代码

User user = new User("admin" ,"10086");

ValueStack stack=ActionContext.getContext().getValueStack();//执行的是压栈的动作。 放置的东西永远会在栈顶。

stack.push(user);

​//第二次的时候,user02已经位于栈顶 ,之前的那个user就要往下压一格

User user02 = new User("zhangsan" ,"1000000");

stack.push(user02);

取值(演示[0]和[1]的区别)

取push放的值

,

取push的值 就取第二个,不取栈顶

,

5.2set方式

​   set 和 push 的区别在于, push 是直接把数据压倒栈顶 , 但是set方式是用一个map集合来包装数据,然后才把map压倒栈顶。 所以取值手法也有点不一样。 set(key, value); key就是包装map的key。

5ec2239cb97dc419b3d0a74ecf9545f8.png

存值Java代码

User user = new User("admin" ,"10086");

ValueStack stack=ActionContext.getContext().getValueStack();

stack.set("user01", user);

取值

取set放的值

,

5.3属性驱动方式

​   和之前的获得请求参数属性驱动类似. 存到了当前的Action类的区域(还是在根里面)

存值Java代码

1 public class ActionDemo01 extends ActionSupport {2 private String str;3 public String fun01(){4 str = "hello";5 return "success";6 }7 //提供get方法

8 public String getStr() {9 returnstr;10 }11 ​12 }

取值

取属性封装的值

5.4模型驱动方式

存值

1 public class ActionDemo01 extends ActionSupport implements ModelDriven{2 privateUser user;3 publicString fun01(){4 return "success";5 }6 @Override7 publicUser getModel() {8 if(user == null){9 user = new User("李四", "66666666");10 }11 returnuser;12 }13 ​14 }

取值

,
或者: ,

由于使用模型驱动封装,存值的时候,也还是存到action的范围里面去.

5.5使用EL表达式取值

​   EL表达式也可以取到值栈的值,本来EL表达式是用于取作用域的值,但是值栈和作用域是两个东西。 为什么EL 表达式也能去值栈的值呢?原因是 : struts对EL 表达式取值的代码进行了扩展,如果从作用域取不到值就会去值栈找。

​   reuqest.setAttribute("user" , user); ${user.name} ------> pageContext.findAttrbute(); --> 先从page范围找, 没有,就找request, 还没有就找session。request类型被包装成了 StrutsRequestWrapper 在里面的getAttribute 做了判定,如果从作用域中去不到值,就去值栈取值

6.OGNL中的符号

6.1#号的作用

获取Context中的数据,非根对象里面的数据

构建一个Map集合

//var变量会存一份到root也会存一份到上下文 c:foreach

--

--

6.2 $号的作用

在xml等配置文件里面使用ognl

8447733.html

87cadf68980c1a55472145ea24c50b47.png

6.3 OGNL取值流程图

2b32f0830204844f404d86a1a080c423.png

相关文章:

c语言课程设计商品销售系统,c语言课程设计商品销售管理系统.pdf

C语言课程设计商品销售管理系统12020 年 4 月 19 日文档仅供参考商品销售管理系统目录一、 需求分析 2二、概要设计 2三、详细设计 4四、调试分析 14五、用户手册 14六、测试数据 15七、 附录 18— 1—22020 年 4 月 19 日文档仅供参考一、需求分析商品销售管理程序商品信息&am…

uploadhandler.php,WordPress Kernel Theme ‘upload-handler.php’任意文件上传漏洞

javascript中apply、call和bind的区别在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢.在说区别之前还是先总结一下三者的相似之处:1.都是用来改变函数的this对象的指向的.2.第一个参数都是this要指向的对 ...AIX UNIX 系统管理、维护与高可用集群建设—…

selenium--driver.switchTo()

在自动化测试中,会遇到多窗口、多iframe、多alert的情况。此时,会使用driver.switchTo()来解决。 下面时关于driver.switchTo()的详细介绍: 1.多windows操作。 在页面A上操作时,点击某个元素之后,可能会打开新的窗口。…

代理模式-积木模式

代理模式-积木模式 代理模式在实际开发中的确非常常见和常用,表面上代理模式是产生出一个代理类,作为访问实际实现类的代理,控制了外界对实际代理类的访问,在此基础上增加一些增强性的功能。实际上,还将实际…

java调用系统时间函数_JAVA自学笔记:不使用系统函数来计算日期处于当年的第多少天...

前段时间练习了一个求闰年的功能,现在就可以用上啦,这次写一个不借助类库的时间函数,利用基础代码写一个计算求日期处于当年的第多少天的函数。虽然也有简单的方法,例如直接定义每月的天数累加,然后加上当月的天数就可…

c语言输入学生成绩q退出,哭诉、拜求C语言学生成绩管理系统

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼/* Note:Your choice is C IDE */#include "stdio.h"#include "stdlib.h"#include "conio.h"#include "string.h"struct student{int num;char name[20];float score1;float score2;float…

php 所有魔术方法,PHP常用的魔术方法及规则

转:https://www.cnblogs.com/wanglijun/p/10926303.html1. __construct 具有构造函数的类会在每次创建新对象时先调用此方法;初始化工作执行。2. __desstruct 对象的所有引用都被删除或者当对象被显式销毁时执行。3.__call()在对象中调用一个不可访问方法时&#xf…

mysql启动后在哪里编程_启动mysql后怎么连接数据库

推荐答案一.mysql安装百度mysql下载一个即可。只是注意一下几个重要的数据:第一个就是Port Number :3306。端口号默认3306,一般不需要改,如果改了,请记住这个端口号。第二个就是password:本地数据库密码,默…

Python 出现 can't use a string pattern on a bytes-like object

# codingutf-8import urllib.requestimport reurl http://www.163.comfile d:/test.htmldata urllib.request.urlopen(url).read() r1 re.compile(<.*?>)c_t r1.findall(data)print(c_t)发现读取下来后,运行到第9 行,出现: cant use a string pattern on a bytes-l…

2018牛客网暑期ACM多校训练营(第十场)J(二分)

题目描述&#xff1a; 给你n个字符串&#xff0c;要让它们一个一个的合并成一个串。在合并的过程中&#xff0c;要保证被合并的串S是合并后的串r的前缀&#xff0c;模式串t是串r的子序。问你将这n个字符串合并后所得到的字典序最小的串是什么。 题目分析&#xff1a; 首先&…

实用c语言函数源码,C语言编写简单朗读小工具(有源码)

原标题&#xff1a;C语言编写简单朗读小工具(有源码)最近不少人在后台留言说学C都是面对枯燥的控制台程序&#xff0c;能不能体现一下C语言的实际用途&#xff0c;今天我们就理论结合实践一把&#xff1a;C语言结合VBS脚本编写一个简单的朗读小工具&#xff0c;做一个能够发音的…

php监听订单状态,ecshop数据库订单状态判断

order_info 表刚下完订单order_status 0shipping_status 0pay_status 0取消order_status 2shipping_status 0pay_status 0确认order_status 1shipping_status 0pay_status 0已付款order_status 1shipping_status 0pay_status 2配货中order_status 1shipping_status 3pay_status…

flask异步操作_Python Flask后端异步处理(三)

前一篇博文我们已经将基础知识和环境配置进行了介绍&#xff1a;首先编写一个celerytask.py文件进行Celery的配置&#xff0c;同时耗时任务也写在该文件中from celery import Celeryfrom init import appfrom SZheConsole import SZheScanapp.config[CELERY_BROKER_URL] redis…

Codeforces Round #308 (Div. 2) C. Vanya and Scales dfs

题目链接: http://codeforces.com/contest/552/problem/C 题意: 给你100个砝码&#xff0c;第i个砝码质量是w^i&#xff0c;然后问你能不能在有m的情况下&#xff0c;左边和右边都放砝码&#xff0c;使得这个天平平衡 题解: dfs直接暴力 对于这个砝码来说&#xff0c;只有3种选…

java中JVM的原理【转】

一、java虚拟机的生命周期&#xff1a; Java虚拟机的生命周期 一个运行中的Java虚拟机有着一个清晰的任务&#xff1a;执行Java程序。程序开始执行时他才运行&#xff0c;程序结束时他就停止。你在同一台机器上运行三个程序&#xff0c;就会有三个运行中的Java虚拟机。 Java虚拟…

switch的case使用数组C语言,使用常量数组的元素作为switch语句中的case

我正在尝试将一组按键映射到一组命令.因为我处理来自多个地方的命令,所以我想在键和命令之间设置一个抽象层,这样如果我更改底层键映射,我就不必更改很多代码.我目前的尝试看起来像这样:// input.henum LOGICAL_KEYS {DO_SOMETHING_KEY,DO_SOMETHING_ELSE_KEY,...countof_LOGIC…

PHP上传文件函数move_upload,如何使用php中move_uploaded_file函数

我们平时上传的文件保存在临时文件夹中&#xff0c;例如/ tmp&#xff0c;但临时文件夹的内容在一段时间后会被删除&#xff0c;因此为了将来要使用上传文件&#xff0c;需要将内容保存在不太可能被任意删除的专用目录中&#xff0c;这时就需要使用move_uploaded_file函数&…

java的标记接口_Java中的标记接口?

我被教授&#xff0c;Java中的Marker接口是一个空接口&#xff0c;用于向编译器或JVM发送信号&#xff0c;实现此接口的类的对象必须以特殊方式处理&#xff0c;如序列化&#xff0c;克隆等。但最近我了解到&#xff0c;它实际上与编译器或JVM无关。例如&#xff0c;在Serializ…

Java Exception

先贴上一段Exception源码注释 1 /**2 * The class {code Exception} and its subclasses are a form of3 * {code Throwable} that indicates conditions that a reasonable4 * application might want to catch.5 *6 * <p>The class {code Exception} and any subc…

c语言实验至少包括四个函数中,C语言实验报告《函数》

学号&#xff1a;__________ 姓名&#xff1a;__________ 班级&#xff1a;__________ 日期&#xff1a;__________指导教师&#xff1a;__________ 成绩&#xff1a;__________实验四 函数一、 实验目的1、掌握函数定义、调用和声明的方法2、掌握实参和形参之间的…

Android与iOS对比

最近有并行开发Android与iOS端App,想在这总结一些两种开发的相似与区别。转载于:https://www.cnblogs.com/stuwan/p/6475725.html

oracle停止一切进程,oracle启动/停止的几种方法以及 启动和停止过程中出错的解决办法...

一、启动几种方法&#xff1a;1、sqlplus /nologconnect /as sysdbastartup2、sqlplus /nologconnect /as sysdbastartup nomountalter database mountalter database open在以上两种方法中&#xff0c;1方法中的startup相当于2方法中的startup nomountalter database mountalt…

前端js判断上传是否为EXCEL表格问题

直接贴代码吧~JS部分 输入框部分&#xff1a; 转载于:https://www.cnblogs.com/aijiajia1314/p/9517541.html

java 外部类似_[求指点] 如何用java 实现类似linux中管道调用外部程序的功能

想写个小程序实现类似linux中管道的功能&#xff0c;创建一个外部子进程&#xff0c;然后主进程不断地写输入给子进程&#xff0c;而后把子进程的返回值取出。如下的小代码就是从stdin读入一个字符串&#xff0c;调用子进程(cat)返回这个串&#xff0c;然后返回。但下面的写法只…

c语言递归求五阶行列式源代码,久游堂怎么样 -官网

iOS版# -*- coding: utf-8 -*- """ author: Dell Created on Tue Dec 24 12:33:56 2019 """ import time from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait#等待一个元素加载完成 from selenium.webdri…

POJ - 3660 Cow Contest(flod)

题意&#xff1a;有N头牛&#xff0c;M个关系&#xff0c;每个关系A B表示编号为A的牛比编号为B的牛强&#xff0c;问若想将N头牛按能力排名&#xff0c;有多少头牛的名次是确定的。 分析&#xff1a; 1、a[u][v]1表示牛u比牛v强&#xff0c;flod扫一遍&#xff0c;可以将所有牛…

oracle scn与数据恢复,SCN与数据库恢复的关系

一。SCN与CHECKPOINTCKPT进程在checkpoint发生时&#xff0c;将当时的SCN号写入数据文件头和控制文件&#xff0c;同时通知DBWR进程将数据块写到数据文件。CKPT进程也会在控制文件中记录RBA(redo block address),以标志Recovery需要从日志中哪个地方开始。与checkpoint相关的SC…

Java 理解泛型的基本含义

Java 泛型 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。 泛型的本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数。 泛型方法 你可…

java严格区分大小写吗_Java是否区分大小写?

我在某处读到Java是区分大小写的。 我一直无法证实这一点。Java源代码是区分大小写的&#xff0c;如果你的意思是。 即Double与double不是同一个types&#xff0c;并且可以有两个不同的variablesmyData和mydata 。是吗&#xff1f; 如果是这样&#xff0c;为什么&#xff1f;区…

4、Hibernate查询语句

转载于:https://www.cnblogs.com/wyl9527/p/6484099.html