• 分享公司Entity与DTO之间数据拷贝的方法


    主题

      最早以前自学java web的时候,数据库查询出来一个Entity对象(CMP对象).就直接传给前台展示了.并没有用到DTO对象,开始并没有觉得有什么不好...后来发现还是需要一些DTO对象来专门用来传值与前台展示用的.因为直接使用Entity对象有几个地方会比较麻烦:

    1.Entity对象的成员域和数据库字段是对应的(比如使用hibernate).所以不能额外向里面增加字段.但是有时候前台就是需要这个字段.反之,前台要向后台传一些值,entity也没办法接受,前台Form表单不可能和数据库公用同一套对象的.

    2.有时候完成1个业务需要N个entity.一个一个传给前台很麻烦.这个不是最关键的,最关键的是如果你的service第一次需求定下来的时候只需要1个entity对象做为参数,后来需求变更了,需要用到另外一个entity,这个时候如果修改service的方法签名,增加一个入参,那所有用到这个service的地方都需要修改.而且其他地方不一定有那个业务相关的entity.而方法参数为单独一个DTO的时候就没有这个问题,需要什么其他属性,直接在DTO增加成员域即可.

    3.entity可能是由框架控制生命周期的,比如hibernate,如果他的某个属性是懒加载的,那万一不在session中调用的话会抛出异常,而DTO对象很干净,并不会有什么问题.你可以自己控制DTO,喜欢就存在缓存里,不喜欢也没关系.同时entity对象如果属性变化的话会有是否需要同步更新数据库的问题,而DTO与数据库并没有什么卵关系.

    对象拷贝

    所以DTO还是需要的.这样的话就需要entity与dto之间进行数据库的拷贝. 最简单的方法当然是自己调用setget方法..但是显然这样比较麻烦.....因为成员域多的话一个一个set起来很累....

    有不少框架都支持对象间属性的拷贝.公司的方法是采用CGLIB的BeanCopier去copy对象,并且在外面稍微包装了一层.

      1 @SuppressWarnings("rawtypes")
      2 public final class ConverterUtil {
      3 
      4     /**
      5      * The Constant LOGGER.
      6      */
      7     private static final Logger LOGGER = LoggerFactory.getLogger(ConverterUtil.class);
      8 
      9     /**
     10      * The Constant CACHED_COPIER_MAP.
     11      */
     12     private static final Map<String, BeanCopier> CACHED_COPIER_MAP = new ConcurrentHashMap<String, BeanCopier>();
     13 
     14     /**
     15      * The Constant CACHED_CUSTOM_CONVERTER_MAP.
     16      */
     17     private static final Map<String, ObjectConverter> CACHED_CUSTOM_CONVERTER_MAP = new ConcurrentHashMap<String, ObjectConverter>();
     18 
     19     /**
     20      * Instantiates a new converter util.
     21      */
     22     private ConverterUtil() {
     23     }
     24 
     25     /**
     26      * Convert list.
     27      * 
     28      * @param <T>
     29      *            the generic type
     30      * @param <F>
     31      *            the generic type
     32      * @param source
     33      *            the source
     34      * @param target
     35      *            the target
     36      * @param sourceList
     37      *            the source list
     38      * @return the list
     39      */
     40     public static <T, F> List<F> convertList(Class<T> source, Class<F> target, List<T> sourceList) {
     41         return convertList(source, target, sourceList, null, null);
     42     }
     43 
     44     /**
     45      * Convert list.
     46      * 
     47      * @param <T>
     48      *            the generic type
     49      * @param <F>
     50      *            the generic type
     51      * @param source
     52      *            the source
     53      * @param target
     54      *            the target
     55      * @param sourceList
     56      *            the source list
     57      * @param converter
     58      *            the converter
     59      * @param customConverterClass
     60      *            the custom converter class
     61      * @return the list
     62      */
     63     public static <T, F> List<F> convertList(Class<T> source, Class<F> target, List<T> sourceList, Converter converter,// NOSONAR
     64             Class<? extends ObjectConverter> customConverterClass) {
     65         if (CollectionUtils.isNotEmpty(sourceList)) {
     66             @SuppressWarnings("unchecked")
     67             List<F> targetList = new ArrayList();
     68             for (T t : sourceList) {
     69                 try {
     70                     F f = target.newInstance();
     71                     targetList.add(convert(t, f, converter, customConverterClass));
     72                 } catch (Exception e) {
     73                     LOGGER.error("When copy instance" + t, e);
     74                 }
     75             }
     76             return targetList;
     77         } else {
     78             return null;// NOSONAR
     79         }
     80 
     81     }
     82 
     83     /**
     84      * Convert.
     85      * 
     86      * @param <T>
     87      *            the generic type
     88      * @param <F>
     89      *            the generic type
     90      * @param source
     91      *            the source
     92      * @param target
     93      *            the target
     94      * @return the f
     95      */
     96     public static <T, F> F convert(T source, F target) {
     97         return convert(source, target, null, null);
     98     }
     99 
    100     /**
    101      * Convert.
    102      * 
    103      * @param <T>
    104      *            the generic type
    105      * @param <F>
    106      *            the generic type
    107      * @param source
    108      *            the source
    109      * @param target
    110      *            the target
    111      * @param converter
    112      *            the converter
    113      * @param customConverterClass
    114      *            the custom converter class
    115      * @return the f
    116      */
    117     public static <T, F> F convert(T source, F target, Converter converter,
    118             Class<? extends ObjectConverter> customConverterClass) {
    119         if (source == null || target == null) {
    120             return null; // NOSONAR
    121         }
    122         copy(source, target, converter, customConverterClass);
    123         return target;
    124     }
    125 
    126     /**
    127      * Private methods.
    128      * 
    129      * @param <T>
    130      *            the generic type
    131      * @param <F>
    132      *            the generic type
    133      * @param source
    134      *            the source
    135      * @param target
    136      *            the target
    137      * @param converter
    138      *            the converter
    139      * @param customConverterClass
    140      *            the custom converter class
    141      */
    142 
    143     @SuppressWarnings("unchecked")
    144     private static <T, F> void copy(T source, F target, Converter converter,
    145             Class<? extends ObjectConverter> customConverterClass) {
    146         BeanCopier beanCopier = getBeanCopierInstance(source, target.getClass(), converter);
    147         beanCopier.copy(source, target, converter);
    148         ObjectConverter customConverter = getCustomConverterInstance(customConverterClass);
    149         if (customConverter != null) {
    150             if (target.getClass().getName().endsWith("CMP")) {
    151                 customConverter.convertFromDto(source, target);
    152             } else if (target.getClass().getName().endsWith("DTO")) {
    153                 customConverter.convertToDto(source, target);
    154             }
    155         }
    156     }
    157 
    158     /**
    159      * Gets the bean copier instance.
    160      * 
    161      * @param <T>
    162      *            the generic type
    163      * @param <F>
    164      *            the generic type
    165      * @param source
    166      *            the source
    167      * @param targetClass
    168      *            the target class
    169      * @param converter
    170      *            the converter
    171      * @return the bean copier instance
    172      */
    173     private static <T, F> BeanCopier getBeanCopierInstance(T source, Class<F> targetClass, Converter converter) {
    174         String key = source.getClass().getName() + "#" + targetClass.getName();
    175         BeanCopier beanCopier = CACHED_COPIER_MAP.get(key);
    176         if (beanCopier == null) {
    177             synchronized (CACHED_COPIER_MAP) {
    178                 beanCopier = CACHED_COPIER_MAP.get(key);
    179                 if (beanCopier == null) {
    180                     beanCopier = TypeAwareBeanCopier.instantiate(source.getClass(), targetClass, converter != null);
    181                     CACHED_COPIER_MAP.put(key, beanCopier);
    182                 }
    183             }
    184         }
    185         return beanCopier;
    186     }
    187 
    188     /**
    189      * Gets the custom converter instance.
    190      * 
    191      * @param <T>
    192      *            the generic type
    193      * @param <F>
    194      *            the generic type
    195      * @param customConverterClass
    196      *            the custom converter class
    197      * @return the custom converter instance
    198      */
    199     private static <T, F> ObjectConverter getCustomConverterInstance(
    200             Class<? extends ObjectConverter> customConverterClass) {
    201         if (customConverterClass == null) {
    202             return null;// NOSONAR
    203         }
    204         String key = customConverterClass.getName();
    205         ObjectConverter converter = CACHED_CUSTOM_CONVERTER_MAP.get(key);
    206         if (converter == null) {
    207             synchronized (CACHED_CUSTOM_CONVERTER_MAP) {
    208                 try {
    209                     converter = (ObjectConverter) SpringContextUtil.getBean(customConverterClass);
    210                 } catch (BeansException e) {// NOSONAR
    211                     LOGGER.info(customConverterClass.getName() + " is not a component, need new instance.");// NOSONAR
    212                 }
    213                 if (converter == null) {
    214                     try {
    215                         converter = customConverterClass.newInstance();
    216                         CACHED_CUSTOM_CONVERTER_MAP.put(key, converter);
    217                     } catch (InstantiationException e) {
    218                         LOGGER.info(e.getMessage(), e);
    219                         return null;
    220                     } catch (IllegalAccessException e) {
    221                         LOGGER.info(e.getMessage(), e);
    222                         return null;
    223                     }
    224                 }
    225             }
    226         }
    227         return converter;
    228     }
    229 
    230 }

    完整的代码就这么多...

    convert一个list,其实就是convert了N个普通对象.

    convert 1个对象,其实就是new了一个相同类型的对象,然后copy成员域.

    所以核心还是copy方法

     1     private static <T, F> void copy(T source, F target, Converter converter,
     2             Class<? extends ObjectConverter> customConverterClass) {
     3         BeanCopier beanCopier = getBeanCopierInstance(source, target.getClass(), converter);
     4         beanCopier.copy(source, target, converter);
     5         ObjectConverter customConverter = getCustomConverterInstance(customConverterClass);
     6         if (customConverter != null) {
     7             if (target.getClass().getName().endsWith("CMP")) {
     8                 customConverter.convertFromDto(source, target);
     9             } else if (target.getClass().getName().endsWith("DTO")) {
    10                 customConverter.convertToDto(source, target);
    11             }
    12         }
    13     }

    copy方法就2个步骤,第一个步骤是调用CGLIB的BeanCopier的copy方法去copy对象,然后再调用自己写的ObjectConverter接口的实现类去做额外的copy..ObjectConverter接口有2个方法,一个是convertFromDto,就是DTO -> Entity的拷贝,另外一个是convertToDto就是Entity -> Dto或者Dto -> Dto的拷贝.

    小小的总结

    公司的对象间拷贝方法还是比较简单的,同时也蛮好用的,毕竟大多数时候就是收集下前台表单的数据,然后Copy到要保存的entity中,或者数据库查出来Entity,拷贝到前台去展示.

    一般String呀,int呀这些都能很方便的拷贝,不过如果成员是List呀,引用对象呀什么的....那就只能自己去实现ObjectConverter接口做额外copy 或者为每个引用对象再掉一次copy方法.

    这点是算个小缺陷吧....不过大多数情况下这个简易的转化工具还是超级好用的.

  • 相关阅读:
    容灾、备份、存储
    春节前后学习实践的技术领域
    C#高级编程技术复习一
    利用投影制作多边框
    利用循环调用同一个函数
    IOS NSURLRequest(http请求)讲解 ---------赎罪之路
    IOS SQLite基本操作
    数据库三凡式通俗解析(转载)
    数据库设计原则(转载)
    MusicRadio ----------项目分享
  • 原文地址:https://www.cnblogs.com/abcwt112/p/6073103.html
Copyright © 2020-2023  润新知