OGNL表达式学习笔记

OGNL表达式是一个独立的语言,strut2将其引入共同构造struts2。

OGNL语言强大于EL表达式,其可以访问java类中的对象,也可以访问对象的静态方法。

public class OgnlDemo1 {

	@Test
	public void test1() throws OgnlException{
		OgnlContext context = new OgnlContext();
		Object value = Ognl.getValue("'hello OGNL'.length()", context, context.getRoot());
		System.out.println(value);
	}
	
	@Test
	public void test2() throws OgnlException{
		OgnlContext context = new OgnlContext();
		Object root = context.getRoot();
		Object value = Ognl.getValue("@java.lang.Math@random()", context, root);
		System.out.println(value);
	}
}

root中存放的是java对象(一般写实体对象),访问Java类中的属性的demo:

	@Test
	public void test3() throws OgnlException{
		OgnlContext context = new OgnlContext();
		//通过context对象和User的有参构造给root设置值
		context.setRoot(new User("aloha","keep moving!"));
		//获取root
		Object root = context.getRoot();
		Object username = Ognl.getValue("username", context, root);
		Object password = Ognl.getValue("password", context, root);
		System.out.println(username);
		System.out.println(password);
	}

获取context中的数据,需要加#:

	@Test
	public void test4() throws OgnlException{
		OgnlContext context = new OgnlContext();
		//往Map集合context中添加键值对
		context.put("name", "aloha");
		Object name = Ognl.getValue("#name", context, context.getRoot());
		System.out.println(name);
	}

Struts2中使用OGNL

主要使用在:在页面中获取数据。

首先配置struts2环境,然后配置核心过滤器:

  <filter>
  	<filter-name>struts2</filter-name>
  	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>struts2</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

在jsp页面中引入strut2的标签库:

<%@ taglib uri="/struts-tags" prefix="s" %>

如何使用ognl表达式访问?

<!-- property表示ognl表达式,value属性中写表达式 -->
<s:property value="'aloha'.length()"/>

注意:strut2中默认关闭访问静态成员。在struts2-core-2.3.24.jar/org.apache.struts2/default.properties的第208行中约定:struts.ognl.allowStaticMethodAccess=false,所以我们可以在struts.xml常量配置中开启:

<constant name="struts.ognl.allowStaticMethodAccess" value="true" />

这样就可以调用静态方法了。

OGNL在struts2中获取值栈(ValueStack)

什么是值栈(ValueStack):实际上是一个容器,由当前页面发送一个请求的时候,struts的默认拦截器会将请求中的数据进行封装,并入ValueStack栈顶。相当一个数据中转站(Struts2的框架中数据实际就保存到了ValueStack中。

ValueStack 是struts的一个接口,OgnlValueStack是ValueStack的实现类。客户端发起一个请求,struts2架构后创建一个action实例同时创建一个OgnlValueStack值栈实例,这个实例贯穿Action的整个生命周期,Struts2中使用OGNL将亲求Action的参数封装为对象存储到值栈中,并通过OGNL表达是读取值栈中的对象属性值。

为啥要使用ValueStack?
存入ValueStack中的数据,我们在任何地方都可以把它取出来。(页面、action、配置文件)所以建议把数据存放到值栈中。

ValueStack的内部结构

structs2引用OGNL的时候并没有引入源代码,所以我们在导入struts2源码后并不能查看OGNL的源码,我们需要再导入ognl的源码。

ValueStack中有两个主要的区域:

root区和context区:root区是CompoundRoot类继承了ArrayList集合,其实就是一个ArrayList集合,,实现了压栈和出栈的功能,存储action实例及请求参数,其中保存对象Object;context区是OgnlContext类实现Map集合的一个Map集合,其键值为常用web开发对象的引用。

ValueStack和ActionContext的关系

类比于ServletContext, ActionContext对象是获取action上下文的对象。可以通过下面的方法获取

struts2-core-2.3.24.jar/StrutsPrepareAndExecuteFilter.class/doFilter(ServletRequest req, ServletResponse res, FilterChain chain)方法中,如果要经过过滤器,则执行有这句:prepare.createActionContext(request, response);

翻看源码:其中有一个逻辑:如果老的ActionContext为空, ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

这句话创建了一个ValueStack对象。

分析源码得出结论:

当请求过来的时候,执行过滤器中的doFilter方法,这个方法中创建ActionContext,再ActionContext创建的过程中,创建了ValueStack对象,然后将ValueStack的对象传递给了ActionContext。这就是可以通过ActionContext获取值栈对象的原因。

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

获取值栈对象的两种方法

1.通过ActionContext的方法,如上面的代码所示。

2.通过request。struts2将值栈存入request一份。如下

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

向值栈中存入数据

1.在action中提供属性get方法的方式:(部分代码) 默认将数据不存在栈顶

public class ValueStackDemo3 extends ActionSupport {
	//action会被压入值栈中,所以属性也会被压入值栈中,我们只需要提供get方法即可
	User user ;
	public User getUser() {
		return user;
	}
	@Override
	public String execute() throws Exception {
		user = new User("mlgg", "213");
		return SUCCESS;
	}
}

取值:

<s:debug></s:debug>
<s:property value="user.username"/>
<s:property value="user.password"/>

2.使用ValueStack中本身的方法方式(部分代码)这种方式将数据存在栈顶

public class ValueStackDemo4 extends ActionSupport {
	@Override
	public String execute() throws Exception {
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		User user = new User("aloha","keep moving");
		//方式一
		valueStack.push(user);//压栈
		
		//方式二:这种方式可以压栈,但是在debug标签中显示为null,我们可以手动获取到jsp页面
		valueStack.set("zyf", "upup");
		return super.execute();
	}
}

debug标签执行结果(未写方式二前):

可以看到此时的栈顶是User对象   username  aloha   ,这时我们在jsp中获取值不能使用user.username等的方式,只能使用下面的方式直接获取:

<s:property value="username"/>
<s:property value="password"/>
<!-- 方法二 -->
<s:property value="zyf"/>

在root中获取数据&在context中获取数据

public class ValueStackDemo5 extends ActionSupport {
	@Override
	public String execute() throws Exception {
		//向堆栈中保存数据
		User user = new User("java","no.1");
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		valueStack.push(user);
		//向集合中保存数据
		List<User> list = new ArrayList<User>();
		list.add(new User("python", "to be no.1"));
		list.add(new User("javascript", "you don't know me"));
		list.add(new User("go", "small King"));
		ActionContext.getContext().getValueStack().set("list", list);
		//向context中保存数据,这些数据可以在debug标签中找出
		ServletActionContext.getRequest().setAttribute("name", "aloha");
		ServletActionContext.getRequest().getSession().setAttribute("name", "mlgg");
		ServletActionContext.getServletContext().setAttribute("name", "sugarcane");
		return super.execute();
	}
}
<s:property value="username"/>
<s:property value="password"/><br/>
<!-- 获取集合中的数据 -->
<s:property value="list[0].username"/>
<s:property value="list[0].password"/><br/>
<s:property value="list[1].username"/>
<s:property value="list[1].password"/><br/>
<s:property value="list[2].username"/>
<s:property value="list[2].password"/><br/>
<!-- 获取context中的数据 -->
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#attr.name"/>
<s:property value="#parameters.id"/>

结果:

注意:attr获取的是request中的数据。如果request中没有数据,那么获取的是session中的数据;如果session中没有数据,那么获取的是application中的数据。

struts2对EL表达式进行了增强

对request.getAttribute(String name)方法进行了增强。所以在struts2框架中EL表达式也可以进行获取对象。

OGNL中的特殊字符

#

获取context的数据

构建map集合

<body>
<h1>#的用法</h1>
<h3>1.获取context数据</h3>
<%
	request.setAttribute("aloha", "go down");
 %>
 <s:property value="#request.aloha"/>
 <h3>2.创建map集合</h3>
 <s:iterator var="i" value="{'aa','bb','cc','dd'}"><!-- 默认把这个装为list集合 -->
 	<s:property value="i"/> -- <s:property value="#i"/><br/>
 </s:iterator><br/>
 <h3>3.创建map集合</h3>
 <s:iterator value="#{'aa':'11','bb':'22','cc':'33'}">
 	<s:property value="key"/> -- <s:property value="value"/><br/>
 </s:iterator><br/>
  <s:iterator var="entry" value="#{'aa':'11','bb':'22','cc':'33'}">
 	<s:property value="#entry.key"/> -- <s:property value="#entry.value"/><br/>
 </s:iterator>
 <hr/>
 <s:radio list="{'男','女'}" name="sex" label="性别" /><br/>
 <s:radio list="#{'1':'男','2':'女' }" name="sex1" label="性别(Map)" />
 <s:debug></s:debug>
</body>

radio中的1,2构成map集合的键,作用同于<input>标签中的value的值。map集合的值相当于input标签外的显示。

%(基本没什么卵用)

1.强制解析OGNL

应用场景:struts2标签不能嵌套,比如我们要在s:textfield文本框的value赋值,那么是 不能直接把一个OGNL表达式放里边的,直接写也不解析。

我们给它写在%{}中,可强制解析

	<%
		request.setAttribute("aloha", "love_java");
	 %>
	 what aloha love?<s:textfield name="aloha" value="%{#request.aloha}" />

2.强制不解析OGNL(不常用)

我们把表达式写在%{' '}中强制不解析

$

在配置文件(xml、属性文件)使用,属性文件主要在国际化中使用,我国做的软件不做国际化!咋地?

在配置文件中从值栈中获取变量的值。比如在配置文件中提供下载链接提供值栈中的链接。

猜你喜欢

转载自blog.csdn.net/weixin_38930706/article/details/81771458