对ognl表达式的简单实现(Ognl.getValue(express,root)),帮助理解ognl表达式的基本原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对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表达式的基本原理的主要内容,如果未能解决你的问题,请参考以下文章