博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Struts( 三 )
阅读量:5771 次
发布时间:2019-06-18

本文共 6334 字,大约阅读时间需要 21 分钟。

hot3.png

OGNL表达式

概述

OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个开源项目。Struts框架使用OGNL作为默认的表达式语言。

所谓表达式,就是用一定的格式字符串访问数据或方法。

表达式显示的内容如果脱离了解析引擎是毫无意义的。

OGNL提供了这种字符串解析的引擎

开发人员可以把重点放在如何写字符串上就可以达到调用方法或属性的功能

OGNL环境

Jar包

ognl-xxx.jar,javassist-xxx.jar

ognl:ognl的核心环境

javassist是ognl的依赖,提供字节码修改能力。

OGNL提供的功能

  • 支持对象方法的调用
  • 支持对象对象属性访问(getter方法属性化的转换)
  • 支持静态方法的调用
  • 支持集合对象操作

OGNL API使用

核心类和元素

  • 表达式:expression
  • 根对象:root
  • 上下文: OgnlContext
  • Ognl工具类: Ognl

表达式与根对象

访问根对象的属性

// 根对象User root = new User();root.setName("张三疯");root.setAge(19);// 表达式String expression="name";//通过Ognl方式获得根对象中的表达式结果Object value = Ognl.getValue(expression, root);

Ognl在根对象中以表达式的方式取出根对象的属性

访问根对象的方法

// 根对象User root = new User();root.setName("张三疯");root.setAge(19);// 表达式String expression="getName()";//通过Ognl方式获得根对象中的表达式结果Object value = Ognl.getValue(expression, root);

 

表达式与上下文

通过#+key修饰符的方式访问上下文中的对象

// 上下文对象Map
context = new HashMap
();context.put("aaa", "小a");context.put("bbb", "小b");// 根对象Object root = null;// 表达式String expression = "#aaa";Object value = Ognl.getValue(expression, context, root);

 

表达式,根对象,上下文

根对象与上下文结合

// 上下文对象Map
context = new HashMap
();context.put("aaa", "小a");context.put("bbb", "小b");// 根对象User root = new User();root.setName("小a");root.setAge(19);// 表达式String expression = "name.equals(#aaa)";// 获取ognl结果Object value = Ognl.getValue(expression, context, root);

 

静态方法调用

// Integer.valueOf("123");String expression = "@java.lang.Integer@valueOf(\"123\")";Object value = Ognl.getValue(expression, null);
// Runtime.getRuntime().exec("calc.exe");String expression = "@java.lang.Runtime@getRuntime().exec(\"calc.exe\")";Object value = Ognl.getValue(expression, null);

静态方法调用中:

  • 类名必须使用全路径
  • 类前加@修饰
  • 调用的静态方法的@替代

ValueStack值栈

值栈的概念

ValueStack是一个接口,实现类是OgnlValueStack。值栈就是一个存取空间,理解为是一个数据的中转站。客户端发送一个请求到Action,服务器就会创建一个Action的实例。(Action是多例的,不会出现线程安全的问题。Servlet是单例的,会出现线程安全的问题。),只要服务器有一个Action的实例,就会创建一个值栈为这个Action服务。值栈对象贯穿了整个的Action的生命周期。值栈被Struts2保存到了request域中一份。

  • 值栈是数据的中转站
  • MVC模型中,Action负责Controller,在Action中将model数据存储到值栈中
  • MVC模型中,JSP负责View,view通过值栈去取数据

185135_MprZ_3669094.jpg

ActionContext和ValueStack的关系

每次请求中,都会在这个请求的过程中,创建一个ActionContext。ActionContext创建的同时,会创建一个ValueStack。ValueStack中的的上下文对象会传递给ActionContext,作为ActionContext的上下文。ValueStack中的上下文同时引用了自身ValueStack。

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
(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;}

ValueStack获取方式

  • ActionContext方式获取

    ValueStack valueStack = ActionContext.getContext().getValueStack();

    值栈是存储在自己内部的map中,自己的map又传递交给了ActionContext。

  • HttpServletRequest方式获取ValueStack

    ValueStack valueStack = ServletActionContext.getValueStack(ServletActionContext.getRequest());

    值栈也存储了一份到request中。

值栈的结构组成

  •  

    root 区

    根对象。

    具体类型为CompoundRoot。
    CompoundRoot实现了List接口,其实就是一个list集合。

     

  • context 区

    上下文对象。

    具体类型为OgnlContext。
    OgnlContext内部操控的是一个Map集合,其实context区可以理解为一个Map集合。

值栈的debug查询展示

  • 在jsp页面中,引入struts的标签库
    <%@ taglib uri="/struts-tags" prefix="s"%>
  • 通过<s:debug/>标签可以在jsp中查看值栈的结构

185136_pBJV_3669094.jpg

上下文区存储的数据

  • request对象数据
  • response对象数据
  • application对象数据
  • parameters数据
  • attr数据:request,session,application中的atrribute数据。

值栈存储数据方式

值栈存储数据主要指的是往根对象区存储数据。根对象是一个List集合类型,存储着对象。

其中根对象还维护了一个Map负责存储key-value类型的数据

默认的值栈数据

  • DefaultTextProvider
  • 当前的action对象实例

push方式存取

  • 存储
    ValueStack valueStack = ActionContext.getContext().getValueStack();User user = new User();user.setName("李四");user.setAge(100);valueStack.push(user);

     

  • 获取

set方式存取

  • 存储

    ValueStack valueStack = ActionContext.getContext().getValueStack();User user = new User();user.setName("李四");user.setAge(100);	valueStack.set("user", user);

     

  • 获取

属性驱动方式

  • 存储:自动通过valueStack存储到当前action的类中
  • 获取

模型驱动方式

  • 存储:自动存储到valuestack的root区中
  • 获取

EL 如何获得值栈中数据

  • struts在前端控制器中对请求进行了包装,包装为了StrutsRequestWrapper
  • EL表达式的核心内容其实就是对request的attribute属性进行访问,即request.getAttribute()方法
  • StrutsRequestWrapper对getAttribute方法进行了重写
    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;}

    通过struts的源码可以看出,getAttribute方法是先在request的attribuite中找,找不到就到ValueStack中去找

获取值栈上下文中的数据

OGNL中的符号

#号的作用

获取Context中的数据

构建一个Map集合

--
--

%号的作用

强制解析OGNL表达式

强制不解析OGNL表达式

$号的作用

中文 :login.welcome=您好:${#session.user.username}英文 :login.welcome=Hello:${#session.user.username}

 

转载于:https://my.oschina.net/px828261/blog/1554361

你可能感兴趣的文章
Swoole 4.1.0 正式版发布,支持原生 Redis/PDO/MySQLi 协程化 ...
查看>>
开发网络视频直播系统需要注意的地方
查看>>
haproxy mysql实例配置
查看>>
强化学习的未来— 第一部分
查看>>
TableStore:用户画像数据的存储和查询利器
查看>>
2019 DockerCon 大会即将召开,快来制定您的专属议程吧!
查看>>
15分钟构建超低成本数据大屏:DataV + DLA
查看>>
jSearch(聚搜) 1.0.0 终于来了
查看>>
盘点2018云计算市场,变化大于需求?
查看>>
极光推送(一)集成
查看>>
MySQL 8.0 压缩包版安装方法
查看>>
@Transient注解输出空间位置属性
查看>>
Ansible-playbook 条件判断when、pause(学习笔记二十三)
查看>>
5种你未必知道的JavaScript和CSS交互的方法(转发)
查看>>
线程进程间通信机制
查看>>
galera mysql 多主复制启动顺序及命令
查看>>
JS prototype 属性
查看>>
中位数性质——数列各个数到中位数的距离和最小
查看>>
WebApp之Meta标签
查看>>
添加Java文档注释
查看>>