Struts2框架(三):OGNL表达式与值栈

Struts2系列文章推荐:
👉 Struts2框架(一):入门xml配置及action编写
👉 Struts2框架(二):封装方法&其他介绍&注入方式详解
👉 Struts2框架(四):控制器&其他OGNL标签&拦截器
👉 待更新

1、OGNL初识

OGNL的概述

什么是OGNL
OGNL表达式
 OGNL:对象图导航语言,比EL表达式强大很多倍的语言
   EL:从域对象中获取数据,从EL的11个对象中获取
   OGNL:调用对象的方法,获取Struts2的值栈的数据,OGNL其实是第三方的表达式语言,与Struts2无关,可独立运行
为什么要学习OGNL
OGNL作用
OGNL使用的要素
*表达式  *根对象  *Context对象

OGNL的入门
OGNL的入门:Java环境入门(了解)

访问对象的方法

@Test
public void test1() throws OgnlException{
	//获得OgnlContext
	OgnlContext context = new OgnlContext();
	//获得Root
	Object root = context.getRoot();
	//书写表达式并执行
	Object value = Ognl.getValue("'helloworld'.length()", context, root);
	System.out.println(value);
}

访问对象的静态方法

@Test
public void test2() throws OgnlException{
	//获得OgnlContext
	OgnlContext context = new OgnlContext();
	//获得Root
	Object root = context.getRoot();
	//书写表达式并执行,使用静态方法要加@
	Object value = Ognl.getValue("@java.lang.Math@random()", context, root);
	System.out.println(value);
}

获得Root中的数据

@Test
public void test3() throws OgnlException{
	//获得OgnlContext
	OgnlContext context = new OgnlContext();
	//先往Root中存储一些数据,比如对象
	context.setRoot(new Customer("钻石王老五","黄老板推荐的"));
	//获得Root
	Object root = context.getRoot();
	//书写表达式并执行
	Object value = Ognl.getValue("cust_name", context, root);
	System.out.println(value);
}

获得OGNLContext中的数据

@Test
public void test4() throws OgnlException{
	//获得OgnlContext
	OgnlContext context = new OgnlContext();
	//获得Root
	Object root = context.getRoot();
	//先往Context中存储一些数据,比如对象
	Map<String, String> map = new HashMap<String,String>();
	map.put("cust_source", "黄老板推荐的");
	context.setValues(map);
	//书写表达式并执行,获取Context中的值要在前加#
	Object value = Ognl.getValue("#cust_source", context, root);
	System.out.println(value);
}
OGNL的入门:Struts2环境入门

访问对象的方法

<!-- Struts中使用OGNL -->
<h3>调用对象的方法</h3>
<s:property value="'helloworld'.length()"/>

访问对象的静态方法

<!-- 静态方法在Struts2中默认关闭,需在struts.xml中配置常量
	struts.ognl.allowStaticMethodAccess = true-->
<h3>调用对象的静态方法</h3>
<s:property value="@java.lang.Math@random()"/>

2、ValueStack

ValueStack的概述

什么是值栈
 Struts2将XWork对Ognl的扩展这一套机制封装起来,这个对象叫ValueStack。
 ValueStack实际上就是一个容器。它由Struts框架创建,当前端页面如jsp发送一个请求时,Struts的默认拦截器会将请求中的数据进行封装,并入ValueStack的栈顶。
 类似于一个数据中转站,Struts2框架中的数据都保存到了ValueStack中
 ValueStack贯穿整个Action的生命周期。Action一旦创建了,框架就会创建一个ValueStack对象,这个对象在配置文件、Action、JSP都能取到

ValueStack的内部结构

 ValueStack中有两个主要的区域(获取root不用加#)
值栈结构
   root区域:其实就是一个ArrayList,里面一般放置对象
   Context区域:其实就是一个Map,里面放置的是web开发中常用的对象数据的引用
     request:该 Map 中包含当前 request 对象中的所有属性。
     session:该 Map 中包含当前 session 对象中的所有属性。
     application:该 Map 中包含当前 application 对象中的所有属性。
     parameters:该 Map 中包含当前请求的请求参数。
     attr:该 Map 按如下顺序检索某个属性:request,session,application。
 所说的操作值栈,通常指的是操作ValueStack中的Root区域
注意:在 context 对象中包含了 root 对象,从 context 对象的结构中就可以查看到相关信息
值栈结构
除了上面查看值栈结构的方式之外,也可以通过页面的方式查看,首先新建一个bean,在传入一个bean对象并转发到jsp中,jsp页面代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>属性驱动方式获取值栈中的数据</title>
</head>
<body>
    <s:debug></s:debug>
    姓名:<s:property value="user.name"/><br/>
    年龄:<s:property value="user.age"/>
</body>
</html>

此时在页面中点击debug即可查看完整信息,并且存的值也可以看到。这里的contents为栈存储
值栈结构3

ValueStack与ActionContext的关系

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

ValueStack的获得

 通过ActionContext对象获得值栈
 在Struts2的内部,将值栈存入request中一份

//第一种:通过ActionContext获得
ActionContext.getContext().getValueStack();
//第二种:通过request对象获得
ServletActionContext.getRequest().getAttribute("struts.valueStack");//1
ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);//2
ValueStack的操作-向值栈中存入数据

 第一种:在Action中提供属性的get方法的方式
   默认情况下,会将Action对象压入到值栈,Action中的属性(对象)也会到栈中

//Action中
public String showinfo(){
	user = new User("黄老板","123456");
	return "show_info";
}
//JSP中
<s:debug/>
<h3><s:property value="user.username"/></h3>
<h3><s:property value="user.password"/></h3>

 第二种:使用ValueStack中本身的方法的方式

//Action中
public String showinfo2(){
	//获得值栈对象
	ValueStack valueStack = ActionContext.getContext().getValueStack();
	//使用Push(Object obj);、set(String key,Object obj);保存数据,后者保存在map中
	user = new User("黄老板","456789");
	valueStack.push(user);//压栈,在栈顶
	
	valueStack.set("name", "黄先生");//将map压栈,谁靠后谁栈顶
	return "show_info";
}

默认存到栈顶
注意:这里name在debug中为null,是因为没有设置get方法,但是还是能通过OGNL表达式取出

获取ValueStack中的数据

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

  • 获取Root的数据
    //Java中
    public String showinfo(){
    	//获得值栈对象
    	User user = new User("黄老板","456789");
    	ValueStack valueStack = ActionContext.getContext().getValueStack();
    	valueStack.push(user);//压栈,在栈顶
    	return "show_info";
    }
    public String showinfo2(){
    	List<User> list = new ArrayList<User>();
    	User user1 = new User("蓉老板","1");
    	User user2 = new User("嬷老板","2");
    	User user3 = new User("嬷老板","3");
    	list.add(user1);list.add(user2);list.add(user3);
    	//获得值栈对象
    	ValueStack valueStack = ActionContext.getContext().getValueStack();
    	valueStack.set("list",list);//压栈,在栈顶
    	return "show_info";
    }
    //JSP中
    !-- 获取一个对象的数据 -->
    <h3><s:property value="username"/>
    <s:property value="password"/></h3>
    <!-- 获取集合中的数据 -->
    <h3><s:property value="list[0].username"/>
    <s:property value="list[0].password"/></h3>
    <h3><s:property value="list[1].username"/>
    <s:property value="list[1].password"/></h3>
    <h3><s:property value="list[2].username"/>
    <s:property value="list[2].password"/></h3>
    
  • 获取Context的数据
    //Java中
    public String showinfo3(){
    	List<User> list = new ArrayList<User>();
    	User user1 = new User("蓉老板","1");
    	User user2 = new User("嬷老板","2");
    	User user3 = new User("嬷老板","3");
    	list.add(user1);list.add(user2);list.add(user3);
    	//获得值栈对象
    	ServletActionContext.getRequest().setAttribute("list", list);
    	ServletActionContext.getRequest().getSession().setAttribute("list", list);
    	ServletActionContext.getServletContext().setAttribute("list", list);
    	return "show_info";
    }
    //JSP中
    <!-- 获取集合中的数据 -->
    <h3><s:property value="#request.list[0].username"/>
    <s:property value="#request.list[0].password"/></h3>
    <h3><s:property value="#session.list[1].username"/>
    <s:property value="#session.list[1].password"/></h3>
    <h3><s:property value="#application.list[2].username"/>
    <s:property value="#application.list[2].password"/></h3>
    <h3><s:property value="#attr.list"/>
    <s:property value="#parameters.name"/></h3>
    

注意:这里的parameters为获取页面传递的参数

获取ValueStack中的数据

Struts2的框架的底层对request.getAttribute实现了增强,如果在request中可以直接获取到,那就返回,如果获取不到就在值栈中获取
EL表达式取值

3、OGNL表达式中的特殊字符

#号的用法

1、获取context数据 2、构建集合

<h3>使用#构建集合并获取</h3>
<!-- 这里遍历list集合 -->
<s:iterator var="i" value="{'aaa','bbb','ccc'}">
	<!-- 下面的i和#i都一样 -->
	<h4><s:property value="i"/>---<s:property value="#i"/></h4>
</s:iterator>
<!-- 这里遍历map集合 -->
<s:iterator var="i" value="#{'1':'aaa','2':'bbb','3':'ccc'}">
	<!-- 第一种写法:如果上面的map中用了#,下面的i和#i都一样,key+value -->
	<h4>第一种写法:<s:property value="i"/>---<s:property value="#i"/></h4>
	<!-- 第二种写法:key和value分开显示,必须:(#+var.属性) -->
	<h4>第二种写法:<s:property value="#i.key"/>---<s:property value="#i.value"/></h4>
	<!-- 第三种写法:key和value分开显示,直接写属性 -->
	<h4>第三种写法:<s:property value="key"/>---<s:property value="value"/></h4>
</s:iterator>
<h3>使用#创建单选框</h3>
<!-- 如果key与value一样用list集合 -->
<s:radio list="{'aa','bb','cc'}" name="sex1" label="性别"/><br/>
<!-- 如果key与value不一样用map集合 -->
<s:radio list="#{'1':'aaa','2':'bbb','3':'ccc'}" name="sex2" label="性别"/>

注意:
1、只要有关是map的,都必须在前面加#
2、radio的中,map和list都用list=""
3、当单选框内容与value一致就用list,不一致用map
4、一旦定义了var,那就在前面加#(统一规范)

%号的用法

强制解析OGNL
强制不解析OGNL(基本不用)

<s:debug/>
<h3>%号的用法</h3>
<%
	request.setAttribute("name","小李");
%>
姓名:<s:textfield name="name" value="%{#request.name}" />
<!-- 强制不解析 -->
<s:property value="%{'#request.name'}" />

注意: 强制解析就是%{OGNL表达式},不解析就是%{‘OGNL表达式’}

$号的用法

在配置文件中使用OGNL
 属性文件
   国际化地方:
     message_zh_CN.properties
     user.login=登陆
     user.welcome=欢迎,${#session.user.username}
     message_en_US.properties
     user.login=Login
     user.welcome=Welcome,${#session.user.username}
 xml文件
   文件下载:
     配置

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

4、综合案例CRM的查询优化

将查询到的数据存到值栈中
ActionContext.getContext().getValueStack().set("list", service.find());
页面中用OGNL表达式取值

<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 }/customerServlet?method=edit&custId=<s:property value="cust_id"/>">修改</a>
	&nbsp;&nbsp;
	<a href="${pageContext.request.contextPath }/customerServlet?method=delete&custId=<s:property value="cust_id"/>">删除</a>
	</TD>
</TR>
</s:iterator>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hillain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值