利用递归遍历获取复杂对象中所有目标属性的值(三)

待我称王封你为后i 2022-03-14 15:08 586阅读 0赞
  1. 关于遍历复杂对象中目标属性的值的文章,这是我写的第三篇,也是目前为止我能想到的遍历效率最高的一篇,再前两篇基础上做了相关完善和优化,主要是思路改变了。
  2. 具体实现思路:在复杂对象的目标属性上增加自定义注解,目标属性所属类也可能是某个bo的属性,则在这个属性上增加另一个自定义注解,然后利用递归遍历。
  3. 闲话少说,直接上代码

一、两个自定义注解

  1. /**
  2. * @author: lsl
  3. * @date: 2019/3/1
  4. * 作用:字典类属性注解
  5. */
  6. @Target(value = {ElementType.TYPE,ElementType.FIELD})
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface DictClass {
  9. public String value() default "";
  10. }
  11. /**
  12. * @author: lsl
  13. * @date: 2019/3/1
  14. * 字典属性注解
  15. */
  16. @Target(value = {ElementType.FIELD})
  17. @Retention(RetentionPolicy.RUNTIME)
  18. public @interface DictField {
  19. public String dictCode();
  20. public String transColumName() default "";
  21. public String isSpeRule() default "0";
  22. }

二、核心代码,递归遍历类。主要方法是ergodicObject。入口方法是objectCodeTrans。

  1. package com.newcore.pcms.common.support.codetrans.util;
  2. import com.halo.core.cache.api.CacheMetaInfoFactory;
  3. import com.halo.core.cache.api.CacheService;
  4. import com.halo.core.cache.models.IndexItem;
  5. import com.halo.core.cache.support.redis.holder.TableHolder;
  6. import com.halo.core.common.SpringContextHolder;
  7. import com.halo.core.common.models.XOR;
  8. import com.halo.core.exception.BusinessException;
  9. import com.newcore.pcms.common.support.codetrans.annotation.DictClass;
  10. import com.newcore.pcms.common.support.codetrans.annotation.DictField;
  11. import com.newcore.pcms.common.support.codetrans.dao.api.ServiceAttrDictDao;
  12. import com.newcore.pcms.common.support.codetrans.models.po.pcms.PCodeTransDefPO;
  13. import com.newcore.pcms.common.support.codetrans.models.po.pcms.ServiceAttrDictBO;
  14. import org.apache.commons.lang3.StringUtils;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17. import java.beans.IntrospectionException;
  18. import java.beans.PropertyDescriptor;
  19. import java.lang.reflect.Field;
  20. import java.lang.reflect.InvocationTargetException;
  21. import java.lang.reflect.Method;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.Map;
  25. /**
  26. * 对象级的码表转换工具类
  27. * @author: lsl
  28. * @date: 2018/12/12
  29. */
  30. public class CodeTransHolderUtils {
  31. private static Logger logger = LoggerFactory.getLogger(CodeTransHolderUtils.class);
  32. int num=0;
  33. // public static CacheMetaInfoFactory getCacheMetaInfoFactory() {
  34. // return (CacheMetaInfoFactory) SpringContextHolder.getBean("cacheMetaInfoFactory");
  35. // }
  36. //
  37. // public static CacheService getCacheService() {
  38. // return (CacheService) SpringContextHolder.getBean("cacheService");
  39. // }
  40. /**
  41. * 对服务中参数中的属性是字典,进行全部码值转换
  42. * @param srcSysCode 源系统
  43. * @param destSysCode 目标系统
  44. * @param obj 服务中方法入参
  45. * @return
  46. */
  47. public static List<String> objectCodeTrans(String srcSysCode, String destSysCode, Object obj) {
  48. List<String> listNotIncludeAttr = new ArrayList<>();
  49. // boolean methodParamNameNotBlank = (ConstantTools.FLAG_Y).equals(forwardFlag) ? StringUtils.isNotBlank(serMethodParamName) : true;
  50. boolean notBlankFlag = StringUtils.isNotBlank(srcSysCode) && StringUtils.isNotBlank(destSysCode) && (null!= obj) ;
  51. logger.info("objectCodeTrans方法的参数:srcSysCode=" + srcSysCode + ",destSysCode=" + destSysCode );
  52. CodeTransHolderUtils utils = new CodeTransHolderUtils();
  53. long startTime = System.currentTimeMillis();
  54. if (notBlankFlag){
  55. if (obj instanceof List<?>) {
  56. utils.ergodicList(srcSysCode, destSysCode, (List) obj , listNotIncludeAttr);
  57. } else {
  58. utils.ergodicObject(srcSysCode, destSysCode, obj, listNotIncludeAttr);
  59. }
  60. }
  61. long endTime = System.currentTimeMillis();
  62. System.err.println("对象级码表转换耗时=" + (endTime-startTime) + ",递归次数=" + utils.num);
  63. return listNotIncludeAttr;
  64. }
  65. /**
  66. *
  67. * @param srcSysCode 源系统
  68. * @param destSysCode 目标系统
  69. * @param listParam 服务方法入参(list)
  70. * @param listNotIncludeAttr 入参字典属性未在码表中找到对应的目标系统字典值的属性名
  71. * @param <T> 码表转换后的入参
  72. */
  73. public <T> void ergodicList(String srcSysCode, String destSysCode, List<T> listParam, List<String> listNotIncludeAttr) {
  74. listParam.stream().forEach(t -> {
  75. ergodicObject(srcSysCode, destSysCode, t, listNotIncludeAttr);
  76. });
  77. }
  78. /**
  79. * 对象级码表转换。把t中指定attribute属性的值更改为目标系统的字典值,并把在目标系统中没有找到字典值的属性放到listNotIncludeAttr
  80. * 注意:
  81. * 1、t中的属性类型不能包含以下集合嵌套类型:Set、List<Map<K,V>、Map<K,List<BO>>
  82. * 2、t中的属性类型可以是BO、数组、List<BO>、Map<K,BO>
  83. * 3、属性名一定要规范,比如private PCodeTransDefPO pCodeTransDefPO(不规范),这样利用反射找不到getter方法,应该改成codeTransDefPO或者PCodeTransDefPO
  84. * @param srcSysCode 源系统
  85. * @param destSysCode 目标系统
  86. * @param t 入参对象(是BO非list)
  87. * @param listNotIncludeAttr 没有在码表中找到目标系统中对应的码值的字典属性
  88. * @param <T> 码表转换后的入参
  89. */
  90. public <T> void ergodicObject(String srcSysCode, String destSysCode, T t, List<String> listNotIncludeAttr) {
  91. num++;
  92. Class clazz = t.getClass();
  93. Field[] fields = clazz.getDeclaredFields();
  94. try {
  95. for (Field field : fields) {
  96. field.setAccessible(true);
  97. // String attrType = field.getType().getSimpleName();//属性类型
  98. String attrShortName = field.getName();//属性名
  99. if (field.isAnnotationPresent(DictField.class)){
  100. String attrValue = (String)field.get(t);//属性值
  101. String dictCode = field.getAnnotation(DictField.class).dictCode();//字典名
  102. String transColumName = field.getAnnotation(DictField.class).transColumName();//词汇名
  103. String isSpeRule = field.getAnnotation(DictField.class).isSpeRule();//是否特殊
  104. if(ConstantTools.DEFAULT_0.equals(isSpeRule) ){
  105. transColumName="";
  106. }
  107. // String destCodeVal = "";
  108. String destCodeVal =CodeTransDefTools.queryOneUnCodeTransValPOrder(srcSysCode,destSysCode,dictCode,attrValue,isSpeRule,transColumName);
  109. //如果t中的目标属性的值为null或者"",则不需要修改其值
  110. if (attrValue != null && !"".equals(attrValue)){
  111. if (destCodeVal != null && !"".equals(destCodeVal)) {
  112. //如果从目标系统中查到的字典值非null或者非空字符串,则重新给属性赋值,否则把属性放到listNotIncludeAttr
  113. field.set(t, destCodeVal);
  114. } else {
  115. listNotIncludeAttr.add(attrShortName);
  116. logger.info("在目标系统" + destSysCode + "中,没有找到源系统" + srcSysCode + "中属性是" + attrShortName + "对应的字典" + dictCode + ",找到的字典值是:" + destCodeVal);
  117. }
  118. }
  119. }else if (field.isAnnotationPresent(DictClass.class)){
  120. if (isList(field)){
  121. //对List/ArrayList类型的属性遍历
  122. try {
  123. PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
  124. Method method = descriptor.getReadMethod();
  125. List list = (List) method.invoke(t);
  126. if (list != null && list.size() > 0) {
  127. list.stream().forEach(p -> {
  128. // 递归
  129. ergodicObject(srcSysCode, destSysCode, p, listNotIncludeAttr);
  130. });
  131. }
  132. } catch (IntrospectionException e) {
  133. logger.info(e.getMessage());
  134. } catch (InvocationTargetException e) {
  135. logger.info(e.getMessage());
  136. }
  137. }else if(isMap(field)){
  138. //对Map/HashMap类型的属性遍历
  139. try {
  140. PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
  141. Method method = descriptor.getReadMethod();
  142. Map map = (Map) method.invoke(t);
  143. if (map != null && map.size() > 0) {
  144. for (Object obj : map.values()) {
  145. // 递归
  146. ergodicObject(srcSysCode, destSysCode, obj, listNotIncludeAttr);
  147. }
  148. }
  149. } catch (IntrospectionException e) {
  150. logger.info(e.getMessage());
  151. } catch (InvocationTargetException e) {
  152. logger.info(e.getMessage());
  153. }
  154. }else if (field.getType().isArray()) {
  155. //对数组类型的属性遍历
  156. field.setAccessible(true);
  157. Object[] objArr = (Object[]) field.get(t);
  158. if (objArr != null && objArr.length > 0) {
  159. for (Object arr : objArr) {
  160. //递归
  161. ergodicObject(srcSysCode, destSysCode, arr, listNotIncludeAttr);
  162. }
  163. }
  164. }else {
  165. //对自定义类的属性递归
  166. try {
  167. PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
  168. Method method = descriptor.getReadMethod();
  169. Object obj = method.invoke(t);
  170. if (obj != null) {
  171. //递归
  172. ergodicObject(srcSysCode, destSysCode, obj, listNotIncludeAttr);
  173. } else {
  174. continue;
  175. }
  176. } catch (IntrospectionException e) {
  177. logger.info(e.getMessage());
  178. } catch (InvocationTargetException e) {
  179. logger.info(e.getMessage());
  180. }
  181. }
  182. }else {
  183. continue;
  184. }
  185. }
  186. } catch (IllegalAccessException e) {
  187. logger.info(e.getMessage());
  188. }
  189. }
  190. /**
  191. * 判断是否是List或者ArrayList
  192. * @param field
  193. * @return
  194. */
  195. public boolean isList(Field field){
  196. boolean flag = false;
  197. String simpleName = field.getType().getSimpleName();
  198. if ("List".equals(simpleName) || "ArrayList".equals(simpleName)){
  199. flag = true;
  200. }
  201. return flag;
  202. }
  203. /**
  204. * 判断是否是Map或者HashMap
  205. * @param field
  206. * @return
  207. */
  208. public boolean isMap(Field field){
  209. boolean flag = false;
  210. String simpleName = field.getType().getSimpleName();
  211. if ("Map".equals(simpleName) || "HashMap".equals(simpleName)){
  212. flag = true;
  213. }
  214. return flag;
  215. }
  216. }

三、如何使用

复杂对象如下:

  1. package com.lsl.model;
  2. import com.lsl.annotion.DictClass;
  3. import java.util.List;
  4. /**
  5. * @author: lsl
  6. * @date: 2019/2/27
  7. */
  8. public class ParentClass {
  9. private String fatherName;
  10. private int fatherAge;
  11. @DictClass
  12. private List<SubClass> list;
  13. @DictClass
  14. private SubClass subClass;
  15. public String getFatherName() {
  16. return fatherName;
  17. }
  18. public void setFatherName(String fatherName) {
  19. this.fatherName = fatherName;
  20. }
  21. public int getFatherAge() {
  22. return fatherAge;
  23. }
  24. public void setFatherAge(int fatherAge) {
  25. this.fatherAge = fatherAge;
  26. }
  27. public List<SubClass> getList() {
  28. return list;
  29. }
  30. public void setList(List<SubClass> list) {
  31. this.list = list;
  32. }
  33. public SubClass getSubClass() {
  34. return subClass;
  35. }
  36. public void setSubClass(SubClass subClass) {
  37. this.subClass = subClass;
  38. }
  39. }

复杂对象ParentClass包含子对象SubClass

子对象SubClass代码:

  1. package com.lsl.model;
  2. import com.lsl.annotion.DictField;
  3. /**
  4. * @author: lsl
  5. * @date: 2019/2/27
  6. */
  7. public class SubClass {
  8. @DictField(dictCode = "aaa")
  9. private String subName;
  10. private int subAge;
  11. public String getSubName() {
  12. return subName;
  13. }
  14. public void setSubName(String subName) {
  15. this.subName = subName;
  16. }
  17. public int getSubAge() {
  18. return subAge;
  19. }
  20. public void setSubAge(int subAge) {
  21. this.subAge = subAge;
  22. }
  23. }

简单测试,和二、核心代码部分略有区别

  1. package com.lsl;
  2. import com.alibaba.fastjson.JSON;
  3. import com.lsl.annotion.DictClass;
  4. import com.lsl.annotion.DictField;
  5. import com.lsl.model.ParentClass;
  6. import com.lsl.model.SubClass;
  7. import com.lsl.service.MyService;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.stereotype.Controller;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.transaction.annotation.Transactional;
  12. import org.springframework.web.bind.annotation.RequestMapping;
  13. import java.beans.IntrospectionException;
  14. import java.beans.PropertyDescriptor;
  15. import java.lang.reflect.Field;
  16. import java.lang.reflect.InvocationTargetException;
  17. import java.lang.reflect.Method;
  18. import java.sql.Timestamp;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import java.util.Map;
  22. /**
  23. * @author: lsl
  24. * @date: 2019/2/15
  25. */
  26. @Controller
  27. @RequestMapping("/lsl")
  28. public class MyTest {
  29. public static void main(String [] args){
  30. SubClass sub1 = new SubClass();
  31. sub1.setSubAge(21);
  32. sub1.setSubName("aaa");
  33. SubClass sub2 = new SubClass();
  34. sub2.setSubName("bbb");
  35. sub2.setSubAge(20);
  36. SubClass sub3 = new SubClass();
  37. sub3.setSubName("ccc");
  38. sub3.setSubAge(22);
  39. List<SubClass> list = new ArrayList();
  40. list.add(sub1);
  41. list.add(sub2);
  42. ParentClass parent = new ParentClass();
  43. parent.setFatherAge(18);
  44. parent.setFatherName("aaa");
  45. parent.setSubClass(sub3);
  46. parent.setList(list);
  47. ergodicObject(parent);
  48. }
  49. public static <T> void ergodicObject(T t){
  50. Class clazz = t.getClass();
  51. Field[] fields = clazz.getDeclaredFields();
  52. try {
  53. for (Field field : fields) {
  54. field.setAccessible(true);
  55. // String attrType = field.getType().getSimpleName();//属性类型
  56. String attrShortName = field.getName();//属性名
  57. if (field.isAnnotationPresent(DictField.class)){
  58. String attrValue = (String)field.get(t);//属性值
  59. }else if (field.isAnnotationPresent(DictClass.class)){
  60. if (isList(field)){
  61. //对List/ArrayList类型的属性遍历
  62. try {
  63. PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
  64. Method method = descriptor.getReadMethod();
  65. List list = (List) method.invoke(t);
  66. if (list != null && list.size() > 0) {
  67. for(Object obj : list){
  68. ergodicObject(obj);
  69. }
  70. }
  71. } catch (IntrospectionException e) {
  72. // logger.info(e.getMessage());
  73. } catch (InvocationTargetException e) {
  74. // logger.info(e.getMessage());
  75. }
  76. }else if(isMap(field)){
  77. //对Map/HashMap类型的属性遍历
  78. try {
  79. PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
  80. Method method = descriptor.getReadMethod();
  81. Map map = (Map) method.invoke(t);
  82. if (map != null && map.size() > 0) {
  83. for (Object obj : map.values()) {
  84. // 递归
  85. ergodicObject( obj);
  86. }
  87. }
  88. } catch (IntrospectionException e) {
  89. // logger.info(e.getMessage());
  90. } catch (InvocationTargetException e) {
  91. // logger.info(e.getMessage());
  92. }
  93. }else if (field.getType().isArray()) {
  94. //对数组类型的属性遍历
  95. field.setAccessible(true);
  96. Object[] objArr = (Object[]) field.get(t);
  97. if (objArr != null && objArr.length > 0) {
  98. for (Object arr : objArr) {
  99. //递归
  100. ergodicObject( arr);
  101. }
  102. }
  103. }else {
  104. //对自定义类的属性递归
  105. try {
  106. PropertyDescriptor descriptor = new PropertyDescriptor(attrShortName, clazz);
  107. Method method = descriptor.getReadMethod();
  108. Object obj = method.invoke(t);
  109. if (obj != null) {
  110. //递归
  111. ergodicObject( obj);
  112. } else {
  113. continue;
  114. }
  115. } catch (IntrospectionException e) {
  116. // logger.info(e.getMessage());
  117. } catch (InvocationTargetException e) {
  118. // logger.info(e.getMessage());
  119. }
  120. }
  121. }else {
  122. continue;
  123. }
  124. }
  125. } catch (IllegalAccessException e) {
  126. e.printStackTrace();
  127. }
  128. }
  129. public static boolean isList(Field field){
  130. boolean flag = false;
  131. String simpleName = field.getType().getSimpleName();
  132. if ("List".equals(simpleName) || "ArrayList".equals(simpleName)){
  133. flag = true;
  134. }
  135. return flag;
  136. }
  137. /**
  138. * 判断是否是Map或者HashMap
  139. * @param field
  140. * @return
  141. */
  142. public static boolean isMap(Field field){
  143. boolean flag = false;
  144. String simpleName = field.getType().getSimpleName();
  145. if ("Map".equals(simpleName) || "HashMap".equals(simpleName)){
  146. flag = true;
  147. }
  148. return flag;
  149. }
  150. public static String countMethod(){
  151. StringBuffer a= new StringBuffer("11");
  152. try {
  153. try {
  154. a = a.append("22");
  155. int m=1/0;
  156. } catch (Exception e) {
  157. System.err.println("内层catch执行");
  158. throw e;
  159. }
  160. // return a.toString();
  161. } catch (Exception e) {
  162. // return a.toString();
  163. System.err.println("外层catch执行");
  164. throw e;
  165. } finally {
  166. a = a.append("33");
  167. System.err.println("finally==a==" + a);
  168. }
  169. return a.toString();
  170. }
  171. @Autowired
  172. MyService service;
  173. // @Transactional
  174. @RequestMapping("/lock")
  175. public void tranactionalTest(){
  176. BizLock lock = new BizLock();
  177. BizLock bizLock = new BizLock();
  178. bizLock.setBizId("11223344");
  179. bizLock.setBizNo("aabbccdd");
  180. bizLock.setBizType("MTNNO");
  181. long nowTime = System.currentTimeMillis();
  182. bizLock.setCreateTime(new Timestamp(nowTime));
  183. bizLock.setPassTime(new Timestamp(nowTime));
  184. int count = service.addLock(bizLock);
  185. if (count==1){
  186. System.err.println("加锁成功" + count);
  187. }else {
  188. System.err.println("加锁失败" + count);
  189. }
  190. // int aa = 1/0;
  191. // try {
  192. // System.err.println("Thread名字"+ Thread.currentThread().getName() + ",开始休眠8888888");
  193. // Thread.sleep(50000L);
  194. // } catch (InterruptedException e) {
  195. //
  196. // }
  197. int num=12;
  198. System.err.println("endendendend");
  199. // return count;
  200. }
  201. @RequestMapping("/lock2")
  202. public void tranactionalTes2t(){
  203. BizLock lock = new BizLock();
  204. BizLock bizLock = new BizLock();
  205. bizLock.setBizId("11223344");
  206. bizLock.setBizNo("aabbccdd");
  207. bizLock.setBizType("MTNNO");
  208. long nowTime = System.currentTimeMillis();
  209. bizLock.setCreateTime(new Timestamp(nowTime));
  210. bizLock.setPassTime(new Timestamp(nowTime));
  211. int count = service.addLock(bizLock);
  212. if (count==1){
  213. System.err.println("加锁成功" + count);
  214. }else {
  215. System.err.println("加锁失败" + count);
  216. }
  217. //
  218. System.err.println("endendendend");
  219. }
  220. }

发表评论

表情:
评论列表 (有 0 条评论,586人围观)

还没有评论,来说两句吧...

相关阅读