选择Mapstruct的核心原因
- 代码封装
- 速度快(十倍以上的速度优势)
Mapstruct让转换代码聚集在一起
这是一个DTO转Entity的Mapstruct代码,可以看到有如下优势:
- 所有赋值工作,都在一个接口里定义,外部进行DTO转Entity时,只需要一句话,极其简洁,无需多行的设置操作。
- 可以解决不同字段名的赋值,可以解决赋值需要运行函数获取的方式,也可以解决源为空时,再使用函数赋值等等的常见操作
@Mapper(imports = {IdUtil.class, Date.class, CommonUtil.class, VersionUtil.class, SparringWorkConstant.class, DeleteFlagConstant.class})
public interface LessonDTO2Entity{
LessonDTO2Entity instance = Mappers.getMapper(LessonDTO2Entity.class);
@Mapping(target="id", source="id", defaultExpression = "java(IdUtil.getId())")
@Mapping(target="workflowType", source="lessonType")
@Mapping(target="workflowName", source="lessonName")
@Mapping(target="workflowDesc", source="lessonIntroduction")
@Mapping(target="updatedDate", expression = "java(new Date())")
@Mapping(target="updatedBy", expression = "java(CommonUtil.getCurrentUsername())")
SparringWorkflowEntity from(AddOrModifyLessonDTO dto);
/*
from dto
*/
@Mapping(target="id", source="id", defaultExpression = "java(IdUtil.getId())")
@Mapping(target="workflowType", source="lessonType")
@Mapping(target="workflowName", source="lessonName")
@Mapping(target="workflowDesc", source="lessonIntroduction")
/*
init values
*/
@Mapping(target="workflowCode", expression = "java(IdUtil.uuid())")
@Mapping(target="createdDate", expression = "java(new Date())")
@Mapping(target="updatedDate", expression = "java(new Date())")
@Mapping(target="createdBy", expression = "java(CommonUtil.getCurrentUsername())")
@Mapping(target="updatedBy", expression = "java(CommonUtil.getCurrentUsername())")
@Mapping(target="workflowVersion", expression = "java(VersionUtil.init())")
@Mapping(target="workflowState", expression = "java(SparringWorkConstant.EXECUTABLE_STATE)")
@Mapping(target="deleteFlag", expression = "java(DeleteFlagConstant.persist)")
SparringWorkflowEntity fromAndInit(AddOrModifyLessonDTO dto);
}
Mapstruct速度非常快
性能比较代码如下:
@Test
void performance() {
AddOrModifyLessonDTO dto = new AddOrModifyLessonDTO();
dto.setId("123");
dto.setLessonType("dialogue");
dto.setLessonName("test lesson");
dto.setLessonIntroduction("test lesson description");
SparringWorkflowEntity sparringWorkflowEntity = null;
final long LOOP_TIMES = 100000;
StopWatch stopWatch = new StopWatch();
stopWatch.start("mapstruct copy dto");
for(int i=0;i<LOOP_TIMES;i++){
sparringWorkflowEntity = lessonDTO2Entity.instance.from(dto);
}
stopWatch.stop();
stopWatch.start("beansutils copy dto");
for(int i=0;i<LOOP_TIMES;i++){
BeanUtils.copyProperties(dto, sparringWorkflowEntity);
sparringWorkflowEntity.setWorkflowName(dto.getLessonName());
sparringWorkflowEntity.setWorkflowDesc(dto.getLessonIntroduction());
sparringWorkflowEntity.setWorkflowType(dto.getLessonType());
sparringWorkflowEntity.setUpdatedDate(new Date());
sparringWorkflowEntity.setUpdatedBy(CommonUtil.getCurrentUsername());
}
stopWatch.stop();
log.info(stopWatch.prettyPrint());
}
测试结果:
---------------------------------------------
ns % Task name
---------------------------------------------
032059349 005% mapstruct copy dto
555997343 095% beansutils copy dto
mapstruct 比 beansutils的方式快了 17 倍
原因分析:
mapstruct在代码编译阶段,就将接口的Map逻辑转换为set方法,为原生代码实现;
而beansutils是基于java的反射机制实现,通过反射获取类变量是比较慢的;
DTO和Entity的java对象转换,根据典型场景罗列如下FAQ
Q:如果DTO和Entity的字段名和类型相同
A:不需要处理,默认赋值
Q:字段名不同
A: 通过在函数上加Mapping清晰描述映射关系
@Mapping(target="workflowName", source="lessonName")
Q:值是执行函数得到的且没有入参,如 updatedBy, createdDate
A: 通过在函数上加
@Mapping(target="updatedDate", expression = "java(new Date())"
默认需要写全路径,上述可以简写,是因为
在类上加入了imports,能明确知道Date来自这个Date.class
@Mapper(imports = {IdUtil.class, Date.class})
Q:值是执行函数得到,且有入参
A: 通过qualifiedByName
@Mapping(target="workflowType", source="lessonType", qualifiedByName="LessonTypeEnum2WorkflowType")
@Named("LessonTypeEnum2WorkflowType")
public static String LessonTypeEnum2WorkflowType(ESparringWorkflowType lessonType){
return lessonType == null? null : lessonType.getCode();
}
Q:列表的赋值
A: 先定义一个列表转换函数,然后对列表内部的元素的赋值再定义一个函数,具体的规则在元素的函数上定义
@Mapping(source="workflowType", target="lessonType", qualifiedByName = "WorkflowType2LessonTypeEnum")
@Mapping(source="workflowName", target="lessonName")
GetOrModifyLessonResponseDTO to(SparringWorkflow sparringWorkflow);
List<GetLessonsResponseDTO> to(List<SparringWorkflow> sparringWorkflow);