Struts2 的OGNL与值栈学习
程序员文章站
2022-04-18 11:47:38
...
1.OGNL的概述
1.1什么是OGNL
- OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
- OGNL:对象图导航语言,是第三方的表达式语言,比EL表达式强大很多倍,可以调用对象的方法和获取Struts2的值栈的数据。
1.2.为什么要学习OGNL?
- 支持对象方法的调用
- 支持类静态方法的调用和值访问,与EL表达式一样,可以取值
- 支持赋值操作和表达式串联
- 支持访问OGNL上下文和ActionContext
- 可以操作(创建)对象集合
- 可以直接new一个对象
1.3 OGNL的作用
- 用于JSP页面的取值
- EL表达式语言也用于页面取值,不需要配置就可以直接使用,是JSP页面默认的取值标准
- OGNL表达式语言是Struts标签默认支持的表达式语言,必须配置Struts标签用!!!
1.4.OGNL使用的要素
- 表达式
- 表达式就是一个带有语法含义的字符串,这个字符串规定了操作的类型和操作的内容,OGNL支持大量的表达式语法,不仅支持“链式”对象访问路径,还支持在表达式中进行简单额计算。
- 根对象
- Context
1.5.OGNL在java环境的入门
- 1.调用对象方法
// OGNL调用对象的方法
@Test
public void demo1() throws OgnlException {
//获取context
OgnlContext context=new OgnlContext();
//获取根对象
Object root =context.getRoot();
//执行表达式
Object obj=Ognl.getValue("'hello'.length()", context, root);
System.out.println(obj);
}
- 2.访问对象的静态方法
//访问对象的静态方法
@Test
public void demo2() throws OgnlException {
//获取context
OgnlContext context=new OgnlContext();
//获取根对象
Object root =context.getRoot();
//执行表达式:@类名@方法名
Object obj = Ognl.getValue("@[email protected]()", context, root);
System.out.println(obj);
}
- 3.获取Root中的数据
//访问root中的数据,不加#
@Test
public void demo3() throws OgnlException {
//获取context
OgnlContext context=new OgnlContext();
//new一个对象出来(一个实体User类,提供get、set,无参、有参)
User user=new User("aaa","123");
//向root中存储值
context.setRoot(user);
//获取根对象
Object root =context.getRoot();
//执行表达式
String username = (String) Ognl.getValue("username", context, root);
String password = (String) Ognl.getValue("password", context, root);
System.out.println(username+" "+password);
}
- 4.访问context中的数据
//访问context中的数据,需要加#
@Test
public void demo4() throws OgnlException {
//获取context
OgnlContext context=new OgnlContext();
//获取根对象
Object root =context.getRoot();
//向context中存入数据
context.put("name", "老王");
Object value = Ognl.getValue("#name", context,root);
System.out.println(value);
}
1.6 OGNL在Struts2环境下的入门
- 1.可以直接访问对象的方法
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>OGNL在Struts2环境中的入门</h1>
<s:property value="'struts'.length()" />
-------------------------------
<h3>调用对象的静态方法</h3>
<!--静态方法访问在Struts2中默认是关闭的,需要开启一个常量-->
<s:property value="@[email protected]()" />
</body>
</html>
- 2.对象的静态方法的访问
<!--在struts.xml中开启静态方法访问 -->
<constant name="struts.ognl.allowStaticMethodAccess"
value="true"></constant>
2.值栈的概述
2.1.什么是值栈
- ValueStack是Struts的一个接口,字面意思是值栈,OgnlValueStack是ValueStack的实现类,客户端发起一个请求struts2架构会创建一个action实例同时创建OgnlValueStack值栈实例,OgnlValueStack贯穿整个Action的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
- ValueStack其实就类似于数据的中转站(Struts2中的数据都保存在ValueStack中)
2.2.值栈的内部结构
- ValueStack中主要有两个区域
-
root区域:就是一个ArrayList,里面一般放置对象,获取root的数据不需要加#
-
context区域:就是一个Map,里面放置的是web开发常用的对象数据的引用。获取数据时加#,下面是常见的web对象的引用
> request > session > application > parameters > attr
-
2.3.值栈与ActionContext的关系
- ServletContext:Servlet的上下文
- ActionContext:Action的上下文
- 通过源码查看到,当请求过来的时候,执行过滤器中的doFilter方法,在这个方法中创建ActionContext,在创建的过程中,创建了ValueStack对象,将ValueStack对象传递给ActionContext对象,所以可以通过ActionContext获取值栈对象。
- ActionContext对象之所以能够访问Servlet的API(访问的是域对象的数据),因为在其内部有值栈的引用。
2.4.获取值栈的方法
- 1.通过ActionContext对象获取值栈
public class ValueStackDemo2 extends ActionSupport {
//获得ValueStack对象方式一
@Override
public String execute() throws Exception {
ValueStack valueStack1 = ActionContext.getContext().getValueStack();
return NONE;
- 2.在Struts2的内部,将值栈存入request中一份。
ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest().
getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
- 注意:一个Action的实例,只会创建一个ValueStack的对象
2.5操作值栈–>向值栈中存入数据
- 1.在Action中提供属性的get方法
- 默认情况下,将Action对象压入到值栈,Action的属性也会在值栈
public class ValueStackDemo3 extends ActionSupport {
private User user;
public User getUser() {
return user;
}
//操作ValueStack
@Override
public String execute() throws Exception {
user=new User("李佳","22222");
return SUCCESS;
}
}
- 2.使用ValueStack中本身的方法
public class ValueStackDemo4 extends ActionSupport {
@Override
public String execute() throws Exception {
//向值栈中保存数据
//获得值栈对象
ValueStack valueStack = ActionContext.getContext().getValueStack();
User user=new User("李佳","2333");
//现在user在栈顶
valueStack.push(user);
valueStack.set("name", "小李子");
return SUCCESS;
}
2.6获取值栈的数据
- 1.获取值栈中的数据就是在页面中使用OGNL表达式即可。
public class ValueStackDemo5 extends ActionSupport {
@Override
public String execute() throws Exception {
//获取值栈的数据
//向值栈中保存一个对象
User user=new User("aaa","1223");
ActionContext.getContext().getValueStack().push(user);
//向值栈中保存一个集合
List<User> list = new ArrayList<User>();
list.add( new User("aaa", "111"));
list.add( new User("bbb", "222"));
list.add( new User("ccc", "333"));
list.add( new User("ddd", "444"));
ActionContext.getContext().getValueStack().set("list",list);
//向context中存入数据
ServletActionContext.getRequest().setAttribute("name", "问天");
ServletActionContext.getRequest().getSession().setAttribute("name", "李");
ServletActionContext.getServletContext().setAttribute("name", "砂皮");
return super.execute();
}
- 页面取值手段
<body>
<h1>查看值栈的数据</h1>
<s:debug></s:debug>
<!--获取一个对象的数据 -->
<s:property value="username" />
<s:property value="password" />
<!-- 获取集合中的数据 -->
<s:property value="list[0].username" />
<s:property value="list[0].password" />
<s:property value="list[1].username" />
<s:property value="list[1].password" />
<s:property value="list[2].username" />
<s:property value="list[2].password" />
<!--获取context中的数据 -->
<s:property value="#request.name" />
<s:property value="#session.name" />
<s:property value="#application.name" />
<s:property value="#attr.name" />
</body>
2.7 OGNL表达式中的特殊字符
- #的用法
<h1>#符号的用法</h1>
<h3>获取context中的数据</h3>
<%
request.setAttribute("name", "阿尔法");
%>
<s:property value="#request.name" />
<h3>构建map集合</h3>
<!-- list集合 -->
<s:iterator value="{'aaa','bbb','ccc'}">
<s:property value="i" />
<s:property value="#i" />
</s:iterator>
<!--map集合 -->
<s:iterator value="#{'a':'10','b':'20','c':'30','d':'40'}">
<s:property value="key"/>=
<s:property value="value"/>
</s:iterator>
- %的用法
<body>
<h1>%的用法</h1>
<%
request.setAttribute("name", "家家");
%>
姓名:
<s:textfield name="name" value="%{#request.name}"></s:textfield>
<!--这中方式不可以,被识别成字符串 -->
<s:property value="%{#request.name}" />
</body>