系统变的复杂,系统的层次划分越来越细,边界也越来越明确。 然后每一层之间一般都有自己要处理的领域对象,统称为pojo一般在model或者domain包下(类的后缀不能为pojo)。
常见的一些模型类型:
在复杂一点的业务中,业务建模是非常有必要的,一定要抽象出业务上常用的领域模型,统一技术和非技术同学的语言。
建完模型之后,在技术的系统中,为了方便维护代码,分离关注点,也会进行再次分层,让每一层解决特定的问题。模型的分层是随着系统的分层而来的;试想所有的模型属性在一个对象中,这个对象你看的懂吗?
举个实际的案例:
简单说就是当我们的系统要输出能力到外部系统的时候,不同系统要的数据不一样,数据安全要求我们不能透出这么多的数据,一定要做一层处理。 另外给另外一个系统关注的数据,而不是一股脑的全部都给对方,对方处理起来也方便。
以上从技术分类的角度来看:
个人觉得,如果说对象比较简单的时候,使用BeanCopier就可以了,因为spring的aop依赖cglib,默认情况下就已经引入了对应的包了,不需要额外的依赖直接就可以用。
如果很复杂的模型之间的转换,并且对性能有更极致的要求,考虑使用下MapStruct。
UserDO
@Data public class UserDO { private Long id; private String name; private Integer gender; private String password; private Date gmtCreate; private Date gmtModified; }
UserDTO
@Data public class UserDTO { private Long id; private String name; private Integer gender; }
BeanCopier beanCopier = BeanCopier.create(UserDO.class, UserDTO.class, false); bean.copy即可;
private static void simpleBeanCopy() { BeanCopier beanCopier = BeanCopier.create(UserDO.class, UserDTO.class, false); UserDO userDO = new UserDO(); userDO.setId(1L); userDO.setName("aihe"); userDO.setGmtCreate(new Date()); userDO.setGender(0); userDO.setPassword("xxxxxx"); UserDTO userDTO = new UserDTO(); beanCopier.copy(userDO, userDTO,null); Assert.assertEquals("名称未成功拷贝",userDTO.getName(),"aihe"); Assert.assertEquals("Id未成功拷贝", 1L, (long)userDTO.getId()); Assert.assertEquals("性别未成功拷贝", Integer.valueOf(0),userDTO.getGender()); }
package me.aihe.daka; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import net.sf.cglib.beans.BeanCopier; /** * @author : aihe * @date : 2022/9/12 9:21 AM * 使用场景: * 功能描述: */ public class BeanCopyUtils { /** * beanCopier缓存 * 由sourceClass和targetClass可以确定一个唯一的BeanCoper,因此使用二级Map; */ private static Map<Class<?>, Map<Class<?>, BeanCopier>> beanCopierMap = new ConcurrentHashMap<>(); /** * 直接指定Bean对象进行拷贝 * @param sourceBean * @param targetBean * @param <S> * @param <T> */ public static <S,T> void copy(S sourceBean,T targetBean){ @SuppressWarnings("unchecked") Class<S> sourceClass = (Class<S>) sourceBean.getClass(); @SuppressWarnings("unchecked") Class<T> targetClass = (Class<T>) targetBean.getClass(); BeanCopier beanCopier = getBeanCopier(sourceClass,targetClass); beanCopier.copy(sourceBean,targetBean,null); } /** * 转换方法 * @param sourceBean 原对象 * @param targetClass 目标类 * @param <S> * @param <T> * @return */ public static <S,T> T convert(S sourceBean,Class<T> targetClass){ try { assert sourceBean!=null; T targetBean = targetClass.newInstance(); copy(sourceBean,targetBean); return targetBean; } catch (Exception e) { throw new RuntimeException(e); } } private static <S,T> BeanCopier getBeanCopier(Class<S> sourceClass, Class<T> targetClass ){ Map<Class<?>,BeanCopier> map = beanCopierMap.get(sourceClass); if(map == null || map.isEmpty()){ BeanCopier newBeanCopier = BeanCopier.create(sourceClass, targetClass, false); Map<Class<?>,BeanCopier> newMap = new ConcurrentHashMap<>(); newMap.put(targetClass,newBeanCopier); beanCopierMap.put(sourceClass,newMap); return newBeanCopier; } BeanCopier beanCopier = map.get(targetClass); if(beanCopier == null){ BeanCopier newBeanCopier = BeanCopier.create(sourceClass, targetClass, false); map.put(targetClass,newBeanCopier); return newBeanCopier; } return beanCopier; } }
同上:
UserDO userDO = new UserDO(); userDO.setId(1L); userDO.setName("aihe"); userDO.setGmtCreate(new Date()); userDO.setGender(0); userDO.setPassword("xxxxxx"); UserDTO userDTO = new UserDTO(); BeanCopyUtils.copy(userDO, userDTO); Assert.assertEquals("名称未成功拷贝",userDTO.getName(),"aihe"); Assert.assertEquals("Id未成功拷贝", 1L, (long)userDTO.getId()); Assert.assertEquals("性别未成功拷贝", Integer.valueOf(0),userDTO.getGender());
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <org.mapstruct.version>1.5.2.Final</org.mapstruct.version> <org.projectlombok.version>1.18.20</org.projectlombok.version> </properties> <dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> <!-- IntelliJ does not pick up the processor if it is not in the dependencies. There is already an open issue for IntelliJ see https://youtrack.jetbrains.com/issue/IDEA-150621 --> <scope>provided</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${org.projectlombok.version}</version> <scope>provided</scope> </dependency> </dependencies>
定义Mapper
@Mapper public interface UserDTOMapper { UserDTOMapper MAPPER = Mappers.getMapper( UserDTOMapper.class ); //@Mapping( source = "test", target = "testing" ) //@Mapping( source = "test1", target = "testing2" ) UserDTO toTarget( UserDO s ); }
使用:
public static void main( String[] args ) { //simpleDemo(); UserDO userDO = new UserDO(); userDO.setId(1L); userDO.setName("aihe"); userDO.setGmtCreate(new Date()); userDO.setGender(0); userDO.setPassword("xxxxxx"); UserDTO userDTO = UserDTOMapper.MAPPER.toTarget(userDO); Assert.assertEquals("名称未成功拷贝",userDTO.getName(),"aihe"); Assert.assertEquals("Id未成功拷贝", 1L, (long)userDTO.getId()); Assert.assertEquals("性别未成功拷贝", Integer.valueOf(0),userDTO.getGender()); }
@Mapping(target = "userNick1", source = "userNick") @Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd") @Mapping(target = "age", source = "age", numberFormat = "#0.00") @Mapping(target = "id", ignore = true) @Mapping(target = "userVerified", defaultValue = "defaultValue-2") UserDTO toTarget( UserDO s );
import java.util.Date; import com.alibaba.fastjson.JSON; import org.junit.Before; import org.junit.Test; /** * @author : aihe aihe.ah@alibaba-inc.com * @date : 2022/9/12 9:47 AM * 使用场景: * 功能描述: */ public class BenchDemoTest{ /** * 转化对象 */ private UserDO userDO; /** * 转化次数 */ private final static int count = 1000000; @Before public void before() { userDO = new UserDO(); userDO.setId(1L); userDO.setName("aihe"); userDO.setGmtCreate(new Date()); userDO.setGender(0); userDO.setPassword("xxxxxx"); } @Test public void mapstruct() { long startTime = System.currentTimeMillis(); for (int i = 1; i <=count; i++) { UserDTO userDTO = UserDTOMapper.MAPPER.toTarget(userDO); } System.out.println("mapstruct time" + (System.currentTimeMillis() - startTime)); } @Test public void beanCopier() { long startTime = System.currentTimeMillis(); for (int i = 1; i <= count; i++) { UserDTO targetBean = new UserDTO(); BeanCopyUtils.copy(userDO, targetBean); } System.out.println("beanCopier time" + (System.currentTimeMillis() - startTime)); } @Test public void springBeanUtils(){ long startTime = System.currentTimeMillis(); for (int i = 1; i <=count; i++) { UserDTO userDTO = new UserDTO(); org.springframework.beans.BeanUtils.copyProperties(userDO, userDTO); } System.out.println("springBeanUtils time" + (System.currentTimeMillis() - startTime)); } @Test public void fastjson() { long startTime = System.currentTimeMillis(); for (int i = 1; i <= count; i++) { JSON.parseObject(JSON.toJSONString(userDO), UserDTO.class); } System.out.println("fastjson time" + (System.currentTimeMillis() - startTime)); } }
总结下本文的内容: