主题

  最早以前自学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对象,并且在外面稍微包装了一层.

 @SuppressWarnings("rawtypes")
public final class ConverterUtil { /**
* The Constant LOGGER.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(ConverterUtil.class); /**
* The Constant CACHED_COPIER_MAP.
*/
private static final Map<String, BeanCopier> CACHED_COPIER_MAP = new ConcurrentHashMap<String, BeanCopier>(); /**
* The Constant CACHED_CUSTOM_CONVERTER_MAP.
*/
private static final Map<String, ObjectConverter> CACHED_CUSTOM_CONVERTER_MAP = new ConcurrentHashMap<String, ObjectConverter>(); /**
* Instantiates a new converter util.
*/
private ConverterUtil() {
} /**
* Convert list.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param source
* the source
* @param target
* the target
* @param sourceList
* the source list
* @return the list
*/
public static <T, F> List<F> convertList(Class<T> source, Class<F> target, List<T> sourceList) {
return convertList(source, target, sourceList, null, null);
} /**
* Convert list.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param source
* the source
* @param target
* the target
* @param sourceList
* the source list
* @param converter
* the converter
* @param customConverterClass
* the custom converter class
* @return the list
*/
public static <T, F> List<F> convertList(Class<T> source, Class<F> target, List<T> sourceList, Converter converter,// NOSONAR
Class<? extends ObjectConverter> customConverterClass) {
if (CollectionUtils.isNotEmpty(sourceList)) {
@SuppressWarnings("unchecked")
List<F> targetList = new ArrayList();
for (T t : sourceList) {
try {
F f = target.newInstance();
targetList.add(convert(t, f, converter, customConverterClass));
} catch (Exception e) {
LOGGER.error("When copy instance" + t, e);
}
}
return targetList;
} else {
return null;// NOSONAR
} } /**
* Convert.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param source
* the source
* @param target
* the target
* @return the f
*/
public static <T, F> F convert(T source, F target) {
return convert(source, target, null, null);
} /**
* Convert.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param source
* the source
* @param target
* the target
* @param converter
* the converter
* @param customConverterClass
* the custom converter class
* @return the f
*/
public static <T, F> F convert(T source, F target, Converter converter,
Class<? extends ObjectConverter> customConverterClass) {
if (source == null || target == null) {
return null; // NOSONAR
}
copy(source, target, converter, customConverterClass);
return target;
} /**
* Private methods.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param source
* the source
* @param target
* the target
* @param converter
* the converter
* @param customConverterClass
* the custom converter class
*/ @SuppressWarnings("unchecked")
private static <T, F> void copy(T source, F target, Converter converter,
Class<? extends ObjectConverter> customConverterClass) {
BeanCopier beanCopier = getBeanCopierInstance(source, target.getClass(), converter);
beanCopier.copy(source, target, converter);
ObjectConverter customConverter = getCustomConverterInstance(customConverterClass);
if (customConverter != null) {
if (target.getClass().getName().endsWith("CMP")) {
customConverter.convertFromDto(source, target);
} else if (target.getClass().getName().endsWith("DTO")) {
customConverter.convertToDto(source, target);
}
}
} /**
* Gets the bean copier instance.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param source
* the source
* @param targetClass
* the target class
* @param converter
* the converter
* @return the bean copier instance
*/
private static <T, F> BeanCopier getBeanCopierInstance(T source, Class<F> targetClass, Converter converter) {
String key = source.getClass().getName() + "#" + targetClass.getName();
BeanCopier beanCopier = CACHED_COPIER_MAP.get(key);
if (beanCopier == null) {
synchronized (CACHED_COPIER_MAP) {
beanCopier = CACHED_COPIER_MAP.get(key);
if (beanCopier == null) {
beanCopier = TypeAwareBeanCopier.instantiate(source.getClass(), targetClass, converter != null);
CACHED_COPIER_MAP.put(key, beanCopier);
}
}
}
return beanCopier;
} /**
* Gets the custom converter instance.
*
* @param <T>
* the generic type
* @param <F>
* the generic type
* @param customConverterClass
* the custom converter class
* @return the custom converter instance
*/
private static <T, F> ObjectConverter getCustomConverterInstance(
Class<? extends ObjectConverter> customConverterClass) {
if (customConverterClass == null) {
return null;// NOSONAR
}
String key = customConverterClass.getName();
ObjectConverter converter = CACHED_CUSTOM_CONVERTER_MAP.get(key);
if (converter == null) {
synchronized (CACHED_CUSTOM_CONVERTER_MAP) {
try {
converter = (ObjectConverter) SpringContextUtil.getBean(customConverterClass);
} catch (BeansException e) {// NOSONAR
LOGGER.info(customConverterClass.getName() + " is not a component, need new instance.");// NOSONAR
}
if (converter == null) {
try {
converter = customConverterClass.newInstance();
CACHED_CUSTOM_CONVERTER_MAP.put(key, converter);
} catch (InstantiationException e) {
LOGGER.info(e.getMessage(), e);
return null;
} catch (IllegalAccessException e) {
LOGGER.info(e.getMessage(), e);
return null;
}
}
}
}
return converter;
} }

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

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

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

所以核心还是copy方法

     private static <T, F> void copy(T source, F target, Converter converter,
Class<? extends ObjectConverter> customConverterClass) {
BeanCopier beanCopier = getBeanCopierInstance(source, target.getClass(), converter);
beanCopier.copy(source, target, converter);
ObjectConverter customConverter = getCustomConverterInstance(customConverterClass);
if (customConverter != null) {
if (target.getClass().getName().endsWith("CMP")) {
customConverter.convertFromDto(source, target);
} else if (target.getClass().getName().endsWith("DTO")) {
customConverter.convertToDto(source, target);
}
}
}

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方法.

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

分享公司Entity与DTO之间数据拷贝的方法的更多相关文章

  1. DistCp 集群之间数据拷贝工具

    DistCp(分布式拷贝)是用于大规模集群内部和集群之间拷贝的工具.可以将数据拷贝到另个一集群,也可以将另一个集群的数据拷贝到本集群.

  2. JAVA中JavaBean对象之间属性拷贝的方法

    JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,对于这种情况,可以采用以下几个简便方法处理. 下面对这 ...

  3. 何时使用Entity或DTO

    关注公众号: 锅外的大佬 每日推送国外优秀的技术翻译文章,励志帮助国内的开发者更好地成长! JPA和Hibernate允许你在JPQL和Criteria查询中使用DTO和Entity作为映射.当我在我 ...

  4. 解析activity之间数据传递方法的详解

    转自:http://www.jb51.net/article/37227.htm 本篇文章是对activity之间数据传递的方法进行了详细的分析介绍,需要的朋友参考下     1  基于消息的通信机制 ...

  5. 软件架构自学笔记----分享“去哪儿 Hadoop 集群 Federation 数据拷贝优化”

    去哪儿 Hadoop 集群 Federation 数据拷贝优化 背景 去哪儿 Hadoop 集群随着去哪儿网的发展一直在优化改进,基本保证了业务数据存储量和计算量爆发式增长下的存储服务质量.然而,随着 ...

  6. MySQL与Oracle之间互相拷贝数据的Java程序

    因为工作需要,先是需要将一个小型的MySQL数据库中的数据拷贝到Oracle中:近期又有需要将一个中型的Oracle数据库拷贝到MySQL中.曾经找过网上各种转换工具,大多收费的,自己写个吧,还一切可 ...

  7. JS之document例题讲解1(两张表之间数据转移、日期时间选择、子菜单下拉、用div做下拉菜单、事件总结)

    作业一:两个列表之间数据从一个列表移动到另一个列表 <div style="width:600px; height:500px; margin-top:20px"> & ...

  8. python之 《进程之间数据交互和进程池》

    1.进程q 进程呢就相当于一个房子,线程就相当于是房子里面在工作的人,那么一个房子的空间对于房子里面的人来说是共享的, 现在是多进程,也就是说有许多房子,很显然这个房子的空间只属于这个房子,不会属于其 ...

  9. DOM的小练习,两个表格之间数据的移动

    本次讲的是两个表格之间数据的移动,左边的表格移动到右边,并且左边表格移动内容消失. <head>   <meta http-equiv="Content-Type" ...

随机推荐

  1. [Erlang 0126] 我们读过的Erlang论文

    我在Erlang Resources 豆瓣小站上发起了一个征集活动 [链接] ,"[征集] 我们读过的Erlang论文",希望大家来参加.发起这样一个活动的目的是因为Erlang相 ...

  2. CSS3:linear-gradient,线性渐变的使用方法

    CSS3 渐变(gradients)可以让你在两个或多个指定的颜色之间显示平稳的过渡. 以前,你必须使用图像来实现这些效果,现在通过使用 CSS3 的渐变(gradients)即可实现.此外,渐变效果 ...

  3. MySQL学习笔记

    数据库 P3306create database [if not exists] db_name [characterset gbk];use database;//跳转数据库show databas ...

  4. IBM Bluemix体验:Containers

    国际版的Bluemix目前有三个region,US South,United Kingdom和Sydney.其中US South是功能最全的,UK其次,Sydney功能最少.Containers服务在 ...

  5. POJ_2386 Lake Counting (dfs 错了一个负号找了一上午)

    来之不易的2017第一发ac http://poj.org/problem?id=2386 Lake Counting Time Limit: 1000MS   Memory Limit: 65536 ...

  6. [LeetCode] Best Time to Buy and Sell Stock with Cooldown 买股票的最佳时间含冷冻期

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  7. Underscore 整体架构浅析

    前言 终于,楼主的「Underscore 源码解读系列」underscore-analysis 即将进入尾声,关注下 timeline 会发现楼主最近加快了解读速度.十一月,多事之秋,最近好多事情搞的 ...

  8. java版简易socket客户端

    android项目需要使用到心跳, 于是编写了一个简易的socket客户端程序 主要功能是给服务端发送心跳包,保持在线状态 没有使用框架,这样避免了需要引入包,直接使用的阻塞Socket通信. 主要逻 ...

  9. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'dd' in 'where clause'

    今天在使用mysql数据库查找数据的时候报错,错误信息如下: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown co ...

  10. JAVA实现带图片的列表——JList

    JList:显示对象列表并且允许用户选择一个或多个项的组件. JList的构造方法: 1.根据数组创建列表: JList(Object[] listData) 构造一个 JList,使其显示指定数组中 ...