这2 天遇到个问题
原因是在将数据进行excel导出的时候用的是hutools 的excelUtil方法
我使用的是导出list 但是有些小问题 因为导出的时候是导出list里面每个对象的所有字段
那比如有2个导出功能 一个用到Stu类的age 一个用到Stu类的name 我就得相对应的建2个bean对象
我就在想有没有相对应的方法就是在导出对象的时候可以忽略里面的某个属性
但是一直没找到相应的方法
然后就想着自定义个方法
首先想到的是重写write方法。。。。。。。但是发现难度特别大。,,
然后就相当利用反射把生成一个bean对象里面就只包含想要的属性值
一开始找的是jdk 的类 里面没发现什么方法(估计是技术太菜) 但是里面我发现了Class有个copyFiled方法 可是我在api文档里没有找到这个方法(1.8) 而且我发现通过反射似乎不能获取到这个方法。,。,。,
然后就在找有没有增加字段的方法 最后找到了cglib
BeanGenerator generator = new BeanGenerator();generator.addProperty(“a”,String.class); Object o1 = generator.create();
但是在我进行excel 导出的时候就发现无法被导出
就一直debug 发现
//在这个方法里 targetMap就是null了相当于赋值不进去public static Map<String, Object> beanToMap(Object bean, Map<String, Object> targetMap, boolean ignoreNullValue, Editor<String> keyEditor) {//这里是原因 getter方法就是null if (null != getter) {// 只读取有getter方法的属性try {value = getter.invoke(bean);} catch (Exception ignore) {continue;}if (false == ignoreNullValue || (null != value && false == value.equals(bean))) {key = keyEditor.edit(key);if (null != key) {targetMap.put(key, value);}}}return targetMap;}
我就在想是不是因为cglib生成的没有getter方法
然后就是自己随便定义了个对象 没有对应的get方法
//然后在这里的BeanUtil.isBean(rowBean.getClass()) 不进入了 ,,,, 因为bean是得有相对应的get方法的public ExcelWriter writeRow(Object rowBean, boolean isWriteKeyAsHead) {else if(BeanUtil.isBean(rowBean.getClass())){if (MapUtil.isEmpty(this.headerAlias)) {rowMap = BeanUtil.beanToMap(rowBean, new LinkedHashMap<String, Object>(), false, false);} else {// 别名存在情况下按照别名的添加顺序排序Bean数据rowMap = BeanUtil.beanToMap(rowBean, new TreeMap<String, Object>(getInitedAliasComparator()), false, false);}}else {//其它转为字符串默认输出return writeRow(CollUtil.newArrayList(rowBean), isWriteKeyAsHead);}
更新:
BeanUtil.isBean(rowBean.getClass()) 还是这个方法 点进去 public static boolean isBean(Class<?> clazz) {if (ClassUtil.isNormalClass(clazz)) {final Method[] methods = clazz.getMethods();for (Method method : methods) {if (method.getParameterTypes().length == 1 && method.getName().startsWith(“set”)) {// 检测包含标准的setXXX方法即视为标准的JavaBeanreturn true;}}}return false;}这里就显示出了 只有含有setXXX的方法才能被视为标准bean 然后把自己随便定义的对象去掉get方法 只留下 set 果然也就不能打印了 public static Map<String, Object> beanToMap(Object bean, Map<String, Object> targetMap, boolean ignoreNullValue, Editor<String> keyEditor) {if (null != getter) {// 只读取有getter方法的属性 因为这里定义了只读取又getter的方法
这里展示了通过generator生成的方法 里面的方法是setPrivate 参数虽然都是String 但是一个数name类型一个是age类型 所以不会出事吧。,, ——–**强行解释。。。。**但是在后面的字节码文件里发现这样解释是错的
这里的时候看到方法是setPrivate
然后联想到上面写着的// 检测包含标准的setXXX方法即视为标准的JavaBean
就试了下把原先的setAge 改成了setTTTAge 发现还是可以打印 然后改成seAge就不行了
果然代码里写着
if (method.getParameterTypes().length == 1 && method.getName().startsWith(“set”)) {// 检测包含标准的setXXX方法即视为标准的JavaBeanreturn true;}
最一开始提到的
if (null != getter) { 这个判断
对于cglib生成的对象
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “C:\\class”);
通过这个方式使得cglib生成的对象 的字节码文件被输出
class文件如下
// Decompiled by DJ v3.12.12.98 Copyright 2014 Atanas Neshkov Date: 2020/1/11 15:54:28// Home Page: http://www.neshkov.com/dj.html – Check often for new version!// Decompiler options: packimports(3) package net.sf.cglib.empty;public class Object$$BeanGeneratorByCGLIB$$cb8daf94{ public String getPrivate_20_java.lang.String_20_Demo.HuDemo.age() { return age; } public void setPrivate_20_java.lang.String_20_Demo.HuDemo.age(String s) { age = s; } public String getPrivate_20_java.lang.String_20_Demo.HuDemo.name() { return name; } public void setPrivate_20_java.lang.String_20_Demo.HuDemo.name(String s) { name = s; } private String $cglib_prop_private_20_java.lang.String_20_Demo.HuDemo.age; private String $cglib_prop_private_20_java.lang.String_20_Demo.HuDemo.name; public Object$$BeanGeneratorByCGLIB$$cb8daf94() { }}
————————————————————————————————
接下来就是寻找为什么getter为null了
getter = prop.getGetter();public Method getGetter() {return this.getter;}private Method getter;接下来就是寻找getter在哪里赋值public PropDesc(Field field, Method getter, Method setter) {this.field = field;this.getter = ClassUtil.setAccessible(getter);this.setter = ClassUtil.setAccessible(setter);}然后就是寻找哪里调用了这个构造函数private PropDesc createProp(Field field) { return new PropDesc(field, getter, setter);}下面的这个方法点进去if (parameterTypes.length == 0) {// 无参数,可能为Getter方法if (isMatchGetter(methodName, fieldName, isBooeanField)) {// 方法名与字段名匹配,则为Getter方法getter = method;}} //因为是cglib生成的bean所以全部返回falseprivate boolean isMatchGetter(String methodName, String fieldName, boolean isBooeanField) {// 全部转为小写,忽略大小写比较methodName = methodName.toLowerCase(); //getprivate java.lang.string demo.hudemo.namefieldName = fieldName.toLowerCase();//$cglib_prop_private java.lang.string demo.hudemo.ageif (false == methodName.startsWith(“get”) && false == methodName.startsWith(“is”)) {// 非标准Getter方法return false;}if(“getclass”.equals(methodName)) {//跳过getClass方法return false;}// 针对Boolean类型特殊检查if (isBooeanField) {if (fieldName.startsWith(“is”)) {// 字段已经是is开头if (methodName.equals(fieldName) // isName -》 isName|| methodName.equals(“get” + fieldName)// isName -》 getIsName|| methodName.equals(“is” + fieldName)// isName -》 isIsName) {return true;}} else if (methodName.equals(“is” + fieldName)) {// 字段非is开头, name -》 isNamereturn true;}}// 包括boolean的任何类型只有一种匹配情况:name -》 getNamereturn methodName.equals(“get” + fieldName);}
————————————————————————
原本想在
if (isMatchGetter(methodName, fieldName, isBooeanField)) {// 方法名与字段名匹配,则为Getter方法getter = method;}
结果。。。
// 包括boolean的任何类型只有一种匹配情况:name -》 getNamereturn methodName.equals(“get” + fieldName);
}
————————————————————————原本想在“`javaif (isMatchGetter(methodName, fieldName, isBooeanField)) {// 方法名与字段名匹配,则为Getter方法getter = method;}
结果。。。
想了想我还是自定义个方法吧,,,,如果是cglib去生成bean去接收更加麻烦。。
于是下载了下源代码,然后自定义了个方法,其实也就是复制了一下原有的方法 多了个参数传递下去而已
关键也就是这个continue了。。