标签:sys 简单实现 war ret his 实现 框架 substr reflect
最近在学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表达式的基本原理
标签:sys 简单实现 war ret his 实现 框架 substr reflect
原文地址:http://www.cnblogs.com/wyhgo/p/6696485.html