Ognl表达式&值栈

目录

 

一.Ongl表达式的使用

1.1 什么是Ognl​

1.2 Ongl的功能

1.3 Ognl的要素

1.3 Ognl入门案例

二.值栈

2.1 什么是值栈

2.2 值栈的内部结构

2.3 ActionContext 与 ValueStack的关系

2.4 获取值栈对象

2.5 操作值栈

2.6 获取ValueStack中的数据

2.7 EL访问ValueStack

三.OGNL中特殊符号的使用:

3.1 #号

3.2 %号

3.3 $号


一.Ongl表达式的使用

1.1 什么是Ognl

1.2 Ongl的功能

1.3 Ognl的要素

1.3 Ognl入门案例

二.值栈

2.1 什么是值栈

总结:

  • 当浏览器访问action的时候,会被前端控制器(StrutsPrepareAndExecuteFilter)拦截住,在filter中创建值栈(ValueStack)对象(特点:访问一次,创建一次)
  • 创建完以后,会将访问的整个action对象放在ValueStack中,还会将request,session,servletContext对象的底层用来存储数据的map数据集合放在ValueStack中
  • 还会将当前页面提交的所有数据以map的方式也存放在ValueStack中(ps:存放的都是地址引用)
  •  
  • 当整个action执行完毕,action对象会被销毁,ValueStack对象也会被销毁下次访问又是一个新的aciton对象和新的ValueStack对象
  • 也就是说:aciton的生命周期和ValueStack是同步的,ValueStack会伴随action一
  • ValueStack: 是struts2提供了一个接口 真正的实现类是:OgnlValueStack

2.2 值栈的内部结构

 

 

2.3 ActionContext 与 ValueStack的关系

  • 为什么可以通过ActionContext获得值栈?

ActionContext:创建Action实例的时候,创建值栈对象,将值栈对象存入到ActionContext中。

    public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {
            counter = oldCounter + 1;
        }
        
        ActionContext oldContext = ActionContext.getContext();
        if (oldContext != null) {
            // detected existing context, so we are probably in a forward
            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
        } else {
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
            ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
        ActionContext.setContext(ctx);
        return ctx;
    }

2.4 获取值栈对象

2.5 操作值栈

  • 操作root区
    • 通过值栈中的API方法操作值栈

调用ValueStack中的方法:push(此种方法操作该属性将位于栈顶)

public class ValueStack3Action extends ActionSupport{

	@Override
	public String execute() throws Exception {
		// 获得值栈:
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		/**
		 * ValueStack中的方法:
		 * 	* void set(String key,Object value);  -- 创建一个Map集合,将Map集合存入到值栈(root)中。
		 * 	* void push(Object obj);			  -- 将对象存入到值栈(root)中。
		 * * 栈的特点:先进后出.
		 */
		valueStack.set("name", "王强勇");// 一般list集合使用set
		
		User user = new User();
		user.setUsername("aaa");
		valueStack.push(user); // 一般Object使用push
		
		return SUCCESS;
	}
}

通过Action中提供成员属性的方式(该属性默认不在栈顶不推荐)

Action类默认是在栈中,而且默认情况下是在栈顶的位置。Action已经在值栈中了,现在提供了一个Action的属性,Action的属性也是会在栈中。

public class ValueStack3Action extends ActionSupport{

	private Integer age;
	
	public Integer getAge() {
		return age;
	}
..
}
  • 操作context区(了解)
//上次课用ActionContext访问Servlet的API:
ActionContext act = ActionContext.getContext();
Map<String,Object> sessionMap = act.getSession();
sessionMap.put();

ActionContext中能够访问ServletAPI基于ValueStack来实现的。 

2.6 获取ValueStack中的数据

<h1>获取root区数据</h1>
<h3>获取push的数据</h3>
<s:property value="username"/>
<s:property value="password"/>
<h3>获取set的数据</h3>
<s:property value="user.username"/>
<s:property value="user.password"/>
<h3>获取list集合中的数据</h3>
<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"/>
<br/>

<h1>获取context区数据</h1>
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#parameters.id"/>
<s:property value="#attr.name"/>

2.7 EL访问ValueStack

  • EL获取的数据来源都是四个作用域还有提供11操作web常用的对象。
  • 11个web常用对象:
  • requestScope
  • sessionScope
  • pageScope
  • applicationScope
  • param
  • paramValues
  • header
  • headerValue
  • cookie
  • initparams
  • pageContext
  • 因为Struts2底层对request对象进行包装:
public class StrutsRequestWrapper extends HttpServletRequestWrapper {

    private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute";
    private final boolean disableRequestAttributeValueStackLookup;

    /**
     * The constructor
     * @param req The request
     */
    public StrutsRequestWrapper(HttpServletRequest req) {
        this(req, false);
    }

    /**
     * The constructor
     * @param req The request
     * @param disableRequestAttributeValueStackLookup flag for disabling request attribute value stack lookup (JSTL accessibility)
     */
    public StrutsRequestWrapper(HttpServletRequest req, boolean disableRequestAttributeValueStackLookup) {
        super(req);
        this.disableRequestAttributeValueStackLookup = disableRequestAttributeValueStackLookup;
    }

    /**
     * Gets the object, looking in the value stack if not found
     *
     * @param key The attribute key
     */
    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;
    }
}

三.OGNL中特殊符号的使用:

3.1 #号

  • 获取context中的数据
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#parameters.id"/>
<s:property value="#attr.name"/>
  • 在OGNL中手动构建一个Map集合
<h1>#号构建一个Map集合</h1>
<h3>遍历List集合</h3>
<s:iterator var="i" value="{'aa','bb','cc'}">
	<s:property value="#i"/><br/>
</s:iterator>
<h3>遍历Map集合</h3>
<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>
<h3>使用Struts2UI标签构建Map集合的地方</h3>
传统方式:<br/>
性别:<input type="radio" name="sex" value="男"/>男<input type="radio" name="sex" value="女"/>女<br/>
性别:<input type="radio" name="sex" value="1"/>男<input type="radio" name="sex" value="2"/>女<br/>
Struts2UI标签的方式:<br/>
<s:radio list="{'男','女'}" name="sex" label="性别"/>
<s:radio list="#{'1':'男','2':'女' }" name="sex" label="性别"/>

3.2 %号

  • 强制解析OGNL表达式:

<s:property value=”ognl”/> 一定会执行的。

<%
	request.setAttribute("name", "王强勇");
%>
<input type="text" name="name" value="<s:property value="#request.name"/>"/>
<s:textfield name="name" value="%{#request.name}"/>

3.3 $号

  • 在Struts2的配置文件中使用OGNL表达式
    • 文件下载
<action name=”download” class=””>
	<result name=”” type=”stream”>${fileName}</result>
</action>

猜你喜欢

转载自blog.csdn.net/qq_30162219/article/details/86664202