您现在的位置是:首页 >学无止境 >关于自动映射在项目中的具体落地(dozer)网站首页学无止境
关于自动映射在项目中的具体落地(dozer)
简介关于自动映射在项目中的具体落地(dozer)
关于自动映射在项目中的具体落地(dozer)
项目开发过程中,经常需要编写model之间的转换,最常见的有:
- 实体转DTO
- DTO转实体
等操作,故为了简化代码的开发工作,需要简化对象属性之间复制的步骤,目前有两种解决方案,一种是定义converter 使用手写或插件生成,对各个属性进行set方法的设置。
IDEA提供GenerateAllSetter插件,可帮助我们快速生成上述代码。
另一中方案是使用自动映射框架进行属性的自动设置,基本有两种方向,一种是基于反射进行的,另一中是进行预编译生成相关代码,当然了 后一种在项目运行中效率是最高的。但是我们下面讲解的具体落地 使用的是基于反射实现的框架 dozer。
具体落地
引入maven
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
创建 SmartMapper接口
定义接口
public interface SmartMapper {
/**
* 创建指定类型的对象
*
* @param source
* @param destinationClass
* @param <T>
* @return
* @throws SmartMapperException
*/
<T> T map(Object source, Class<T> destinationClass) throws SmartMapperException;
/**
* 进行属性的赋值
*
* @param source object to convert from
* @param destination object to convert to
* @throws SmartMapperException mapping failure
*/
void map(Object source, Object destination) throws SmartMapperException;
/**
* 映射集合
* @param source
* @param destinationClass
* @param <T>
* @return
* @throws SmartMapperException
*/
<T> List<T> mapList(List<Object> source,Class<T> destinationClass) throws SmartMapperException;
/**
* 映射集合
* @param source
* @param destination
* @throws SmartMapperException
*/
void map(List<Object> source, List<Object> destination) throws SmartMapperException;
}
创建DozerBeanMapper 的包装器 并实现SmartMapper
public class SmartDozerMapper implements SmartMapper {
private DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();
private DozerBuilder.ConfigurationBuilder config;
/*自定义属性 映射配置 和自定义类型转化器*/
public void addBeanMapping(SmartBeanMapping beanMapping) {
try {
dozerBeanMapper.addMapping(new SmartBeanMappingBuilder() {
@Override
protected void configure() {
TypeMappingBuilder typeMappingBuilder = mapping(beanMapping.getSrcType(), beanMapping.getDestType());
List<SmartFieldMapping> fieldMappingList = beanMapping.getFieldMappings();
for (SmartFieldMapping fieldMapping : fieldMappingList) {
if (fieldMapping.getTypeConverter() == null) {
typeMappingBuilder.fields(fieldMapping.getSrcFieldName(), fieldMapping.getDestFieldName());
} else {
SmartFieldCustomConverter.addFieldTypeConverter(beanMapping.getSrcType(), beanMapping.getDestType(), fieldMapping.getSrcFieldName(), fieldMapping.getDestFieldName(), fieldMapping.getTypeConverter());
String parameter = beanMapping.getSrcType().getName() + "," + beanMapping.getDestType().getName() + "|" + fieldMapping.getSrcFieldName() + "," + fieldMapping.getDestFieldName();
typeMappingBuilder.fields(fieldMapping.getSrcFieldName(), fieldMapping.getDestFieldName(), customConverter(SmartFieldCustomConverter.class, parameter));
}
}
}
});
} catch (Exception e) {
throw new SmartMapperException(e.getMessage(), e);
}
}
/*
全局类型转换器
*/
public void addCustomConterver(SmartTypeConverter converter) {
Pair<Class, Class> typeConverterKey = ResolveTypeUtils.resolveTypeConverterKey(converter.getClass());
SmartCustomConverter.addSmartTypeConverter(converter);
if(config == null) {
dozerBeanMapper.addMapping(new SmartBeanMappingBuilder() {
@Override
protected void configure() {
config = this.getDozerBuilder().configuration();
}
});
config.customConverter(SmartCustomConverter.class).classA(typeConverterKey.getKey()).classB(typeConverterKey.getValue());
}
}
一下功能还是交给dozerBeanMapper去提供
@Override
public <T> T map(Object source, Class<T> destinationClass) throws SmartMapperException {
try {
return dozerBeanMapper.map(source, destinationClass);
}catch (MappingException e) {
throw new SmartMapperException(e.getMessage(),e);
}
}
@Override
public void map(Object source, Object destination) throws SmartMapperException {
try {
dozerBeanMapper.map(source,destination);
}catch (MappingException e) {
throw new SmartMapperException(e.getMessage(),e);
}
}
@Override
public <T> List<T> mapList(List<Object> source, Class<T> destinationClass) throws SmartMapperException {
if(source == null) {
return null;
}
try {
List<T> ret = new ArrayList<>();
for (Object element : source) {
T des = map(element, destinationClass);
ret.add(des);
}
return ret;
}catch (MappingException e) {
throw new SmartMapperException(e.getMessage(),e);
}
}
@Override
public void map(List<Object> source, List<Object> destination) throws SmartMapperException {
if(source == null) {
return;
}
try {
for (int i = 0; i < source.size(); i++) {
map(source.get(i), destination.get(i));
}
}catch (MappingException e) {
throw new SmartMapperException(e.getMessage(),e);
}
}
}
public abstract class SmartBeanMappingBuilder extends BeanMappingBuilder {
//对外暴露config
protected DozerBuilder getDozerBuilder() throws SmartMapperException {
try {
Field dozerBuilder =
this.getClass().getSuperclass().getSuperclass().getDeclaredField("dozerBuilder");
dozerBuilder.setAccessible(true);
return (DozerBuilder) dozerBuilder.get(this);
}catch (Exception e) {
throw new SmartMapperException(e.getMessage(),e);
}
}
}
全局类型转化器的实现
public class SmartCustomConverter implements CustomConverter{
private static Map<Pair<Class,Class>, SmartTypeConverter> smartTypeConverterHashMap = new HashMap<>();
private static Class<?>[] superClassArray = new Class<?>[]{Enumerable.class};
@Override
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
SmartTypeConverter smartTypeConverter = getTypeConverter(destinationClass,sourceClass);
if(smartTypeConverter != null) {
return smartTypeConverter.convert(existingDestinationFieldValue,sourceFieldValue,destinationClass,sourceClass);
}
return existingDestinationFieldValue;
}
public static void addSmartTypeConverter(SmartTypeConverter smartTypeConverter) {
//解析出smartCustom 的源类和目标类
smartTypeConverterHashMap.put(ResolveTypeUtils.resolveTypeConverterKey(smartTypeConverter.getClass()),smartTypeConverter);
}
private SmartTypeConverter getTypeConverter(Class<?> destinationClass, Class<?> sourceClass) {
// 针对Enumerable类型特殊处理下
Class<?> destClass = convertClass(destinationClass);
Class<?> srcClass = convertClass(sourceClass);
SmartTypeConverter typeConverter = smartTypeConverterHashMap.get(new Pair<>(srcClass, destClass));
return typeConverter;
}
private Class<?> convertClass(Class<?> orgiClass) {
Class<?> targetClass = orgiClass;
for (Class<?> each : superClassArray) {
if (each.isAssignableFrom(targetClass)) {
targetClass = each;
break;
}
}
return targetClass;
}
}
自定义字段的转化器实现
public class SmartFieldCustomConverter implements ConfigurableCustomConverter {
private static Map<Pair<Class, Class>, Map<Pair<String, String>, SmartTypeConverter>> fieldTypeConverterMap = new ConcurrentHashMap<>();
private Class baseSrcType;
private Class baseDestType;
private String srcFieldName;
private String destFieldName;
private SmartTypeConverter typeConverter;
public SmartFieldCustomConverter() {
}
public static void addFieldTypeConverter(Class srcType, Class destType, String srcFieldName, String destFieldName, SmartTypeConverter typeConverter) {
Pair<Class, Class> srcDestClassKey = new Pair<>(srcType, destType);
Map<Pair<String, String>, SmartTypeConverter> fieldMap = fieldTypeConverterMap.get(srcDestClassKey);
if (fieldMap == null) {
fieldMap = new ConcurrentHashMap<>();
fieldTypeConverterMap.put(srcDestClassKey, fieldMap);
}
fieldMap.put(new Pair<>(srcFieldName, destFieldName), typeConverter);
}
@Override
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
if (typeConverter == null) {
initTypeConverter();
}
if (typeConverter != null) {
return typeConverter.convert(existingDestinationFieldValue, sourceFieldValue, destinationClass, sourceClass);
}
return existingDestinationFieldValue;
}
private void initTypeConverter() {
Map<Pair<String, String>, SmartTypeConverter> fieldMap = fieldTypeConverterMap.get(new Pair<>(baseSrcType, baseDestType));
if (fieldMap != null) {
typeConverter = fieldMap.get(new Pair<>(srcFieldName, destFieldName));
}
}
@Override
public void setParameter(String parameter) {
// srcClassName,destClassName|srcFieldName,destFieldName
try {
String[] classFieldArray = parameter.split("\|");
String[] classArray = classFieldArray[0].split(",");
String[] fieldArray = classFieldArray[1].split(",");
baseSrcType = Class.forName(classArray[0]);
baseDestType = Class.forName(classArray[1]);
srcFieldName = fieldArray[0];
destFieldName = fieldArray[1];
initTypeConverter();
} catch (Exception e) {
throw new SmartMapperException(e.getMessage(), e);
}
}
}
SmartTypeConverter
public interface SmartTypeConverter<S, D> {
/**
* 转换源对象为目标对象
*
* @param existingDest 目标对象所属类中已经存在的值
* @param src 源对象
* @param destClass 目标类
* @param srcClass 源类
* @return 目标对象
*/
D convert(D existingDest, S src, Class<D> destClass, Class<S> srcClass);
}
自定义映射的封装
SmartBeanMapping
public class SmartBeanMapping<S, D> {
private Class<S> srcType;
private Class<D> destType;
private List<SmartFieldMapping> fieldMappingList = new ArrayList<>();
private SmartBeanMapping(Class<S> srcType, Class<D> destType) {
this.srcType = srcType;
this.destType = destType;
}
public static <S, D> SmartBeanMapping<S, D> create(Class<S> srcType, Class<D> destType) {
return new SmartBeanMapping(srcType, destType);
}
public SmartBeanMapping fields(String srcFieldName, String destFieldName) {
fields(srcFieldName, destFieldName, null);
return this;
}
public SmartBeanMapping fields(String srcFieldName, SmartTypeConverter typeConverter) {
fields(srcFieldName, null, typeConverter);
return this;
}
public SmartBeanMapping fields(String srcFieldName, String destFieldName, SmartTypeConverter typeConverter) {
SmartFieldMapping fieldMapping = SmartFieldMapping.create(srcFieldName, destFieldName, typeConverter);
fieldMappingList.add(fieldMapping);
return this;
}
public List<SmartFieldMapping> getFieldMappings() {
return fieldMappingList;
}
public List<SmartFieldMapping> getFieldMappings(String srcFieldName) {
List<SmartFieldMapping> srcFieldMappingList = new ArrayList<>();
for (SmartFieldMapping each : fieldMappingList) {
if (each.getSrcFieldName().equals(srcFieldName)) {
srcFieldMappingList.add(each);
}
}
return srcFieldMappingList;
}
public SmartFieldMapping getFieldMapping(String srcFieldName) {
List<SmartFieldMapping> fieldMappingList = getFieldMappings(srcFieldName);
if (fieldMappingList != null && fieldMappingList.size() > 0) {
return fieldMappingList.get(0);
}
return null;
}
public Class<S> getSrcType() {
return srcType;
}
public Class<D> getDestType() {
return destType;
}
}
SmartFieldMapping
public class SmartFieldMapping {
private String srcFieldName;
private String destFieldName;
private Class srcFieldType;
private Class destFieldType;
private SmartTypeConverter typeConverter;
private SmartFieldMapping(String srcFieldName, String destFieldName) {
this(srcFieldName, destFieldName, null);
}
private SmartFieldMapping(String srcFieldName, SmartTypeConverter typeConverter) {
this(srcFieldName, null, typeConverter);
}
private SmartFieldMapping(String srcFieldName, String destFieldName, SmartTypeConverter typeConverter) {
this.srcFieldName = srcFieldName;
if (destFieldName == null) {
this.destFieldName = srcFieldName;
} else {
this.destFieldName = destFieldName;
}
if (typeConverter != null) {
this.typeConverter = typeConverter;
Pair<Class, Class> srcDestKey = ResolveTypeUtils.resolveTypeConverterKey(typeConverter.getClass());
this.srcFieldType = srcDestKey.getKey();
this.destFieldType = srcDestKey.getValue();
}
}
public static SmartFieldMapping create(String srcFieldName, String destFieldName) {
return new SmartFieldMapping(srcFieldName, destFieldName);
}
public static SmartFieldMapping create(String srcFieldName, SmartTypeConverter typeConverter) {
return new SmartFieldMapping(srcFieldName, typeConverter);
}
public static SmartFieldMapping create(String srcFieldName, String destFieldName, SmartTypeConverter typeConverter) {
return new SmartFieldMapping(srcFieldName, destFieldName, typeConverter);
}
public String getSrcFieldName() {
return srcFieldName;
}
public String getDestFieldName() {
return destFieldName;
}
public Class getSrcFieldType() {
return srcFieldType;
}
public Class getDestFieldType() {
return destFieldType;
}
public SmartTypeConverter getTypeConverter() {
return typeConverter;
}
}
#### 工具类
public class ResolveTypeUtils {
public static Pair<Class, Class> resolveTypeConverterKey(Class<?> typeConvereterType) {
try {
Type typeConverterInterface = getInterface(typeConvereterType);
Type[] srcDestTypeArray = ((ParameterizedType) typeConverterInterface).getActualTypeArguments();
return new Pair<>(getClass(srcDestTypeArray[0]), getClass(srcDestTypeArray[1]));
} catch (Exception e) {
throw new IllegalStateException("typeConvereterType is invalid:" + e.getMessage(), e);
}
}
private static Class getClass(Type type) {
if (type instanceof Class) {
return (Class) type;
}
return (Class) ((ParameterizedType) type).getRawType();
}
private static Type getInterface(Class<?> typeConvereterType) {
if (typeConvereterType == null || Object.class.equals(typeConvereterType)) {
// 到头了
return null;
}
Type typeConverterInterface = getTypeConverterInterface(typeConvereterType);
if (typeConverterInterface == null) {
return getInterface(typeConvereterType.getSuperclass());
}
return typeConverterInterface;
}
private static Type getTypeConverterInterface(Class<?> typeConvereterType) {
Type[] interfaces = typeConvereterType.getGenericInterfaces();
if (interfaces == null) {
return null;
}
for (Type each : interfaces) {
if (each != null && each instanceof ParameterizedType && SmartTypeConverter.class.equals(((ParameterizedType) each).getRawType())) {
return each;
}
}
return null;
}
}
具体使用
public class EnumTDConverter implements SmartTypeConverter<Enumerable, DictionaryItemDto> {
@Override
public DictionaryItemDto convert(DictionaryItemDto existingDest, Enumerable src, Class<DictionaryItemDto> destClass, Class<Enumerable> srcClass) {
if(src != null) {
DictionaryItemDto dto = new DictionaryItemDto();
dto.setCode(src.getCode());
dto.setCodeString(src.getCodeString());
return dto;
}
return null;
}
}
@Configuration
public class SmartMapperConfig {
@Bean
public SmartMapper createSmartMapper() {
SmartDozerMapper smartDozerMapper = new SmartDozerMapper();
//全局类型转化器
smartDozerMapper.addCustomConterver(new EnumTDConverter());
//自定义类型添加属性字段映射
smartDozerMapper.addBeanMapping(create());
return smartDozerMapper;
}
private SmartBeanMapping create() {
return SmartBeanMapping.create(User.class, UserResponse.class).fields("userType","dictionaryItemDto");
}
}
@SpringBootTest(classes = MybatislearnApplication.class)
@RunWith(SpringRunner.class)
@Slf4j
public class MybatislearnApplicationTests {
@Autowired
private SmartMapper smartMapper;
@Test
public void test() {
User user = new User();
user.setUserType(UserType.NORMAL_USER);
UserResponse map = smartMapper.map(user, UserResponse.class);
System.out.println(map);
}
}
项目gitee 地址
目前项目中用到的自定义类型转化器有65中,压缩出来供大家使用
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。