(十)Struts2进阶之OGNL在Struts2中的使用

上篇文章把OGNL单独拿出来讲了,这篇文章就讲讲OGNL结合Struts2的使用。

Struts2中OGNL表达式必须配合Struts2标签使用,不然没什么效果。

(八)Struts2进阶之值栈详解这篇文章中我们分析了值栈的结构,讲了值栈的实现类是OgnlValueStack类,它包含两部分,分别是root(对应CompoundRoot类)和context(对应OgnlContext类)。

在每次调用核心控制器时,在它的doFilter方法中有这么一行代码

prepare.createActionContext(request, response);

这行对于我们理解值栈很关键啊,本来应该放在值栈里说的。。。

首先先捋一捋ActionContext是什么玩意,上篇文章单纯讲OGNL的时候说了,它有一个执行的上下文环境OgnlContext,它里面有一个根对象和若干个普通对象。

那么在Struts2中,要使用OGNL,也得给它一个上下文环境,其实我看网上很多文章说ActionContext是上下文环境,但我认为应该是OgnlValueStack类,它里面有这么两行代码

CompoundRoot root;
transient Map<String, Object> context;

分别代表值栈的root和context。不过我们可以在ActionContext类中取得值栈对象。

下面开始说。

1.Struts2中的OGNL

Struts2中的OGNL比单纯的OGNL要更强大,上篇文章中,我们说了只能有一个root对象,而在OGNL中,可以有多个root对象。root对应的实现类是CompoundRoot,该类实质是List,所有能有多个root对象。在Strtus2中的Root使用的是CompoundRoot对象,而CompoundRoot继承了ArrayList,所以他可以存储一系列的对象,这些对象可以看作是OGNL中的root对象。当我们当问某个属性时,CompoundRootAccessor对象实例会负责在CompoundRoot对象中找到包含我们指定属性的对象。

2.再说ValueStack

对于用户的每个action请求,Struts2在执行相应的方法之前,都会新建一个valuestack对象,其实这个创建的过程就在Struts2的核心控制器里的doFilter方法中,也就是从上面的那行代码开始的,它会把request、session、application、atrr、parameters放入context中。

valueStack的内部包含两个逻辑部分,一个叫做Object Stack(root),另一个叫做Context Map(context)。Struts2将动作和相关对象压入Object Stack,把各种各样的映射关系(Map类型的对象)压入Context Map。其中的Object Stack中的对象都相当于OGNL中的”root”对象,因此对他们可以直接访问。如果要访问Context Map中的对象,那么就得在OGNL表达式前面加上”#”符号。如果没有加”#”,那么Struts2默认会在Object Stack中进行搜索。


36.jpg

Strut2会把下面的这些映射关系压入到Context Map中:
(1) parameters:这个Map中包含当前请求的请求参数
(2) request:包含当前请求的所有属性
(3) session:包含当前请求的会话的所有属性
(4) application:包含当前应用程序的ServletContext属性
(5) attr:这个Map用来按照这个顺序来检索某个属性:request、session、application
注意:请求参数总是返回一个String类型的数组。比如我们要想知道请求参数的个数,那么正确的表达式应该是#parameters.count[0],而不是#parameters.count。

3.使用OGNL获取值栈中的属性值

34.png

获取root中的值,我们不需要加#符号,这和上篇文章是一样的道理。

下面看看代码
新建一个User类,有username和password两个属性

@SuppressWarnings("serial")
public class User implements Serializable{
    private String username;
    private String password;
    
    public User() {}

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

新建一个OGNLAction类,实现了三个接口,分别用于获取request,session和application,另外还有一个list。

@SuppressWarnings("serial")
public class OGNLAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware {
    // 这里的值会被放入Object Stack(root)中,记得提供get方法,不然无法取值
    private List<User> s1;
    // 这里的值会被放入Context Map(context)中
    private Map<String, Object> applicationMap;
    // 这里的值会被放入Context Map(context)中
    private Map<String, Object> sessionMap;
    // 这里的值会被放入Context Map(context)中
    private Map<String, Object> requestMap;
    @Override
    public String execute() throws Exception {
        User u1 = new User("liu", "12345");
        User u2 = new User("xu", "123456");
        User u3 = new User("guo", "520520");
        s1 = new ArrayList<User>();
        Collections.addAll(s1, u1, u2, u3);
        applicationMap.put("users", s1);
        sessionMap.put("users", s1);
        requestMap.put("users", s1);
        return SUCCESS;
    }
    
    @Override
    public void setApplication(Map<String, Object> application) {
        this.applicationMap = application;
    }
    
    @Override
    public void setRequest(Map<String, Object> request) {
        this.requestMap = request;
    }
    
    @Override
    public void setSession(Map<String, Object> session) {
        this.sessionMap = session;
    }

    public List<User> getS1() {
        return s1;
    }

    public void setS1(List<User> s1) {
        this.s1 = s1;
    }
}

在struts.xml中配置action

<action name="OGNL" class="com.codeliu.action.OGNLAction">
    <result>/index.jsp</result>
</action>

新建一个index.jsp

<body>
    <s:debug></s:debug>
    <s:property value="s1[0].username"/> or <s:property value="#request.users[1].username"/>
    or <s:property value="#application.users[0].username"/> or <s:property value="#session['users'][0].username"/>
    <br>
    <!-- 遍历list中的元素 -->
    <s:iterator value="s1" var="user">
        <!-- 说明使用var属性后,值放在了context Map中,要通过#去获取 -->
        <s:property value="#user.username"/>&nbsp;<s:property value="#user.password"/><br>
        <!-- 不加#也能获取到,说明在root中没有找到,回去 context Map中找-->
        <s:property value="username"/>&nbsp;<s:property value="password"/><br>
    </s:iterator>
    
    <!-- 遍历applicationMap中的元素 -->
    <s:iterator value="#application.users" var="user">
        <s:property value="#user.username"/>&nbsp;<s:property value="#user.password"/><br>
    </s:iterator>
    
    <!-- 遍历requestMap中的元素 -->
    <s:iterator value="#request.users">
        <s:property value="username"/>&nbsp;<s:property value="password"/><br>
    </s:iterator>
    
    <!-- 遍历sessionMap中的元素 -->
    <s:iterator value="#session.users">
        <s:property value="username"/>&nbsp;<s:property value="password"/><br>
    </s:iterator>
</body>

启动tomcat后,结果如下


38.png

代码上面的注释都写的很清楚,说明什么问题?

1.除了List,其他的三个变量的值都放进去了Context Map中,要取出来必须加上#
2.使用遍历标签,如果使用了var属性,则每次遍历的值都放入了Context Map中,使用#符号也可以取出来。(不使用也可以,因为它在root中没找到,应该就会去Context Map中找。)
3.action类中,放入root中的数据,比如上面的list,记得要有相应的get方法,否则无法取到值。
4.使用#session['users'][0].username也可以获取到属性的值

4.调用静态方法和静态字段

其实在Struts2中OGNL调用静态方法、静态字段和上篇文章中讲的都一样。

要注意的是,Struts2默认是关闭调用静态方法的功能,所以要使用,得先打开。

<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

对于值栈中的静态属性和方法,直接使用它们的名称即可。

    <!-- 调用Java API的静态变量和静态方法 -->
    <s:property value="@java.lang.Math@PI"/>
    <br>
    <s:property value="@java.lang.Math@floor(4.3)"/><br>
    
    <!-- 调用自己写的类中的静态字字段和静态方法 -->
    <s:property value="myName"/><br>
    <s:property value="getMyName()"/>

5.投影和过滤

和上篇文章讲的也一样。

6.# $ %的使用

“#”的作用
(1)访问非root对象的属性。例如:#session[“userName”]
(2)对集合进行投影与选择(具体可看上篇文章)
(3)构造对象(具体可看上篇文章),
“%”的作用
在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式 <s:property value="%{#foobar['foo1']}" />
“$”的作用
(1)在配置文件中引用OGNL表达式(访问Action的属性)。
(2)在国际化资源文件中引用OGNL表达式(学习国际化时会学到)

7.this指针

在很多编程语言中,都有this指针的概念,它表示调用当前函数(方法)的对象。那么在OGNL中也有类似的概念。
我们已经学过,OGNL表达式是以”.”进行串联的的一个串字符串表达式。这个表达式在被执行的时候,从左到右,每一次计算都会返回一个临时的当前对象,并在此临时对象上再次进行调用,直到执行完毕。这个临时的当前变量就存储在一个叫做this的变量中,这个this变量我们就叫它this指针。通过使用this指针,我们可以使OGNL更加灵活,更加强大。
注:使用this指针时,必须在this前面加”#”,即this指针必须以“#this”的形式出现。
例如:group.userList.size().(#this+1).toString()

上篇文章中讲投影和过滤的时候使用了this指针



参考文章
https://blog.csdn.net/xiaokang123456kao/article/details/59483038
https://blog.csdn.net/yu102655/article/details/52182801

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352