SSH学习-valueStack和OGNL表达式的使用

Struts2的学习过程中,提到了valueStack和OGNL表达式,这两个是Struts2框架下的概念,这里参考老师授课和博客,进行简单记录和整理,后续有其他理解再添加上去。

概念介绍

(1)valueStack

valueStack是值栈,是Struts2中用户共享数据的一种数据结构,其包含两个区域。

Contents区域

一个是Contents为栈结构(先进后出),也有博客称之为Root区域,主要是一个ArrayList,里面一般放置对象,获取这个区域的数据不需要加#。

浏览器发送一个action请求到服务端filter,会在服务端创建一个action对象和valueStack,将请求所带的数据属性,在contents区域保存,默认值为数据类型初始值,如String类型属性为null,int类型为0,保存到contents区域,当action对象执行使用时,将调用拦截器,将请求中的数据取出来,初始化content区域的属性值,再将contents区域所保存的属性值,赋值给action对象的属性。当action请求结束返回字符串给result后,valueStack将销毁,这就是valueStack的生命周期。

Context区域

另外一个是Context为Map结构,里面放置的是web开发常用的对象数据引用,获取里面的数据需要加#对象名.属性名。常见的几种对象数据引用有(可以通过OGNL表达式的debug标签获取具体内容):

1. Request

2. Session

3. Application

4. Parameters

5. attr

JSP访问方式

1. Contents区域使用OGNL表达式,EL表达式

2. Context区域使用#Key的方式访问对应Value

(2)OGNL表达式

OGNL(Object-Graph Navigation Language),对象图导航语言,OGNL被Struts2整合后将变成它的一种标签,可以在JSP中使用,获取Contents区域的数值。此外它还有其他的强大功能,这里不做详细深究,其他可以参考文末博客。

(3)生命周期

当请求进入服务器端的filter,将创建valueStack对象,当请求结束,valueStack对象将被销毁。

案例测试

案例发送一个action请求到服务端,服务端action请求里有若干属性,在具体的执行方法里,采用两种方式获取valueStack,并往其中一个加入一条对象数据。在JSP页面使用OGNL表达式和EL表达式获取数据进行查看。

(1)struts.xml中的配置

   <!-- 测试保存数据到valueStack中 -->
   <package name="test" namespace="/testValueStack" extends="struts-default">
     <action name="valueStack" class="testValueStack" method="doValueStack">
       <result name="success">
        /WEB-INF/msg.jsp
       </result>
     </action>
   </package>

(2)将push到valueStack栈顶的对象所属类,其中包含message属性。

package Entity;
/**
 * 实体类,用于测试valueStack
 * @author yangchaolin
 */
public class Person {
    
    private int id;
    private String name;
    private String message;//action请求也将有一个同名的属性message
    
    //创建无参数构造方法
    public Person() {
        super();
    }

    //创建有参数构造方法
    public Person(int id, String name, String message) {
        super();
        this.id = id;
        this.name = name;
        this.message = message;
    }

...省略get set方法

}

(3)action请求处理类,其中也包含一个message属性,跟action中的属性同名同类型。另外session中以key为name也放入了一条数据,其中Person对象中也有属性name。

package Controller;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;

import Entity.Person;

/**
 * 控制器类
 * @author yangchaolin
 */
@Controller
@Scope("prototype")
public class testValueStack {
    
    private String message;//Person实体类也有同名的属性message

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    
    //具体实现方法
    public String doValueStack() {
        
        //给属性赋值
        message="我是action请求中的message";
        //创建person对象
        Person p=new Person(1,"我是Person对象中的name","我是Person对象中的message");
        //将person对象添加到valueStack中
        //action执行的所需的对象保存在ActionContext,如参数,session等
        
        //第一种获取valueStack的方式,根据ActionContext获得
        ActionContext ctx=ActionContext.getContext();
        ValueStack stack=ctx.getValueStack();
        stack.push(p);
        //第二种获取valueStack的方式,根据request对象获得
        HttpServletRequest request=ServletActionContext.getRequest();
        //key为struts.valueStack
        ValueStack stack_compare=(ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
        System.out.println("两种获取得到的valueStack相同吗?"+(stack==stack_compare));
        
        //session中也保存一条数据
        ctx.getSession().put("name", "我是Session中的name");
        
        return "success";
    }

}

(4)JSP页面,引入了Struts2的标签库,这样就可以使用OGNL表达式,EL表达式可以直接使用。

<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!-- 引入Struts2中的标签库 -->
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试valueStack</title>
</head>
<body style="font-family:'微软雅黑';font-size:15px;">
     <h2>使用OGNL表达式</h2>
     <s:property value="message"></s:property><br>
     <!-- 获取同名message -->
     <s:property value="[1].message"></s:property><br>
     <s:property value="#session.name"></s:property><br><!-- 通过key获取 -->
      
     <h2>使用EL表达式</h2>    
     ${message}<br>
     ${name}   
     
     <!-- OGNL和EL表达式获取的都是contents区域中的值 -->
     
     <h2>输出valueStack中的数据,使用debug标签</h2>
     <s:debug></s:debug>
</body>
</html>

测试结果

(1)OGNL表达式和EL表达式获取值结果

 从测试结果可以看出来OGNL和EL表达式都可以从Contents区域获取数据,其中message都是Person对象中的message,而不是action对象中的message,是因为action中的message先存到了栈里面,使用表达式取值时是从栈顶往下扫描的,因此先扫描到了Person对象中的message后不再往下扫描,所以的两个表达式获取的都是Person对象中的。而使用EL表达式获取的也是Person对象中,而不是session中的,说明session中的值需要使用#Key的方式获取。

此外两种获取valueStack的方式表明,两者获取的valueStack是一样的。

 (2)debug标签获取Contents和Context中的内容

从结果可以直观的看到数据存储的地方,进而加强对valueStack和OGNL表达式的理解。可以看出session中的name,保存在了Context区域,只能通过#key的方式获取值。而message保存也是先保存了action中的message,后面执行了action中方法后,将Person对象push到栈顶后,才出现第二个message。如果要获取第二个message,需要在JSP中使用[1].message来得到。

结论

(1)valueStack是封装了action请求中数据的一种特殊数据结构,其中包含Contents区域和Context区域。

(2)获取Contents区域需使用OGNL表达式或EL表达式,获取Context区域数据使用#Key方式

(3)valueStack当action请求结束后将消失。

参考博文:https://blog.csdn.net/qq_23853743/article/details/84664867

原文地址:https://www.cnblogs.com/youngchaolin/p/10879348.html