mapstruct⾼级使⽤⽅法
背景介绍
在微服务盛⾏的当下,相信对领域驱动设计都不陌⽣,在领域驱动设计中,我们经常要处理将DTO转换成Domain,Domain转成Entity等各类对象相互转换,在没有接触mapstruct之前,相信⼤多数⼈都是使⽤Spring框架⾃带的BeanUtils或者直接使⽤getter/setter⽅法进⾏属性赋值,如果我们采⽤BeanUtils⼯具类的copyProperty进⾏转换,除了性能低之外(因为是利⽤反射实现的),还有可能出现类型转换错误等问题。⽽使⽤getter/setter⽅法需要写很多代码,效率低。
与BeanUtils转换⼯具相⽐,MapStruct具有以下优点:
1.使⽤纯Java⽅法代替Java反射机制快速执⾏
2.编译时类型安全:只能映射彼此的对象和属性
3.如果⽆法映射实体或属性,则在编译时清除错误报告
从上图可以看出性能优势⽐较明显。
Maven依赖
<dependency>
<groupId>org.mapstruct</groupId>
<!-- jdk8以下就使⽤mapstruct -->
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
为了省懒,也使⽤了lombok,所以也加⼊了lombok的依赖,需要注意的是lombok版本,如果使⽤了lombok的1.16.10版本,需要调整为1.16.20版本,否则在编译的时候可能会报⽆参构造函数等等错误。
使⽤⽅法
下⾯使⽤Staff和StaffEntity对象互相转换为例进⾏说明mapstruct的使⽤⽅法,基本包含了各种情况下
的使⽤⽅法。
由于⼀个项⽬内会有很多这种对象间转换的情况,下⾯我们抽象出⼀个转换基类,不同对象如果只是简单转换则可以直接继承该基类,不需要覆写基类的任何⽅法,即只需要⼀个空类就可以。需要说明的是如果⼦类覆写了基类的⽅法,那么基类上配置的 @Mapping 就会失效。
import org.mapstruct.InheritConfiguration;
import org.mapstruct.InheritInverseConfiguration; import org.mapstruct.MapperConfig;
import java.util.List;
import java.util.stream.Stream;
/**
* @author Administrator
*/
@MapperConfig
public interface BaseMapping<S, T> {
/**
* 映射同名属性
* @param source
* @return
*/
T source2target(S source);
/**
* 反向映射同名属性
* @param target
* @return
*/
@InheritInverseConfiguration(name = "source2target") S target2Source(T target);
/**
* 集合形式的映射同名属性
* @param source
* @return
*/
@InheritConfiguration(name = "source2target")
List<T> source2target(List<S> source);
/**
* 集合形式的反向映射同名属性
* @param target
* @return
*/
@InheritConfiguration(name = "target2Source")
List<S> target2Source(List<T> target);
/**
* 集合流形式的映射同名属性
* @param source
* @return
*/
List<T> source2target(Stream<S> source);jdk怎么使用
/
**
* 集合流形式的反向映射同名属性
* @param target
* @return
*/
List<S> target2Source(Stream<T> target);
}
创建Staff与StaffEntity对象的转换器
demomon.BaseMapping;
demo.domain.Staff;
ity.StaffEntity;
ums.StatusEnum;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import java.util.Objects;
/**
* @author Administrator
*/
@Mapper(componentModel = "spring")
public interface StaffTranslator extends BaseMapping<Staff, StaffEntity> {
@Override
@Mappings({
@Mapping(source = "description", target = "staffDescription")
,
@Mapping(source = "department.id", target = "departmentId"),
@Mapping(target = "birthday", dateFormat = "yyyyMMdd"),
@Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(target = "salary", numberFormat = "0.00")
})
StaffEntity source2target(Staff source);
@Override
@Mappings({
@Mapping(source = "staffDescription", target = "description")
,
@Mapping(source = "departmentId", target = "department.id"),
@Mapping(target = "password", ignore = true),
@Mapping(target = "birthday", dateFormat = "yyyyMMdd"),
@Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
})
Staff target2Source(StaffEntity target);
default Integer statusEnum2Int(StatusEnum value){
return Objects.isNull(value) ? null : Value();
}
default StatusEnum int2StatusEnum(Integer value){
return Objects.isNull(value) ? null : ByValue(value);
}
}
说明:
@Mapping(source = "description", target = "staffDescription")
将Staff对象的description属性映射StaffEntity对象的staffDescription属性,在属性类型⼀样的情况。
@Mapping(source = "department.id", target = "departmentId")
将Staff对象的department对象的id属性映射StaffEntity对象的departmentId属性,在属性类型不⼀样的情况。
@Mapping(target = "birthday", dateFormat = "yyyyMMdd")
和
@Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
将Staff对象的birthday属性映射StaffEntity对象的birthday属性时对⽇期按照dateFormat配置的格式进⾏格式化,在属性类型不⼀样的情况,针对的是⽇期和字符串类型之间的转换。
@Mapping(target = "salary", numberFormat = "0.00")
将Staff对象的salary属性映射StaffEntity对象的salary属性时对数值按照numberFormat配置的格式进⾏格式化,在属性类型不⼀样的情况,这个是对数值进⾏格式化,只是这个格式化针对的是数值和字符串之间的转换。
@Mapping(target = "password", ignore = true)
在StaffEntity转换成Staff对象时会忽略掉password这个属性。
default Integer statusEnum2Int(StatusEnum value){
return Objects.isNull(value) ? null : Value();
}
default StatusEnum int2StatusEnum(Integer value){
return Objects.isNull(value) ? null : ByValue(value);
}
这个是⾃定义的数据类型转换,将StatusEnum枚举类型转换成int类型
下⾯看看上⾯的配置编译之后的代码(可以到项⽬的target/generated-sources/annotations下⾯到)。
1.Staff转StaffEntity时编译后的代码
@Override
public StaffEntity source2target(Staff source) {
if ( source == null ) {
return null;
}
StaffEntity staffEntity = new StaffEntity();
staffEntity.setStaffDescription( Description() );
staffEntity.setDepartmentId( sourceDepartmentId( source ) );
staffEntity.setId( Id() );
staffEntity.setName( Name() );
staffEntity.setPassword( Password() );
staffEntity.setSex( Sex() );
if ( Birthday() != null ) {
staffEntity.setBirthday( new SimpleDateFormat( "yyyyMMdd" ).format( Birthday() ) );
}
if ( Salary() != null ) {
staffEntity.setSalary( new DecimalFormat( "0.00" ).format( Salary() ) );
}
staffEntity.setStatus( statusEnum2Int( Status() ) );
if ( CreateTime() != null ) {
staffEntity.setCreateTime( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format( CreateTime() ) ); }
return staffEntity;
}
2.StaffEntity转Staff时编译后的代码
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论