代码改变世界

OGNL

2017-07-13 17:49  Loull  阅读(324)  评论(0)    收藏  举报

在mvc中,数据是在各个层次之间进行流转是一个不争的事实。而这种流转,也就会面临一些困境,这些困境,是由于数据在不同世界中的表现形式不同而造成的:

  1. 数据在页面上是一个扁平的,不带数据类型的字符串,无论数据结构有多复杂,数据类型有多丰富,到了展示的时候,全都一视同仁的成为字符串在页面上展现出来。

  2. 数据在Java世界中可以表现为丰富的数据结构和数据类型,可以自行定义你喜欢的类,在类与类之间进行继承、嵌套。我们通常会把这种模型称之为复杂的对象树。

  此时,如果数据在页面和Java世界中互相流转传递,就会显得不匹配。所以也就引出了几个需要解决的问题:

  1. 当数据从View层传递到Controller层时,我们应该保证一个扁平而分散在各处的数据集合能以一定的规则设置到Java世界中的对象树中去。同时,能够聪明的进行由字符串类型到Java中各个类型的转化。

  2. 当数据从Controller层传递到View层时,我们应该保证在View层能够以某些简易的规则对对象树进行访问。同时,在一定程度上控制对象树中的数据的显示格式。

      同样的问题会发生在Java世界与数据库世界中,面对这种对象与关系模型的不匹配,我们采用的解决方法是使用ORM框架,例如hibernate,iBatis等等。那么现在,在Web层同样也发生了不匹配,所以我们也需要使用一些工具来帮助我们解决问题。为了解决数据从View层传递到Controller层时的不匹配性,Struts2采纳了OGNL方案和OGNLValueStack机制 

基本概念

        OGNL(Object Graph Navigation Language),全称叫做对象图导航语言。可以通过某种表达式语法,存取Java对象树中的任意属性、调用Java对象树的方法、同时能够自动实现必要的类型转化。如果我们把表达式看做是一个带有语义的字符串,那么OGNL无疑成为了这个语义字符串与Java对象之间沟通的桥梁。既然OGNL那么强大,那么让我们一起来研究一下他的API,看看如何使用OGNL.

OGNL的API看起来就是两个简单的静态方法:

public static Object getValue( Object tree, Map context, Object root ) throws OgnlException; 
public static void setValue( Object tree, Map context, Object root, Object value ) throws OgnlException  

 

OGNL三要素:OGNL的三要素。OGNL的操作实际上就是围绕着这三个参数而进行的。

A) 针对根对象(Root Object)的操作,表达式是自根对象到被访问对象的某个链式操作的字符串表示。

B) 针对上下文环境(Context)的操作,表达式是自上下文环境(Context)到被访问对象的某个链式操作的字符串表示,但是必须在这个字符串的前面加上#符号,以表示与访问根对象的区别。

Ognl.setValue("department.name", user2, "dev");  
System.out.println(user2.getDepartment().getName()); 
 
Ognl.setValue(Ognl.parseexpression_r("department.name"), context, user2, "otherDev"); 
System.out.println(user2.getDepartment().getName()); 

 

1. 表达式(Expression)

  表达式会规定此次OGNL操作到底要干什么。我们可以看到,在上面的测试中,name、department.name等都是表达式,表示取name或者department中的name的值。

2. 根对象(Root Object)

  根对象可以理解为OGNL的操作对象。在表达式规定了“干什么”以后,你还需要指定到底“对谁干”。

  在上面的测试代码中,user就是根对象。这就意味着,我们需要对user这个对象去取name这个属性的值(对user这个对象去设置其中的department中的name属性值)。

3. 上下文环境(Context)

  有了表达式和根对象,我们实际上已经可以使用OGNL的基本功能。例如,根据表达式对根对象进行取值或者设值工作。不过实际上,在OGNL的内部,所有的操作都会在一个特定的环境中运行,这个环境就是OGNL的上下文环境(Context)。说得再明白一些,就是这个上下文环境(Context),将规定OGNL的操作“在哪里干”。

  OGNL的上下文环境是一个Map结构,称之为OgnlContext。上面我们提到的根对象(Root Object),事实上也会被加入到上下文环境中去,并且这将作为一个特殊的变量进行处理,具体就表现为针对根对象(Root Object)的存取操作的表达式是不需要增加#符号进行区分的。

       OgnlContext不仅提供了OGNL的运行环境。在这其中,我们还能设置一些自定义的parameter到Context中,以便我们在进行OGNL操作的时候能够方便的使用这些parameter。不过正如我们上面反复强调的,我们在访问这些parameter时,需要使用#作为前缀才能进行。

 

1)上下文环境中使用OGNL

public static void main(String[] args)  
    {  
        /* 创建一个上下文Context对象,它是用保存多个对象一个环境 对象*/  
        Map<String , Object> context = new HashMap<String , Object>();  
  
        Person person1 = new Person();  
        person1.setName("zhangsan");  
         
        Person person2 = new Person();  
        person2.setName("lisi");  
  
        Person person3 = new Person();  
        person3.setName("wangwu");  
  
        /* person4不放入到上下文环境中*/  
        Person person4 = new Person();  
        person4.setName("zhaoliu");  
  
        /* 将person1、person2、person3添加到环境中(上下文中)*/  
        context.put("person1", person1);  
        context.put("person2", person2);  
        context.put("person3", person3);  
  
        try  
        {  
            /* 获取根对象的"name"属性值*/  
            Object value = Ognl.getValue("name", context, person2);  
            System.out.println("ognl expression \"name\" evaluation is : " + value);  
  
            /* 获取根对象的"name"属性值*/  
            Object value2 = Ognl.getValue("#person2.name", context, person2);  
            System.out.println("ognl expression \"#person2.name\" evaluation is : " + value2);  
  
            /* 获取person1对象的"name"属性值*/  
            Object value3 = Ognl.getValue("#person1.name", context, person2);  
            System.out.println("ognl expression \"#person1.name\" evaluation is : " + value3);  
  
            /* 将person4指定为root对象,获取person4对象的"name"属性,注意person4对象不在上下文中*/  
            Object value4 = Ognl.getValue("name", context, person4);  
            System.out.println("ognl expression \"name\" evaluation is : " + value4);  
  
            /* 将person4指定为root对象,获取person4对象的"name"属性,注意person4对象不在上下文中*/  
            Object value5 = Ognl.getValue("#person4.name", context, person4);  
            System.out.println("ognl expression \"person4.name\" evaluation is : " + value5);  
  
            /* 获取person4对象的"name"属性,注意person4对象不在上下文中*/  
            // Object value6 = Ognl.getValue("#person4.name", context, person2);  
           // System.out.println("ognl expression \"#person4.name\" evaluation is : " + value6);  
  
        }  

2)使用OGNL调用方法

public static void main(String[] args)  
    {  
        /* OGNL提供的一个上下文类,它实现了Map接口*/  
        OgnlContext context = new OgnlContext();  
  
        People people1 = new People();  
        people1.setName("zhangsan");  
  
        People people2 = new People();  
        people2.setName("lisi");  
  
        People people3 = new People();  
        people3.setName("wangwu");  
  
        context.put("people1", people1);  
        context.put("people2", people2);  
        context.put("people3", people3);  
         
        context.setRoot(people1);  
  
        try  
        {  
            /* 调用 成员方法*/  
            Object value = Ognl.getValue("name.length()", context, context.getRoot());  
            System.out.println("people1 name length is :" + value);  
             
            Object upperCase = Ognl.getValue("#people2.name.toUpperCase()", context, context.getRoot());  
            System.out.println("people2 name upperCase is :" + upperCase);  
  
            Object invokeWithArgs = Ognl.getValue("name.charAt(5)", context, context.getRoot());  
            System.out.println("people1 name.charAt(5) is :" + invokeWithArgs);  
  
            /* 调用静态方法*/  
            Object min = Ognl.getValue("@java.lang.Math@min(4,10)", context, context.getRoot());  
            System.out.println("min(4,10) is :" + min);  
  
            /* 调用静态变量*/  
            Object e = Ognl.getValue("@java.lang.Math@E", context, context.getRoot());  
            System.out.println("E is :" + e);  
        }  

3)使用OGNL操作集合

public static void main(String[] args) throws Exception  
    {  
        OgnlContext context = new OgnlContext();  
         
        Classroom classroom = new Classroom();  
        classroom.getStudents().add("zhangsan");  
        classroom.getStudents().add("lisi");  
        classroom.getStudents().add("wangwu");  
        classroom.getStudents().add("zhaoliu");  
        classroom.getStudents().add("qianqi");  
         
        Student student = new Student();  
        student.getContactWays().put("homeNumber", "110");  
        student.getContactWays().put("companyNumber", "119");  
        student.getContactWays().put("mobilePhone", "112");  
         
        context.put("classroom", classroom);  
        context.put("student", student);  
        context.setRoot(classroom);  
  
        /* 获得classroom的students集合*/  
        Object collection = Ognl.getValue("students", context, context.getRoot());  
        System.out.println("students collection is :" + collection);  
  
        /* 获得classroom的students集合*/  
        Object firstStudent = Ognl.getValue("students[0]", context, context.getRoot());  
        System.out.println("first student is : " + firstStudent);  
  
        /* 调用集合的方法*/  
        Object size = Ognl.getValue("students.size()", context, context.getRoot());  
        System.out.println("students collection size is :" + size);  
  
        System.out.println("--------------------------飘逸的分割线--------------------------");  
         
        Object mapCollection = Ognl.getValue("#student.contactWays", context, context.getRoot());  
        System.out.println("mapCollection is :" + mapCollection);  
  
        Object firstElement = Ognl.getValue("#student.contactWays['homeNumber']", context, context.getRoot());  
        System.out.println("the first element of contactWays is :" + firstElement);  
  
        System.out.println("--------------------------飘逸的分割线--------------------------");  
  
        /* 创建集合*/  
        Object createCollection = Ognl.getValue("{'aa','bb','cc','dd'}", context, context.getRoot());  
        System.out.println(createCollection);  
  
        /* 创建Map集合*/  
        Object createMapCollection = Ognl.getValue("#{'key1':'value1','key2':'value2'}", context, context.getRoot());  
        System.out.println(createMapCollection);  
  
    }  
} 

 

 

获取属性:

@Test
public void test1(){
    Dog dog = new Dog();
    dog.setName("wangcai");
        
    Dog dog1 = new Dog();
    dog1.setName("wangwang");
        
    Person person = new Person();
    person.setName("zhagnsan");
    person.setDog(dog1);
        
    OgnlContext context = new OgnlContext(); //实例化一个Ognl的上下文
    context.put("person", person); 
    context.put("dog", dog);
        
    context.setRoot(person);  //将person设置为ongl的根
    try {
        //使用Ognl.paraseExpression(str)来解析ognl表达式。dog是person这个根对象的属性,可以直接写属性名
        Object obj = Ognl.getValue(Ognl.parseExpression("dog.name"), context, context.getRoot());
        System.out.println(obj);                           
        System.out.println("=================================");

        //#person.name获取根对象person的name属性, #person代表的person这个对象,如要拿到某个对象要使用#
        obj = Ognl.getValue(Ognl.parseExpression("#person.name"), context, context.getRoot());
        System.out.println(obj);     
        System.out.println("=================================");
            
        //#dog表示的是context.put("dog", dog)这个对象
        obj = Ognl.getValue("#dog.name", context, context.getRoot());
        System.out.println(obj);
        System.out.println("==================================");
            
        //此时name表示的是person这个根对象的属性,直接写上属性名即可
        obj = Ognl.getValue("name", context, context.getRoot());
        System.out.println(obj);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

输出结果:

wangwang

================================================

zhagnsan

================================================

wangcai

================================================

zhagnsan

方法调用

@Test
public void test2(){
    try{
        Person person = new Person();
        person.setName("zhagnsan");
            
        OgnlContext context = new OgnlContext();
        context.put("person", person);

        context.setRoot(person);
            
        //可以直接调用方法,name是根对象person的属性
        Object obj = Ognl.getValue("name.toUpperCase().length()", context, context.getRoot());
        System.out.println(obj);
        System.out.println("=================================");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

输出结果: 8

调用静态方法

@Test
public void test3(){
    OgnlContext context = new OgnlContext();
    try {
        //调用静态方法的语法: @类的全名@静态方法名
        Object obj = Ognl.getValue("@java.lang.Integer@toBinaryString(10)", context, context.getRoot());
        System.out.println(obj);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

输出结果:1010

java.lang.Math的处理

@Test
public void test4(){
    OgnlContext context = new OgnlContext();
    try {
        //java.lang.Math为ognl的内置对象,@@即可表示对java.lang.Math的引用
        Object obj = Ognl.parseExpression("@@min(10, 4)");
        obj = Ognl.getValue(obj, context, context.getRoot());
        System.out.println(obj);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

输出结果:4

List集合的处理

@Test
public void test5(){
    OgnlContext context = new OgnlContext();
    try {
        Object obj = Ognl.getValue("{'aa', 'bb', 'cc'}", context, ontext.getRoot());
        System.out.println(obj instanceof List);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

输出结果:true

@Test
public void test7(){
    OgnlContext context = new OgnlContext();
    try {
        List<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("welcome");
        context.put("list", list);
            
        Object obj = Ognl.getValue("#list[1]", context, context. getRoot());
        System.out.println(obj);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

输出结果:world

Map集合

@Test
public void testMap(){
    OgnlContext context = new OgnlContext();
    try {
        /*
        Map<String, String> map = new HashMap<String, String>();
        map.put("aa", "abc");
        map.put("bb", "zz");
        map.put("cc", "gg");
            
        context.put("map", map);
            
        Object obj = Ognl.getValue("#map['aa']", context, context.getRoot());
        */
        Object obj = Ognl.getValue("#{'aa':'zz', 'bb':'cc', 'dd':'xx'}['aa']", context, context.getRoot());
        System.out.println(obj);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

输出结果:zz

过滤

//过滤,语法格式Collection.{? expr},返回的是一个集合
@Test
public void testFilter(){
    OgnlContext context = new OgnlContext();
    try {
        List<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("welcome");
        list.add("helloworld");
        context.put("list", list);
            
        /*
        Object obj = Ognl.getValue("#list.{? #this.length() gt 5}", context, context.getRoot());
        System.out.println(obj);
        */
        //Object obj = Ognl.getValue("#list.{? #this.length() gt 5}.size()", context, context.getRoot()); //size是伪属性,isEmpty也是伪属性
        Object obj = Ognl.getValue("#list.{? #this.length() gt 5}.size", context, context.getRoot()); 
        System.out.println(obj);  
        System.out.println("==============================");
        /**
         * collectoin.{^ expr} 获取到过滤后的集合中的第一个元素
         */
        obj = Ognl.getValue("#list.{^ #this.length() > 5}", context, context.getRoot()); 
        System.out.println(obj);
        System.out.println("==============================");
            
        /**
         * collectoin.{$ expr} 获取到过滤后的集合中的最后一个元素
         */
        obj = Ognl.getValue("#list.{$ #this.length() > 5}[0]", context, context.getRoot()); 
        System.out.println(obj);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

输出结果:

2

==============================

[welcome]

==============================

helloworld

2.2.8 投影

/**
 * 投影 collection.{expr}, 返回的依然是集合,并且长度不会变化,仅仅只是属性的个数发生的变化。拿数据库来类比:过滤相当于取行的操作(行数的可能会变化),投影相当于数据库的取列的操作。
 */
@Test
public void testProjectoin(){
    OgnlContext context = new OgnlContext();
    try {
        List<Person> list = new ArrayList<Person>();
        Person p1 = new Person();
        p1.setName("zhangsan");
            
        Person p2 = new Person();
        p2.setName("lisi");
            
        Person p3 = new Person();
        p3.setName("wangwu");
        list.add(p1);
        list.add(p2);
        list.add(p3);
        context.put("list", list);
            
        /*//将List中每个Person的name取出来,放到一个集合中
        //Object obj = Ognl.getValue("#list.{name}", context, context.getRoot()); 
        Object obj = Ognl.getValue("#list.{#this.name}", context, context.getRoot()); //与上一行代码实现相同的功能
        System.out.println(obj);
        */
        //当名字长度大于5,就用helloworld来替换,否则保持不变
        //Object obj = Ognl.getValue("#list.{#this.name.length() > 5 ? 'helloworld' : #this.name}", context, context.getRoot()); 
        Object obj = Ognl.getValue("#list.{name.length() > 5 ? 'helloworld' : name}", context, context.getRoot()); //与上一行代码实现相同的功能 
        System.out.println(obj);
    } catch (OgnlException e) {
        e.printStackTrace();
    }
}

 输出结果:

[helloworld, lisi, helloworld]

 

http://www.cnblogs.com/miller-zou/p/5598291.html

http://blog.csdn.net/csh624366188/article/details/7552950#