JavaWeb学习:OGNL

一、OGNL:Object-Graph Navigation Language(对象导航图语言)的缩写,是应用于Java中的一个开源的表达式语言

二、OGNL的优势:

  • 支持对象方法调用
  • 支持静态方法调用和值访问(表达式:@[类全名(包括包路径)]@[方法名 | 值名])
  • 支持赋值操作和表达式串联
  • 访问OGNL上下文
  • 操作集合
  • 可以new 一个对象

三、Java环境

  ①、对象方法调用 

  @Test
    public void demo1() throws OgnlException {
    OgnlContext context = new OgnlContext();
    Object root = context.getRoot();
    Object object = Ognl.getValue("'hellow ognl'.length()", context, root);
    System.out.println(object);
    }

  ②、静态方法调用和值访问

   @Test
    public void demo2() throws OgnlException {
    OgnlContext context = new OgnlContext();
    Object root = context.getRoot();
    Object object = Ognl.getValue("@java.lang.Math@random()", context, root);
    System.out.println(object);
    }

  ③、赋值操作和表达式串联

  @Test
    public void demo3() throws OgnlException {
    OgnlContext context = new OgnlContext();
    Object root = context.getRoot();
    Object object = Ognl.getValue("price=100, discount=0.8, price*discount", context, root);
    System.out.println(object);
    }

    出现异常:ognl.OgnlException: target is null for setProperty(null, "price", 100),不知道怎么解决

   ④、访问OGNL上下文(OgnlContext)

    

public class User {
    private String userName;
    private String 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;
    }
    public User(String userName, String passWord) {
    this.userName = userName;
    this.passWord = passWord;
    }
    public User() {
    }
    
}

    4.1、访问Root中的数据

    @Test
    public void demo4() throws OgnlException {
    OgnlContext context = new OgnlContext();
    context.setRoot(new User("zhangsan","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.2、访问context中的数据,需要加#

    @Test
    public void demo5() throws OgnlException {
    OgnlContext context = new OgnlContext();
    Object root = context.getRoot();

    context.put("name", "zhangsan");
    Object name=Ognl.getValue("#name", context, root);
    System.out.println(name);
    }

四、Struts2环境

  ①、对象方法调用、静态方法调用

<!-- 调用对象方法 -->
<s:property value="'hello struts ognl'.length()"/>
<!-- 
在struts2中静态方法访问默认式禁止访问的,
需要设置一个常量(struts.ognl.allowStaticMethodAccess=true)开启访问权限 
-->
<s:property value="@java.lang.Math@random()"/>
<!-- 赋值操作和表达式串联(无法正常显示,不知道为什么)  -->
<s:property value="price=100, discount=0.8, price*discount"/>

  ②、访问ognl上下文(OgnlContext)需要使用ValueStack存储数据

    2.1、在Struts2环境中使用OGNL语法,主要作用:数据库传输(Struts2的框架中的数据都存储到ValueStack中)

      • ValueStack接口,实现类OgnlValueStack对象
      • ValueStack贯穿整个Action的生命周期

2.2、ValueStack中有两个主要区域:

   root:其实就是一个ArrayList,主要存储对象

   context:其实就是一个Map,主要存储web开发常用对象数据库的引用

    

      操作值栈是指操作ValueStack的root区域,而操作request、session、application、就相当于操作context区域

          可以通过Debug方式查看(debug在页面上看不到,配置常量<constant name="struts.devMode" value="true" />),具体代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h3>Success</h3>
    <s:debug></s:debug>
</body>
</html>

          root区域的内容

            

          context区域

             

     2.3、值栈与ActionContext的关系

      ActionContext:Action的上下文,当有请求时,执行过滤器中的doFilter方法,此方法会创建ActionContext,在创建ActionContext过程中创建ValueStack对象,并将ValueStack对象存储在ActionContext中,所以可以通过ActionContext获取值栈对象(ActionContext.getContext().getValueStack()

        ActionContext对象可以访问Servlet的API(访问的是域对象的数据),因为其内部有值栈的引用。

    2.4、ValueStack的获取

      1、通过ActionContext对象获取值栈

ActionContext.getContext().getValueStack()

       2、在Struts2内部将值栈存入request对象中

ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY)

     2.5、ValueStack的操作(实际操作的root区域)

      操作的方式一:因为root区域是存储了当前Action对象的,所以把操作数据存储在Action对象中(存储数据存放在Action对象的属性)

public class Demo1Action extends ActionSupport {
    private User user;
    
    public User getUser() {
        return user;
    }

    @Override
    public String execute() throws Exception {
    user = new User("zhangsan","123");
    return SUCCESS;
    }
}

      查看ognl debug,可以看到User对象数据存储到Demo1Action的user属性

        

 

 

       页面读取root中的数据,根据上图中Property Name中值进行读取操作的。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h3>Success</h3>
    <s:debug></s:debug><br />
    
    <s:property value="user.userName"/>
    <s:property value="user.passWord"/>
</body>
</html>

      操作的方式二:操作ValueStack对象(通过push(Object obj) 、set(String key,Object obj)两个方法操作ValueStack对象)

         push(Object obj) 方法

public class Demo2Action extends ActionSupport {
    @Override
    public String execute() throws Exception {
    ValueStack valueStack=ActionContext.getContext().getValueStack();
    valueStack.push(new User("lisi", "456"));
    return super.execute();
    }
}

        通过下图,push方法把存储数据对象压入栈内。避免Property Name中的值重复,否则数据会冲突

         

         根据Property Name获取数据

            <s:property value="userName"/>
            <s:property value="passWord"/>

        set(String key,Object obj)方法 

public class Demo2Action extends ActionSupport {
    @Override
    public String execute() throws Exception {
    ValueStack valueStack=ActionContext.getContext().getValueStack();
    List<User> list=new ArrayList<User>();
    list.add(new User("aaa", "111"));
    list.add(new User("bbb", "222"));
    list.add(new User("ccc", "333"));
    valueStack.set("list",list);
    valueStack.set("name", "zhangsan");
    return super.execute();
    }
}

        通过下图,set方法把存储数据存储在Map集合中并压入栈内

         

         根据Property Name获取数据,但是Property Name没值,可以根据set方法中的key值获取数据

            <s:property value="list[0].userName"/><br />
            <s:property value="list[0].passWord"/><br />
            <s:property value="list[1].userName"/><br />
            <s:property value="list[1].passWord"/><br />
            <s:property value="list[2].userName"/><br />
            <s:property value="list[2].passWord"/><br />
            <s:property value="name"/>

  总结:在ognl表达式中action传值给jsp页面,有两种方式:操作root(就是操作ValueStack)、操作context(操作request、session、application)

    • 操作ValueStack:获取ValueStack、读写ValueStack
      • 获取ValueStack有两种方式:ActionContext、Request
      • 写ValueStack:
        • 一、通过当前Action对象属性
        • 二、通过ValueStack的push(Object obj)、set(String key,Object)方法
          • push(Object obj)、set(String key,Object obj)都会把数据从栈顶压入,这样的话,最后执行的方法会在栈顶。
          • push存储对象,set存储集合或字符串
      • 读ValueStack:
          • 一、ognl表达式
          • 二、EL表达式(${name} ):访问request对象中的getAttribute方法
            • 可以使用EL表达式的原因:Struts2框架对request.getAttribute(String key)方法进行增强,在getAttribute方法中,先去获取request查找对应key的数据,如果没有找到的话,再去ValueStack中查找对应key的数据(stack.findValue(key);),
    • 操作context:获取request、session、application,读写request、session、application
      • 获取request、session、application两种方式:一、ServletActionContext 二、ActionContext
        • 写request、session、application
        • ServletActionContext.getRequest().setAttribute("name", "request");
          ServletActionContext.getRequest().getSession().setAttribute("name", "session");
          ServletActionContext.getServletContext().setAttribute("name", "application");
              
          ActionContext.getContext().put("reqName", "reqValue");
          ActionContext.getContext().getSession().put("sessName", "sessValue");
          ActionContext.getContext().getApplication().put("appName", "appValue");
              
        • 读request、session、application:jsp页面通过ognl表达式,读取context中的数据需要加#
        •   <s:property value="#request.name"/>
              <s:property value="#request.reqName"/>
              
              <s:property value="#session.name"/>
              <s:property value="#session.sessName"/>
              
              <s:property value="#application.name"/>
              <s:property value="#application.appName"/>
        • #attr.name:逐级查找request、session、application中的数据,
          • 如果request中没数据,就查看session,session没有数据就查看application
          • 如果request中有数据,就不会查看session。
        • #parameters.id:获取参数信息

      

 

 

posted @ 2020-11-30 18:04  一杯水M  阅读(302)  评论(0编辑  收藏  举报