深入分析JavaWeb Item48 -- Struts2中OGNL表达式与ValueStack_struts 2 过滤ongl表达式

  • request: 该 Map 中包含当前 request 对象中的所有属性
  • session: 该 Map 中包含当前 session 对象中的所有属性
  • application:该 Map 中包含当前 application 对象中的所有属性
  • attr: 该 Map 按如下顺序来检索某个属性: request, session, application

为了更好的理解可以断点执行如下代码:

Object ctx=ServletActionContext.getRequest().getAttribute("struts.valueStack");

这里写图片描述

这里写图片描述

三、理解OGNL Context

ValueStack 类包含两个重要的属性 一个root和一个context。其中root本质上是一个ArrayList. 而context 是一个Map(更确切的说是一个OgnlContext对象)

在这个OgnlContext对象(context)中,有一个默认的顶层对象 _root,OGNL访问context中这个默认顶层对象中的元素时,是不需要#号的,直接通过元素的名称来进行访问,
而访问其他对象时,如 request、session、attr等,则需要#号引用。

注:Struts2将ValueStack的root对象赋值给了OgnlContext 中的_root对象,在ValueStack的root对象中,保存着调用Action的实例,因此,在页面上通过Struts2标签访问Action 的属性时,就不需要通过#号来引用

这里写图片描述

这里写图片描述

当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。

其中ActionContext提供了对ognl上下文对象中数据操作的方法.

 ServletActionContext.getRequest().setAttribute("username", "username\_request");
 ServletActionContext.getServletContext().setAttribute("username", "username\_application");
 ServletActionContext.getContext().getSession().put("username", "username\_session");

 ValueStack valueStack=ServletActionContext.getContext().getValueStack();
 System.out.println("valueStack "+valueStack);
 valueStack.set("username", "username\_valueStack");

总结 :ognl Context包含 ObjectStack属性和ContextMap属性

四、一些常用方法

1、ValueStack中的的常用方法

功能一定要知道干什么的。实现类OgnlValueStack

这里写图片描述

  • getContext():返回的是一个Map<String,Object>
  • *getRoot():返回的是一个CompoundRoot。
  • CompoundRoot就是一个ArrayList的子类(就是一个List)。实现了一个栈结构

ValueStack

  • CompoundRoot():默认的构造方法。实际就是创建一个List集合
  • CompoundRoot(List):用一个集合来初始化一个CompoundRoot对象
  • cutStack(int):按照集合中的索引,剪出一个的List集合
  • peek():取集合中的第一个元素。get(0)
  • pop():从集合中删除第一个元素
  • push(Object):向集合中的第一个元素位置插入数据
  • peek():CompoundRoot中的第一个元素。get(0)
  • pop():从CompoundRoot集合中删除第一个元素
  • push(Object):向CompoundRoot集合中的第一个元素位置插入数据
  • size():获取 CompoundRoot这个集合的大小
  • setValue(String,Object):第一个参数,是OGNL表达式。向自己(getContext())得到那个Map中尝试放东西。
  • setParameter(String,Object):第一个参数,是OGNL表达式。向自己(getContext())得到那个Map中尝试放东西。
  • findString(String expr):返回的是一个String类型的,否则报错.第一个参数,是OGNL表达式。
  • findValue():返回的是一个Object。第一个参数,是OGNL表达式。
2、ActionContext
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();

每个线程都会有唯一的ActionContext,且一个线程中只有一个ActionContext。

这里写图片描述

  • getApplication():返回的是一个Map
  • getContext():放回的当前线程上的ActionContext对象
  • getContextMap():返回ActionCOntext中的那一个Map
  • getParameters():返回的是一个Map
  • getSession():返回的是一个Map
  • getValueStack():返回的是当前线程中的ValueStack实例
  • get(String):从ActionContext的Map中获取数据

最终总结:

3、ServletActionContext决定contextMap中会存哪些数据

总结:ValueStack有一个根的list叫CompundRoot和一个contextMapMap<String,String>getContext(), 而ActionContext中存储的Map就是ValueStack中的那个Map。都是从ActionContext的那个大Map中获取的。

这里写图片描述

4、在执行动作方法前,contextMap中放了以下东西

contextMap中

k这里写图片描述

5、利用OGNL获取ValueStack中:根栈和contextMap中的数据

原则:OGNL表达式如果以#开头,访问的contextMap中的数据
如果不以#开头,是访问的根栈中的对象的属性

1、在动作类中Demo1Action中重写execute方法

package com.itheima.actions;

import org.apache.struts2.ServletActionContext;

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

public class Demo1Action extends ActionSupport{
    private String username = "刘小晨";
// private String p="actionP";

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

// public String getP() {
// return p;
// }
//
// public void setP(String p) {
// this.p = p;
// }

    public String execute() throws Exception {
// ServletActionContext.getRequest().setAttribute("p", "rp");//ServletRequest中的request
        ServletActionContext.getRequest().getSession().setAttribute("p", "sp");//HttpSession中的session
        ServletActionContext.getServletContext().setAttribute("p", "ap");//ServletContext中的application

        ValueStack vs = ActionContext.getContext().getValueStack();
        System.out.println(vs);
        return super.execute();
    }

}

配置struts.xml

<struts>
    <constant name="struts.devMode" value="true" />
    <package name="p1" extends="struts-default">
        <action name="showContextMap" class="com.itheima.actions.Demo1Action">
            <result>/contextMap.jsp</result>
        </action>
    </package>
</struts>

编写contextMap.jsp页面

<%@ page language="java" import="java.util.\*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>OGNL取contextMap中的数据</title>
  </head>

  <body>
    <br/>取contextMap中的根中(List类型的,实际类型CompoundRoot)的数据.<br/>
    <s:property value="locale"/>
    <s:property value="p" /><br/><!--从栈顶开始搜索Map的key或者是对象的属性-->
    <s:property value="[0]" /><br/><!--不是栈顶对象,是从索引为0处砍出来的一个新集合-->
    <s:property value="[0].top" /><br/><!--栈顶对象-->
    <!-- value="username"的涵义:从根中的栈顶开始,对每个对象搜索他的getUsername()方法,找到为止 -->
    <br/>取contextMap中的其他的数据(非根中的).<br/>

    <s:property value="#request"/><br/>
    动作中的:<s:property value="p"/><br/>
    请求范围:<s:property value="#request.p"/><br/>
    会话范围:<s:property value="#session.p"/><br/>
    应用范围:<s:property value="#application.p"/><br/>
    <!-- 依次从动作\页面\请求\会话范围\应用范围查找名称为p的对象 -->
    attr:<s:property value="#attr.p"/><br/>


    <!-- 显示出来的东西并不是contextMap中所有的东西,只是大部分 -->
    <s:debug></s:debug>
  </body>
</html>

数据内存结构

这里写图片描述

6、ValueStack的常用方法
  • void set(String key,Object value):先获取根栈栈顶的Map,如果不存在,压入一个新的Map

这里写图片描述

  • void setValue(String ,Object):String是一个OGNL表达式。如果表达式以#开头,操作contextMap。如果不是,设置根栈中对象的某个属性,从顶到尾依次搜寻。

这里写图片描述

  • Object findValue(String expr):参数是一个OGNL表达式。如果以#开头,从contextMap中找key值所对应的对象。如果不是以#开头,搜索根栈中对象的属性(getter方法)
    特别注意:如果编写的表达式不是以#开头,先搜索根栈对象的所有属性,如果没有找到,会把它当做key值到contextMap中找。

这里写图片描述

这里写图片描述

  • String findString(String expr):把OGNL表达式获取的对象转换成String
    这里写图片描述
7、contextMap中放的常用数据

request:请求范围的数据。即ServletRequest中的那个Map
parameters:请求参数的数据。即request.getParameterMap得到
application:应用范围的数据。即ServletContext中的那个Map
session:会话范围的数据。即HttpSession中的那个Map
attr:也是一个Map。会从以下Map中依次搜索:request、session、application

这里写图片描述

五、OGNL的一些其他操作

1、投影

1、 集合的投影(只输出部分属性)

 <s:iterator value="allList.{name}" var="person">
           <s:property/>  <br>
 </s:iterator> 

2、 过滤条件:this 表示集合中的元素;

a.“?#”:过滤所有符合条件的集合,如:users.{?#this.age > 19};
b.“^#”:过滤第一个符合条件的元素,如:users.{^#this.age > 19};
c.“$#”:过滤最后一个符合条件的元素,如:users.{$#this.age > 19} 。

<s:iterator value="allList.{?#this.age>25}" var="person">
        <s:property value="name"/>  xxxxxx  <s:property value="age"/> <br>
 </s:iterator> 

3、 集合的投影和过滤
投影(过滤)操作返回的是一个集合,可以使用索引取得集合中指定的
元素,如:users.{?#this.age > 19}[0]

<s:iterator value="allList.{?#this.age>25}.{name}" var="person">
        <s:property/><br>
    </s:iterator> 

 <s:iterator value="allList.{?#this.age>25}[0]" var="person">
        <s:property/><br>
  </s:iterator> 

编写TagDemo1Action

package com.itheima.actions;

import java.util.ArrayList;
import java.util.List;

import com.itheima.domain.Person;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class TagDemo1Action extends ActionSupport {
    private String username="刘小晨";
    private List<Person> ps = new ArrayList<Person>();
    public String getUsername() {
        return username;
    }

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

    public List<Person> getPs() {
        return ps;
    }

    public void setPs(List<Person> ps) {
        this.ps = ps;
    }

    public String execute() throws Exception {
        //初始化一些人
        ps.add(new Person("安康", "女性", 7000));
        ps.add(new Person("唐诗诗", "男性", 10000));
        ps.add(new Person("王卫星", "有待鉴定", 10000));

        ActionContext.getContext().getValueStack().setValue("#gender", "美女");
        return SUCCESS;
    }

}

编写jsp页面

<%@ page language="java" import="java.util.\*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>OGNL投影等操作</title>
  </head>

  <body>
    <br/>--------OGNL的投影查询----------<br/>
    <table border="1">
        <tr>
            <th>姓名</th>
        </tr>
        <!-- ps.{nickname} ---List<String> var=“p”引用的是一个String类型的,就代表着匿名 -->


### 文末

技术是没有终点的,也是学不完的,最重要的是活着、不秃。

零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。

最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。

自学最怕的就是缺乏自驱力,一定要自律,杜绝“三天打鱼两天晒网”,到最后白忙活一场。

高度自律的同时,要保持耐心,不抛弃不放弃,切勿自怨自艾,每天给自己一点点鼓励,学习的劲头就会很足,不容易犯困。

技术学到手后,找工作的时候一定要好好准备一份简历,不要无头苍蝇一样去海投简历,容易“竹篮打水一场空”。好好的准备一下简历,毕竟是找工作的敲门砖。

拿到面试邀请后,在面试的过程中一定要大大方方,尽力把自己学到的知识舒适地表达出来,不要因为是自学就不够自信,给面试官一个好的印象,面试成功的几率就会大很多,加油吧,骚年!

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**
  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值