首页 > 代码库 > 对ognl表达式的简单实现(Ognl.getValue(express,root)),帮助理解ognl表达式的基本原理

对ognl表达式的简单实现(Ognl.getValue(express,root)),帮助理解ognl表达式的基本原理

     最近在学struts2,给ognl以及值栈搞的头疼,决定简单实现下 Ognl.getValue(express,root),核心还是反射啦,下面代码复制就可以直接跑

package core;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by wyh on 4/11/2017.
 */
public class AccessBean  {
    class foo{
        bar bar;
        public foo(bar bar){this.bar=bar;}
        public AccessBean.bar getBar() {return bar;}}
    class bar{
        String name;
        foobar foobar;
        public bar(){}
        public bar(String name){this.name=name;}
        public bar(foobar foobar){this.foobar=foobar;}
        public String getName() {return name;}
        public foobar getFoobar() {return foobar;}}
    class foobar{
        String name;
        public foobar(String name){this.name=name;}
        public String getName() {return name;}}
    /**
     * 这是获取单个对象即 foo.bar
     * */
    @SuppressWarnings("unchecked")
    public static Object getSingleProperty(Object root, String property) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class rootClass=root.getClass();
        //得到getter方法名
        String getterStr="get"+property.substring(0,1).toUpperCase()+property.substring(1);
        //获取getter方法对象
        Method getter=rootClass.getDeclaredMethod(getterStr);
        //实施
        return getter.invoke(root);
    }

    /**
     * 利用循环获取多个对象 foo.bar.foobar
     * 表达式默认是直接从property.property2开始,而不是#root.property.property2这种表达式
     * */
    public static Object getValue(Object root,String ognlExpression) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        //将ognl表达式分解为单个属性
        String[] properties=ognlExpression.split("\\.");
        //循环赋值
        for(String property:properties){
            root=getSingleProperty(root,property);
        }
        return root;
    }
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        //创建公有类对象
        AccessBean accessBean=new AccessBean();
        //通过公有类对象创建内部类
        bar bar=accessBean.new bar("i am bar");
        foo foo=accessBean.new foo(bar);
        //获取属性
        System.out.println(getValue(foo,"bar.name"));
        //获取三级属性
        foobar foobar=accessBean.new foobar("i am foobar");
        bar bar2=accessBean.new bar(foobar);
        foo foo2=accessBean.new foo(bar2);

        System.out.println(getValue(foo2,"bar.foobar.name"));
    }
}

  

所以,原理很简单,本质还是通过反射调用getter方法.框架技术离不开反射,xml,注解,把基础打好,你也可以

我们知道,ognl只能从一个root对象开始找,root对象有多个呢?放在map中,然后给出其中一个的key值即可,下面,给出模仿,复制即可运行

 

package core;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by wyh on 4/11/2017.
 */
public class AccessBean2 {
    class foo{
     bar bar; public foo(bar bar){ this.bar=bar; } public AccessBean2.bar getBar() { return bar; }} class bar{ String name; foobar foobar; public bar(){} public bar(String name){this.name=name;} public bar(foobar foobar){this.foobar=foobar; } public String getName() {return name; } public foobar getFoobar() {return foobar;} } class foobar{ String name; public foobar(String name){this.name=name;} public String getName() {return name;} } /** * 这是获取单个对象即 foo.bar * */ @SuppressWarnings("unchecked") public static Object getSingleProperty(Object root, String property) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class rootClass=root.getClass(); //得到getter方法名 String getterStr="get"+property.substring(0,1).toUpperCase()+property.substring(1); //获取getter方法对象 Method getter=rootClass.getDeclaredMethod(getterStr); //实施 return getter.invoke(root); } public static Object getValueForMap(Map<String,Object> context, String ognlExpression) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { //解析字符串,拿到每个属性 String[] properties=ognlExpression.split("\\."); //获得map中的根key值 String rootKey=properties[0].substring(1); //取出value,作为根节点 Object root=context.get(rootKey); int size=properties.length; //因为已经有根节点对象了,从从第二个属性开始循环 for(int i=1;i<size;i++){ //这里其实用到了递归,即不断获取这个对象的属性,作为下一个对象(用取出属性来,说明是一个对象),直到循环结束,到达你想要获取的末端属性 //把一个大实体类,不断解开为被聚合的对象 root=getSingleProperty(root,properties[i]); } return root; } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { //创建公有类对象 AccessBean2 accessBean=new AccessBean2(); //通过公有类对象创建内部类 bar bar=accessBean.new bar("i am bar"); foo foo=accessBean.new foo(bar); //获取属性 foobar foobar=accessBean.new foobar("i am foobar"); bar bar2=accessBean.new bar(foobar); foo foo2=accessBean.new foo(bar2); Map<String,Object> context=new HashMap<>(); context.put("foo",foo); context.put("foo2",foo2); //获取map中"foo"开头的对象的属性 System.out.println(getValueForMap(context,"#foo.bar.name")); //获取map中"foo2"开头的对象的属性 System.out.println(getValueForMap(context,"#foo2.bar.foobar.name")); } }

  


  在ognl中,获取根节点中属性还可以通过,其中#root和#context为固定用法:

直接访问:

Ognl.getValue("street.district.districtName",house));
//根对象为house,省略表达式 Ognl.getValue("#root.street.district.districtName",house); //#root指代house对象 通过map访问不同根对象: Ognl.getValue("#root.street.district.districtName",context,house); //此处#root代表house对象,等价于Ognl.getValue("#root.street.district.districtName",house).其中context不起作用.只为适用其他用法,方法体作为模板出现 Ognl.getValue("#context.house.street.district.districtName",context,house); //同样,#content指代context对象,后面#context.house指代map中的字符串key.最后的house不起作用,只为适用其他用法,凑数用

Ognl.getValue("#house.street.district.districtName",context,house); //此为通过context这个map找root对象,#house表示key值,house对象不起作用

     

      一言以蔽之,使用ognl获取级联属性,只需要告诉ognl根对象是什么(真实的对象),然后以字符串的形式告之这个根对象后面的属性链是什么,就可以找到了.也就是说,最少只需要一个根对象和表达式.

 

     至少以上的几种不同使用方法,只是解析字符串不同罢了,给开发者多几种选择,好看上去高大上一点,初学者别给吓着了.

    

     在战略上藐视技术,在战术上钻研技术

对ognl表达式的简单实现(Ognl.getValue(express,root)),帮助理解ognl表达式的基本原理