Struts2框架基本学习(三) -- OGNL和值栈

一、OGNL

1、OGNL概述

(1) OGNL的概念

对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression Language),它被集成在Struts2等框架中,作用是对数据进行访问,它拥有类型转换、访问对象方法、操作集合对象等功能。
–百度百科

OGNL:对象图导航语言,比EL表达式强大很多倍的语言。调用对象的方法,获取struts2的值栈的数据。OGNL其实是一个第三方的表达式语言。
EL:从域对象中获取数据,从EL的11个对象中获取。 n a m e { name } name{ pageContext.request.contextPath }

(2) OGNL的特点

  1. 支持对象方法调用,如xxx.doSomeSpecial();
  2. 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format(‘foo %s’, ‘bar’)或@tutorial.MyConstant@APP_NAME;
  3. 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(price*discount),这个表达式会返回80;
  4. 访问OGNL上下文(OGNL context)和ActionContext;
  5. 操作集合对象。
  6. 可以直接new一个对象

(3) OGNL使用的要素

  • 表达式
  • 跟对象
  • Context对象

2、OGNL的Java环境入门(了解)

(1) 访问对象的方法

	@Test
	/**
	 * OGNL调用对象的方法
	 */
	public void demo1() throws OgnlException {
		// 获得context
		OgnlContext context = new OgnlContext();
		// 获得跟对象
		Object root = context.getRoot();
		// 执行表达式
		Object object = Ognl.getValue("'helloworld'.length()", context, root);
		System.out.println(object);
	}

(2) 访问对象的静态方法

	@Test
	// 访问对象的静态方法
	public void demo2() throws OgnlException {
		// 获得context
		OgnlContext context = new OgnlContext();
		// 获得跟对象
		Object root = context.getRoot();
		// 执行表达式:@类名@方法名
		Object obj = Ognl.getValue("@java.lang.Math@random()", context, root);
		System.out.println(obj);		
	}

(3) 获得Root中的数据

  访问Root中的数据,不需要加 #

	@Test
	// 访问Root中的数据,不需要加#
	public void demo3() throws OgnlException {
		// 获得context
		OgnlContext context = new OgnlContext();
		
		User user = new User("Brown", "123456");
		context.setRoot(user);
		
		// 获得跟对象
		Object root = context.getRoot();
		
		Object username = Ognl.getValue("username", context, root);
		Object password = Ognl.getValue("password", context, root);
		System.out.println(username + "   " + password);
	}

(4) 获得OgnlCOntext中的数据

  访问Context中的数据,需要加 #

	@Test
	// 访问Context中的数据,需要加#
	public void demo4() throws OgnlException {
		// 获得context
		OgnlContext context = new OgnlContext();
		
		// 获得跟对象
		Object root = context.getRoot();
		// 向Context中存入数据
		context.put("name", "Browen");
		// 执行表达式
		Object obj = Ognl.getValue("#name", context, root);
		System.out.println(obj);
	}

3、OGNL的Struts2环境入门

(1) 访问对象的方法

jsp文件:

<h1>OGNL在struts2环境入门</h1>
<h3>调用对象的方法</h3>
<s:property value="'struts'.length()"/>

(2) 访问对象的静态方法

jsp文件:

<h3>调用对象的静态方法</h3>
<!-- 静态方法的访问默认是关闭的,需要开启常量 -->
<s:property value="@java.lang.Math@random()"/>

在struts.xml中打开静态方法常量:

<!-- 开启静态方法访问 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

二、值栈

1、值栈的概述

(1) 什么是值栈

  ValueStack是Struts的一个借口,字面意思为值栈,OgnlValueStack是ValueStack的实现类,客户端发出一个请求,struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例。OgnlValueStack贯穿整个Action的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。

  ValueStack其实类似于一个数据中转站(Struts2的框架当中的数据就都保存到了ValueStack中)。

  • ValueStack接口,实现类OgnlValueStack对象。
  • ValueStack贯穿整个Action的生命周期。(Action一旦创建,框架就会创建一个ValueStack对象)。

(2) 值栈的内部结构

  1. ValueStack中有两个主要区域:
  • root区域:其实就是一个ArrayList,里面一般放置对象。获取root的数据不需要加#号。
  • context区域:其实就是一个Map,里面放置的是web开发的常用的对象数据的引用。获取context数据需要加#号。
    • request
    • session
    • application
    • parameters
    • attr:从小范围查找数据。
  1. 所说的操作值栈,通常指的是操作的ValueStack中的root区域。

在这里插入图片描述

(3) 值栈与ActionContext的关系

  • ActionContext:Action的上下文。
    • 通过源码查看到:当请求过来的时候, 执行过滤器中doFilter方法,在这个方法中创建ActionContext,在创建ActionContext过程中,创建ValueStack对象,将ValueStack对象传递给ActionContext对象。所以可以通过ActionContext获取值栈对象。
    • ActionContext对象能够访问Servlet的API(访问的是域对象的数据),是因为其内部的值栈的引用。
  • ServletContext:Servlet的上下文。

(4) 获得值栈

  1. 通过ActionContext对象获取值栈。
	// 第一种:通过ActionContext获得:
	ValueStack valueStack = ActionContext.getContext().getValueStack();

  1. 在Struts2的内部,将值栈存入request中一份。
	// 第二种:通过request对象获得:
	// struts.valueStack
		ValueStack valueStack2= (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

(5) 值栈操作 - 向值栈中存入数据

  1. 第一种:在Action中提供属性的get方法的方式
    • 默认的情况下,将Action对象压入值栈。Action的属性也会在值栈中。

Action:

public class ValueStackDemo3 extends ActionSupport {

	private User user;
	public User getUser() {
		return user;
	}
	@Override
	public String execute() throws Exception {
		// 向ValueStack中存值
		user = new User("李末", "569");
		return SUCCESS;
	}
}

对应的JSP:

<!-- 方式一的获取:利用Action在值栈中的特性 -->
<s:property value="user.username"/>
<s:property value="user.password"/>
  1. 使用ValueStack中本身的方法的方式

Action :

public class ValueStackDemo4 extends ActionSupport{

	@Override
	public String execute() throws Exception {
		// 向值栈中保存对象
		// 获得值栈对象:
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		// 使用push(Object obj); set(String key, Object obj);
		User user = new User("赵亮", "38");
		// 现在user在栈顶
		valueStack.push(user);
		
		valueStack.set("name", "小刘");// 创建一个Map集合,将Map压入栈中。
		
		return super.execute();
	}
}

对应的JSP:

<!-- 方式二的获取:调用ValueStack本身的方法 -->
<s:property value="username"/>
<s:property value="password"/>
<s:property value="name"/>

(6) 获取值栈中的数据

获取值栈中的数据就是在页面中使用OGNL表达式即可。

  1. 获取root的数据:不需要加“#
<!-- 获取一个对象的属性 -->
<s:property value="username"/>
<s:property value="password"/>
<!-- 获取集合当中的属性 -->
<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/>
  1. 获取context数据
<!-- 获取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"/>

对应的向context中保存数据:

// 向context中存入数据:
ServletActionContext.getRequest().setAttribute("name", "r李末");
ServletActionContext.getRequest().getSession().setAttribute("name", "s赵亮");
ServletActionContext.getServletContext().setAttribute("name", "al刘铭");

(7) EL为何访问值栈数据

  因为Struts2的框架的底层对request.getAttribute(String name)进行了增强。
在这里插入图片描述

三、OGNL中特殊字符

1、#号

(1)、获取context的数据

<h3>获取context的数据</h3>
<%
	request.setAttribute("name", "李末");
%>
<s:property value="#request.name"/>

(2)、使用#号构建Map集合

<h3>构建Map集合</h3>
<s:iterator var="i" value="{ 'aa','bb','cc' }">
	<s:property value="i"/> -- <s:property value="#i"/><br/>
</s:iterator>

性别:<input type="radio" name="sex3" value="1"><input type="radio" name="sex3" value="2"><hr/>
<s:radio list="#{ '1':'', '2':'' }" name="sex4" label="性别"></s:radio>

2、%号

(1)、强制解析OGNL

<h1>%号的用法</h1>
<%
	request.setAttribute("name", "李末");
%>
姓名:<s:textfield name="name" value="%{ #request.name }"/>

(2)、强制不解析OGNL(没用)

<s:property value="%{'#request.name'}"/>

3、$号

(1)、在配置文件中使用OGNL

  1. 属性文件
    国际化的地方使用

    • message_zh_CN.properties
      user.login=登陆
      user.welcome=欢迎,${#session.username};
    • message_en_US.propertise
      user.login=Login
      user.welcome=Welcome,${#session.username};
  2. XML文件
    文件下载的时候使用

    • 配置:
<action name="download" class="xxx.DownloadAction">
		<result type="stream">
			<param name="Context-Type">文件类型</param>
			<param name="Context-Disposition">attachment;filename=${文件名}</param>
		</result>
</action>

四、综合案例:优化查询

1、代码实现

(1)、将查询到的数据存入到值栈中

	// 查询客户列表的方法
	public String find() {
		// 调用业务层
		CustomerService customerService = new CustomerServiceImpl();
		List<Customer> list = customerService.find();
		// 页面跳转
		//ServletActionContext.getRequest().setAttribute("list", list);
		
		// 将查询到的list存入到值栈中
		ActionContext.getContext().getValueStack().set("list", list);
		return "findSuccess";
	}

(2)、在页面中用OGNL表达式获取

  • 不定义var
<s:iterator value="list">
	<TR
		style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
		<TD><s:property value="cust_name"/></TD>
		<TD><s:property value="cust_level"/></TD>
		<TD><s:property value="cust_source"/></TD>
		<TD><s:property value="cust_industry"/></TD>
		<TD><s:property value="cust_phone"/></TD>
		<TD><s:property value="cust_mobile"/></TD>
		<TD><a
			href="${pageContext.request.contextPath }/">修改</a>
			&nbsp;&nbsp; <a
			href="${pageContext.request.contextPath }/">删除</a>
		</TD>
	</TR>
</s:iterator>
  • 定义var
    定义var后,把数据保存到了context区域中了。
<s:iterator var="c" value="list">
	<TR
		style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
		<TD><s:property value="#c.cust_name"/></TD>
		<TD><s:property value="#c.cust_level"/></TD>
		<TD><s:property value="#c.cust_source"/></TD>
		<TD><s:property value="#c.cust_industry"/></TD>
		<TD><s:property value="#c.cust_phone"/></TD>
		<TD><s:property value="#c.cust_mobile"/></TD>
		<TD><a
			href="${pageContext.request.contextPath }/">修改</a>
			&nbsp;&nbsp; <a
			href="${pageContext.request.contextPath }/">删除</a>
		</TD>
	</TR>
</s:iterator>

  最近几天遇到一些事,学习效率不高,Struts2第三次笔记迟迟没有完成。。。。哎,继续努力。加油!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值