近段时间在做web项目,前端使用的是jQuery EasyUI。

为方便需要,准备做一个前端通用的Datagird导出Excel功能,博主也考虑过思路和最终功能,1、前端选中行导出;2、当前页导出;3、当前过滤条件导出。

想偷懒在网上找找已有的代码改改,发现大部分只能满足个别需求,使用JS导出只能满足前端,使用代码才能实现3功能。

。。。。。。


好了,说了一堆废话,回归正题,本文是在做通用自定义字段导出时所需要,根据属性名去查找对象和子对象,找到对应属性值,抓取回来放到Excel中。


直接上代码,已经封装好,直接调用即可:

import java.lang.reflect.Field;


/**
 * 属性(对象)值反射获取工具类
 * @author 周围
 * @date 2016-8-14
 */
public class ParamsReflect {
	
	public static final String FILE_FIELD = "nameB,";

	/**
	 * 获取当前对象对应字段的属性(对象)
	 * 声明,需要注意在NoSuchFieldException异常捕捉中捕获自己需要的属性字段进行拦截,告诉当查询这些属性名的时候,指定是查找的哪些对象,如果不告诉它,它是不知道的
	 * @param obj	当前对象
	 * @param field	需要获取的属性名,可以是当前对象中的属性名, 也可以是当前对象中的对象的属性名
	 * @return	Object  当前对象指定属性值
	 */
	public static Object getFieldValue(Object obj, String field) {
		Class claz = obj.getClass();
		Field f = null;
		Object fieldValue = null;
		try {
			f = claz.getDeclaredField(field);
			f.setAccessible(true);
			fieldValue = f.get(obj);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			//此处异常捕获为:找不到属性名异常。
			//注意在此处我们要手工去帮它找到field应该对象到哪个对象里的值,因为我们不知道它们之间的关系,所以需要手工指定关系,找哪个对象去关联
			if(FILE_FIELD.indexOf(field) != -1) fieldValue = getCustomChildObj(obj, claz, B.class, field);
			else fieldValue = null;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return fieldValue;
	}
	
	
	/**
	 * 获取自定义子属性对象,传入指定对象名,在当前对象中找到子对象,再通过field找到子属性
	 * @param obj	父对象名称
	 * @param claz	父对象class反射
	 * @param customClass	自定义判断的子对象类型
	 * @param field	属性名
	 * @return Object
	 */
	public static Object getCustomChildObj(Object obj, Class claz, Class customClass, String field) {
		Field[] fs = claz.getDeclaredFields();
		Field f = null;
		for (int i = 0; i < fs.length; i++) {
			f = fs[i];
			if(f.getType().equals(customClass)) {
				return getChildObjectParam(obj, f, field);
				//return claz.getDeclaredField(f.getName());
			}
		}
		return null;
	}
	
	
	/**
	 * 通过找到的子对象,获取到当前的属性,传入所需的属性名,得到属性值
	 * @param o	父对象
	 * @param f	父对象下的子对象的Field对象
	 * @param field	所需要获取的属性名
	 * @return	Object
	 */
	public static Object getChildObjectParam(Object o, Field f, String field)  {
		f.setAccessible(true);
		Object obj = null;
		Class childClass = null;
		Field childF = null;
		Object fieldValue = null;
		try {
			obj = f.get(o);
			childClass = obj.getClass();
			childF = childClass.getDeclaredField(field);
			childF.setAccessible(true);
			fieldValue = childF.get(obj);
			
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		return fieldValue;
	}
}

模拟测试:

对象A中有属性name,子对象B,对象B中有属性id,nameB。

B b = new B();

b.setId("b");

b.setNameB("b-name");


A a = new A();

a.setName("a-name");

a.setB(b);


Object value1 = ParamsReflect.getFieldValue(a, "name"); //获取a中的属性

Object value2 = ParamsReflect.getFieldValue(a, "nameB"); //获取b中的属性



功能比较简单,并不灵活,为应付功能,先做了一个这样的版本,以后继续完善,也留几个问题。

1、目前的版本只控制到了需要自己传入对应的子对象.class,博主还未想到怎么样设定自动匹配对应的属性值。(也想过直接对该对象和里面的所有子对象进行扫描,拿需要获取值得字段进去得,但是发现一个问题,不同对象中的属性,可能存在属性名相同,所以扫描无法控制唯一性)


2、以上版本是用于EasyUI中的Datagrid,该控件中的field属性无法命名为"b.nameB",不能直接用子对象去获取子属性,博主也尝试改过EasyUI的JS源码,让其支持子对象.属性的方式,但又存在其他的问题不兼容这个方式,所以以这个方案实施,有大神有其他办法吗。


3、最终版,作者是准备在空闲的时候完善升级它,不局限于Datagrid,所有都支持的导出Excel功能。这里准备做的是,先将对象传入后台,并进入数据库查询,将对应实体的表,字段名,字段类型全部获取到。之后处理成对应格式,是子对象的,用子对象属性名.子对象属性拼接好,返回前台,让用户选择需要导出的列,选择完毕后返回后台,拼接这些字段,生成SQL语句,传入后台自行查询,至于过滤那部分,应该是没办法抽取的,需要在各自的控制层处理一下。


记录每一次的技术心得。