Struts学习笔记(三)OGNL&ValueStack

OGNL

简介

OGNL(Object-Graph Navigation Language)对象图导航语言,用于存取对象的任意属性,调用对象方法,遍历整个对象的结构图。${user.addr.name} 这种写法就叫对象视图导航。

OGNL作用

对象方法调用
类静态方法调用和值访问
支持赋值操作和表达式串联
访问OGNL上下文(OGNL context)和ActionContext
操作集合对象

OGNL三要素

1.表达式
表示操作要做什么
2.根对象Root
规定了对谁操作。OGNL的所谓对象图,就是以任意一个对象为根,通过OGNL访问与这个对象关联的其他对象。
3.Context对象
root对象所在环境的就OGNL的上下文环境Context。规定了操作在哪儿进行。context是一个Map类型的对象,在表达式中访问context中的对象,需要用#号加上对象名称,"#对象名"

OGNL入门

1.OGNL调用对象的方法

	//OGNL调用对象的方法
	@Test
	public void demo1() throws OgnlException{
		//获得context
		OgnlContext context=new OgnlContext();
		//获得根对象
		Object root=context.getRoot();
		//执行表达式
		Object obj = Ognl.getValue("'helloWord'.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("@java.lang.Math@random()", context, root);
		System.out.println(obj);
	}

3.访问Root中的数据:不用加#

//访问Root中的数据
	@Test
	public void demo3() throws OgnlException{
		//获得context
		OgnlContext context=new OgnlContext();
		//向root存数据
		context.setRoot(new User("aaa","123"));
		//获得根对象
		Object root=context.getRoot();

		Object username=Ognl.getValue("username", context, root);
		Object password=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 name=Ognl.getValue("#name", context, root);
		System.out.println(name);
	}

值栈

值栈概述

ValueStack是struts2的一个接口,客户端每发起一个请求,框架就会创建一个action实例同时创建一个OGNLValueStack(接口的实现类),贯穿整个action生命周期。框架会用OGNL将请求的参数封装为对象存到值栈里面,再用OGNL表达式来取值栈的对象属性。所以说,值栈很像是一个临时的货架。

值栈内部结构

root:CompoundRoot
继承ArrayList实现压栈出栈功能、存储action实例以及请求的参数等
context:OGNLContext
是一个map结构,上下文中存储了一些引用:parameters、request、response、session、application等,attr(该map按照request、session、application顺序检索属性)。它的root就是那个CompoundRoot

ActionContext和ValueStack的关系

创建ActionContext时创建ValueStack对象,将ValueStack对象给ActionContext
ActionContext里有一个ValueStack的引用。ValueStack里也有一个ActionContext的引用
ActionContext获取ServletAPI的时候,依赖值栈了

//在StrutsPrepareAndExecuteFilter-doFilter中有一句
prepare.createActionContext(request, response);
//去PrepareOperations中去找到createActionContext,发现了以下代码
ValueStack stack=dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
ctx = new ActionContext(stack.getContext());
获得值栈

1.通过ActionContext(它里面有值栈,值栈里也有它,参考上边代码)

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

2.通过request域获取值栈

ValueStack valueStack2=(ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
//key记不住就写:ServletActionContext.STRUTS_VALUESTACK_KEY
操作值栈

1.对action中的属性提供get方法
因为action本来就在值栈里,action的属性也在里面。

//操作ValueStack:方式一.利用action本身就在值栈中的特性来操作
public class ValueStackDemo3 extends ActionSupport{
	private User user;
	public User getUser() {
		return user;
	}
	@Override
	public String execute() throws Exception {
		//向ValueStack存值
		user=new User("张三","233");
		return SUCCESS;
	} 
}

2.使用ValueStack本身的方法
调用之战的push和set方法对值栈进行操作

//操作ValueStack:方式二.调用值栈中的方法实现
public class ValueStackDemo4 extends ActionSupport{
	@Override
	public String execute() throws Exception {
		//向值栈中保存数据
		ValueStack valueStack=ActionContext.getContext().getValueStack();
		//使用push(object);set(String key,Object obj);
		User user=new User("李四","594");
		//现在user在栈顶的位置
		valueStack.push(user);
		valueStack.set("myname", "刘振宇");//创建map集合,将map押入栈顶
		return super.execute();
	}
}
从值栈获取数据

0.准备工作:先存数据

public class ValueStackDemo5 extends ActionSupport{
	@Override
	public String execute() throws Exception {
		//向值栈中保存一个对象
		User user=new User("对象","888");
		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"));
		ActionContext.getContext().getValueStack().set("list", list);
		//向context中存入数据
		ServletActionContext.getRequest().setAttribute("name", "attribute_name");
		ServletActionContext.getRequest().getSession().setAttribute("name", "session_name");
		ServletActionContext.getServletContext().setAttribute("name", "application_name");
		return super.execute();
	}
}

1.1页面OGNL-获取对象数据

<!-- 获取一个对象的数据 -->
<s:property value="username" />
<s:property value="password" /><br/>

1.2页面OGNL-获取集合数据

<!-- 获取集合中的数据 -->
<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/>

2.获取context数据

<!-- 获取context中的数据 -->
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/><br/>
<s:property value="#attr.name"/>
<s:property value="#parameters.id"/>
EL为何能访问值栈

原码:StrutsRequestWrapper类-getAttribute方法
对request进行了包装,会自动去值栈中寻找

//StrutsRequestWrapper-getAttribute
public Object getAttribute(String key) {
        if (key == null) {
            throw new NullPointerException("You must specify a key value");
        }

        if (disableRequestAttributeValueStackLookup || key.startsWith("javax.servlet")) {
            // don't bother with the standard javax.servlet attributes, we can short-circuit this
            // see WW-953 and the forums post linked in that issue for more info
            return super.getAttribute(key);
        }

        ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(key);

        if (ctx != null && attribute == null) {
            boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));

            // note: we don't let # come through or else a request for
            // #attr.foo or #request.foo could cause an endless loop
            if (!alreadyIn && !key.contains("#")) {
                try {
                    // If not found, then try the ValueStack
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
                    ValueStack stack = ctx.getValueStack();
                    if (stack != null) {
                        attribute = stack.findValue(key);
                    }
                } finally {
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
                }
            }
        }
        return attribute;
    }
EL的特殊字符使用

1.#号
1.1获取context数据

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

1.2用于构建一个map集合

<h3>2.构建map集合</h3>
//对照组
<s:iterator var="i" value="{'aa','bb','cc'}">
	<s:property value="i"/>--<s:property value="#i"/></br>
</s:iterator>
//使用#
<s:iterator var="entry" value="#{'aa':'11','bb':'22','cc':'33'}">
	<s:property value="key"/>--<s:property value="value"/><br/>//方式一
	<s:property value="#entry.key"/>--<s:property value="#entry.value"/><br/>//方式二
</s:iterator>

2.%
2.1强制解析OGNL表达式
2.2强制不解析OGNL

<h1>%的用法</h1>
<%
	request.setAttribute("name", "王五");
%>
<s:property value="#request.name"/><br/>//正常解析
<s:property value="%{'#request.name'}"/><br/><!-- 强制不解析 -->
<s:textfield name="name" value="%{#request.name}"></s:textfield><!-- 强制解析 -->
<s:textfield name="name" value="#request.name"></s:textfield>//没法解析(在textfield里)

3.$
在配置文件中使用。.XMl文件或者属性文件

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值