利用递归遍历获取复杂对象中所有目标属性的值(三)
关于遍历复杂对象中目标属性的值的文章,这是我写的第三篇,也是目前为止我能想到的遍历效率最高的一篇,再前两篇基础上做了相关完善和优化,主要是思路改变了。
具体实现思路:在复杂对象的目标属性上增加自定义注解,目标属性所属类也可能是某个bo的属性,则在这个属性上增加另一个自定义注解,然后利用递归遍历。
闲话少说,直接上代码
一、两个自定义注解
/**
* @author: lsl
* @date: 2019/3/1
* 作用:字典类属性注解
*/
@Target(value = {ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DictClass {
public String value() default "";
}
/**
* @author: lsl
* @date: 2019/3/1
* 字典属性注解
*/
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DictField {
public String dictCode();
public String transColumName() default "";
public String isSpeRule() default "0";
}
二、核心代码,递归遍历类。主要方法是ergodicObject。入口方法是objectCodeTrans。
package com.newcore.pcms.common.support.codetrans.util;
import com.halo.core.cache.api.CacheMetaInfoFactory;
import com.halo.core.cache.api.CacheService;
import com.halo.core.cache.models.IndexItem;
import com.halo.core.cache.support.redis.holder.TableHolder;
import com.halo.core.common.SpringContextHolder;
import com.halo.core.common.models.XOR;
import com.halo.core.exception.BusinessException;
import com.newcore.pcms.common.support.codetrans.annotation.DictClass;
import com.newcore.pcms.common.support.codetrans.annotation.DictField;
import com.newcore.pcms.common.support.codetrans.dao.api.ServiceAttrDictDao;
import com.newcore.pcms.common.support.codetrans.models.po.pcms.PCodeTransDefPO;
import com.newcore.pcms.common.support.codetrans.models.po.pcms.ServiceAttrDictBO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 对象级的码表转换工具类
* @author: lsl
* @date: 2018/12/12
*/
public class CodeTransHolderUtils {
private static Logger logger = LoggerFactory.getLogger(CodeTransHolderUtils.class);
int num=0;
// public static CacheMetaInfoFactory getCacheMetaInfoFactory() {
// return (CacheMetaInfoFactory) SpringContextHolder.getBean("cacheMetaInfoFactory");
// }
//
// public static CacheService getCacheService() {
// return (CacheService) SpringContextHolder.getBean("cacheService");
// }
/**
* 对服务中参数中的属性是字典,进行全部码值转换
* @param srcSysCode 源系统
* @param destSysCode 目标系统
* @param obj 服务中方法入参
* @return
*/
public static List<String> objectCodeTrans(String srcSysCode, String destSysCode, Object obj) {
List<String> listNotIncludeAttr = new ArrayList<>();
// boolean methodParamNameNotBlank = (ConstantTools.FLAG_Y).equals(forwardFlag) ? StringUtils.isNotBlank(serMethodParamName) : true;
boolean notBlankFlag = StringUtils.isNotBlank(srcSysCode) && StringUtils.isNotBlank(destSysCode) && (null!= obj) ;
logger.info("objectCodeTrans方法的参数:srcSysCode=" + srcSysCode + ",destSysCode=" + destSysCode );
CodeTransHolderUtils utils = new CodeTransHolderUtils();
long startTime = System.currentTimeMillis();
if (notBlankFlag){
if (obj instanceof List<?>) {
utils.ergodicList(srcSysCode, destSysCode, (List) obj , listNotIncludeAttr);
} else {
utils.ergodicObject(srcSysCode, destSysCode, obj, listNotIncludeAttr);
}
}
long endTime = System.currentTimeMillis();
System.err.println("对象级码表转换耗时=" + (endTime-startTime) + ",递归次数=" + utils.num);
return listNotIncludeAttr;
}
/**
*
* @param srcSysCode 源系统
* @param destSysCode 目标系统
* @param listParam 服务方法入参(list)
* @param listNotIncludeAttr 入参字典属性未在码表中找到对应的目标系统字典值的属性名
* @param <T> 码表转换后的入参
*/
public <T> void ergodicList(String srcSysCode, String destSysCode, List<T> listParam, List<String> listNotIncludeAttr) {
listParam.stream().forEach(t -> {
ergodicObject(srcSysCode, destSysCode, t, listNotIncludeAttr);
});
}
/**
* 对象级码表转换。把t中指定attribute属性的值更改为目标系统的字典值,并把在目标系统中没有找到字典值的属性放到listNotIncludeAttr
* 注意:
* 1、t中的属性类型不能包含以下集合嵌套类型:Set、List<Map<K,V>、Map<K,List<BO>>
* 2、t中的属性类型可以是BO、数组、List<BO>、Map<K,BO>
* 3、属性名一定要规范,比如private PCodeTransDefPO pCodeTransDefPO(不规范),这样利用反射找不到getter方法,应该改成codeTransDefPO或者PCodeTransDefPO
* @param srcSysCode 源系统
* @param destSysCode 目标系统
* @param t 入参对象(是BO非list)
* @param listNotIncludeAttr 没有在码表中找到目标系统中对应的码值的字典属性
* @param <T> 码表转换后的入参
*/
public <T> void ergodicObject(String srcSysCode, String destSysCode, T t, List<String> listNotIncludeAttr) {
num++;
Class clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
try {
for (Field field : fields) {
field.setAccessible(true);
// String attrType = field.getType().getSimpleName();//属性类型
String attrShortName = field.getName();//属性名
if (field.isAnnotationPresent(DictField.class)){
String attrValue = (String)field.get(t);//属性值
String dictCode = field.getAnnotation(DictField.class).dictCode();//字典名
String transColumName = field.getAnnotation(DictField.class).transColumName();//词汇名
String isSpeRule = field.getAnnotation(DictField.class).isSpeRule();//是否特殊
if(ConstantTools.DEFAULT_0.equals(isSpeRule) ){
transColumName="";
}
// String destCodeVal = "";
String destCodeVal =CodeTransDefTools.queryOneUnCodeTransValPOrder(srcSysCode,destSysCode,dictCode,attrValue,isSpeRule,transColumName);
//如果t中的目标属性的值为null或者"",则不需要修改其值
if (attrValue != null && !"".equals(attrValue)){
if (destCodeVal != null && !"".equals(destCodeVal)) {
//如果从目标系统中查到的字典值非null或者非空字符串,则重新给属性赋值,否则把属性放到listNotIncludeAttr
field.set(t, destCodeVal);
} else {
listNotIncludeAttr.add(attrShortName);
logger.info("在目标系统" + destSysCode + "中,没有找到源系统" + srcSysCode + "中属性是" + attrShortName + "对应的字典" + dictCode + ",找到的字典值是:" + destCodeVal);
}
}
}else if (field.isAnnotationPresent(DictClass.class)){
if (isList(field)){
//对List/ArrayList类型的属性遍历
try {
PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
Method method = descriptor.getReadMethod();
List list = (List) method.invoke(t);
if (list != null && list.size() > 0) {
list.stream().forEach(p -> {
// 递归
ergodicObject(srcSysCode, destSysCode, p, listNotIncludeAttr);
});
}
} catch (IntrospectionException e) {
logger.info(e.getMessage());
} catch (InvocationTargetException e) {
logger.info(e.getMessage());
}
}else if(isMap(field)){
//对Map/HashMap类型的属性遍历
try {
PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
Method method = descriptor.getReadMethod();
Map map = (Map) method.invoke(t);
if (map != null && map.size() > 0) {
for (Object obj : map.values()) {
// 递归
ergodicObject(srcSysCode, destSysCode, obj, listNotIncludeAttr);
}
}
} catch (IntrospectionException e) {
logger.info(e.getMessage());
} catch (InvocationTargetException e) {
logger.info(e.getMessage());
}
}else if (field.getType().isArray()) {
//对数组类型的属性遍历
field.setAccessible(true);
Object[] objArr = (Object[]) field.get(t);
if (objArr != null && objArr.length > 0) {
for (Object arr : objArr) {
//递归
ergodicObject(srcSysCode, destSysCode, arr, listNotIncludeAttr);
}
}
}else {
//对自定义类的属性递归
try {
PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
Method method = descriptor.getReadMethod();
Object obj = method.invoke(t);
if (obj != null) {
//递归
ergodicObject(srcSysCode, destSysCode, obj, listNotIncludeAttr);
} else {
continue;
}
} catch (IntrospectionException e) {
logger.info(e.getMessage());
} catch (InvocationTargetException e) {
logger.info(e.getMessage());
}
}
}else {
continue;
}
}
} catch (IllegalAccessException e) {
logger.info(e.getMessage());
}
}
/**
* 判断是否是List或者ArrayList
* @param field
* @return
*/
public boolean isList(Field field){
boolean flag = false;
String simpleName = field.getType().getSimpleName();
if ("List".equals(simpleName) || "ArrayList".equals(simpleName)){
flag = true;
}
return flag;
}
/**
* 判断是否是Map或者HashMap
* @param field
* @return
*/
public boolean isMap(Field field){
boolean flag = false;
String simpleName = field.getType().getSimpleName();
if ("Map".equals(simpleName) || "HashMap".equals(simpleName)){
flag = true;
}
return flag;
}
}
三、如何使用
复杂对象如下:
package com.lsl.model;
import com.lsl.annotion.DictClass;
import java.util.List;
/**
* @author: lsl
* @date: 2019/2/27
*/
public class ParentClass {
private String fatherName;
private int fatherAge;
@DictClass
private List<SubClass> list;
@DictClass
private SubClass subClass;
public String getFatherName() {
return fatherName;
}
public void setFatherName(String fatherName) {
this.fatherName = fatherName;
}
public int getFatherAge() {
return fatherAge;
}
public void setFatherAge(int fatherAge) {
this.fatherAge = fatherAge;
}
public List<SubClass> getList() {
return list;
}
public void setList(List<SubClass> list) {
this.list = list;
}
public SubClass getSubClass() {
return subClass;
}
public void setSubClass(SubClass subClass) {
this.subClass = subClass;
}
}
复杂对象ParentClass包含子对象SubClass
子对象SubClass代码:
package com.lsl.model;
import com.lsl.annotion.DictField;
/**
* @author: lsl
* @date: 2019/2/27
*/
public class SubClass {
@DictField(dictCode = "aaa")
private String subName;
private int subAge;
public String getSubName() {
return subName;
}
public void setSubName(String subName) {
this.subName = subName;
}
public int getSubAge() {
return subAge;
}
public void setSubAge(int subAge) {
this.subAge = subAge;
}
}
简单测试,和二、核心代码部分略有区别
package com.lsl;
import com.alibaba.fastjson.JSON;
import com.lsl.annotion.DictClass;
import com.lsl.annotion.DictField;
import com.lsl.model.ParentClass;
import com.lsl.model.SubClass;
import com.lsl.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author: lsl
* @date: 2019/2/15
*/
@Controller
@RequestMapping("/lsl")
public class MyTest {
public static void main(String [] args){
SubClass sub1 = new SubClass();
sub1.setSubAge(21);
sub1.setSubName("aaa");
SubClass sub2 = new SubClass();
sub2.setSubName("bbb");
sub2.setSubAge(20);
SubClass sub3 = new SubClass();
sub3.setSubName("ccc");
sub3.setSubAge(22);
List<SubClass> list = new ArrayList();
list.add(sub1);
list.add(sub2);
ParentClass parent = new ParentClass();
parent.setFatherAge(18);
parent.setFatherName("aaa");
parent.setSubClass(sub3);
parent.setList(list);
ergodicObject(parent);
}
public static <T> void ergodicObject(T t){
Class clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
try {
for (Field field : fields) {
field.setAccessible(true);
// String attrType = field.getType().getSimpleName();//属性类型
String attrShortName = field.getName();//属性名
if (field.isAnnotationPresent(DictField.class)){
String attrValue = (String)field.get(t);//属性值
}else if (field.isAnnotationPresent(DictClass.class)){
if (isList(field)){
//对List/ArrayList类型的属性遍历
try {
PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
Method method = descriptor.getReadMethod();
List list = (List) method.invoke(t);
if (list != null && list.size() > 0) {
for(Object obj : list){
ergodicObject(obj);
}
}
} catch (IntrospectionException e) {
// logger.info(e.getMessage());
} catch (InvocationTargetException e) {
// logger.info(e.getMessage());
}
}else if(isMap(field)){
//对Map/HashMap类型的属性遍历
try {
PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
Method method = descriptor.getReadMethod();
Map map = (Map) method.invoke(t);
if (map != null && map.size() > 0) {
for (Object obj : map.values()) {
// 递归
ergodicObject( obj);
}
}
} catch (IntrospectionException e) {
// logger.info(e.getMessage());
} catch (InvocationTargetException e) {
// logger.info(e.getMessage());
}
}else if (field.getType().isArray()) {
//对数组类型的属性遍历
field.setAccessible(true);
Object[] objArr = (Object[]) field.get(t);
if (objArr != null && objArr.length > 0) {
for (Object arr : objArr) {
//递归
ergodicObject( arr);
}
}
}else {
//对自定义类的属性递归
try {
PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
Method method = descriptor.getReadMethod();
Object obj = method.invoke(t);
if (obj != null) {
//递归
ergodicObject( obj);
} else {
continue;
}
} catch (IntrospectionException e) {
// logger.info(e.getMessage());
} catch (InvocationTargetException e) {
// logger.info(e.getMessage());
}
}
}else {
continue;
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static boolean isList(Field field){
boolean flag = false;
String simpleName = field.getType().getSimpleName();
if ("List".equals(simpleName) || "ArrayList".equals(simpleName)){
flag = true;
}
return flag;
}
/**
* 判断是否是Map或者HashMap
* @param field
* @return
*/
public static boolean isMap(Field field){
boolean flag = false;
String simpleName = field.getType().getSimpleName();
if ("Map".equals(simpleName) || "HashMap".equals(simpleName)){
flag = true;
}
return flag;
}
public static String countMethod(){
StringBuffer a= new StringBuffer("11");
try {
try {
a = a.append("22");
int m=1/0;
} catch (Exception e) {
System.err.println("内层catch执行");
throw e;
}
// return a.toString();
} catch (Exception e) {
// return a.toString();
System.err.println("外层catch执行");
throw e;
} finally {
a = a.append("33");
System.err.println("finally==a==" + a);
}
return a.toString();
}
@Autowired
MyService service;
// @Transactional
@RequestMapping("/lock")
public void tranactionalTest(){
BizLock lock = new BizLock();
BizLock bizLock = new BizLock();
bizLock.setBizId("11223344");
bizLock.setBizNo("aabbccdd");
bizLock.setBizType("MTNNO");
long nowTime = System.currentTimeMillis();
bizLock.setCreateTime(new Timestamp(nowTime));
bizLock.setPassTime(new Timestamp(nowTime));
int count = service.addLock(bizLock);
if (count==1){
System.err.println("加锁成功" + count);
}else {
System.err.println("加锁失败" + count);
}
// int aa = 1/0;
// try {
// System.err.println("Thread名字"+ Thread.currentThread().getName() + ",开始休眠8888888");
// Thread.sleep(50000L);
// } catch (InterruptedException e) {
//
// }
int num=12;
System.err.println("endendendend");
// return count;
}
@RequestMapping("/lock2")
public void tranactionalTes2t(){
BizLock lock = new BizLock();
BizLock bizLock = new BizLock();
bizLock.setBizId("11223344");
bizLock.setBizNo("aabbccdd");
bizLock.setBizType("MTNNO");
long nowTime = System.currentTimeMillis();
bizLock.setCreateTime(new Timestamp(nowTime));
bizLock.setPassTime(new Timestamp(nowTime));
int count = service.addLock(bizLock);
if (count==1){
System.err.println("加锁成功" + count);
}else {
System.err.println("加锁失败" + count);
}
//
System.err.println("endendendend");
}
}
还没有评论,来说两句吧...