传送门
SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口
一、概念
是一个类似于 BeanUtils.copyProperties(source,target);属性拷贝工具,将source对象的所有属性值对应的拷贝到target对象上。由于 BeanUtils.copyProperties(source,target)只拷贝属性名称相同的属性值,属性名称不同的不会拷贝,而MapStruct则更加强大和灵活,并且性能更好。
二、注解
注解 | 作用 |
---|---|
@Mapper | org.mapstruct包下,指明当前接口用于Mapstruct,用于属性拷贝 |
@Mappings | 默认属性相同的都会拷贝,当属性名称不同的时候,使用这个注解结合@Mapping,来让不同属性名称映射。 |
@Condition | 条件注解,除了作用到整个bean外还可以修饰具体的属性值,实现bean属性维度的条件转换。(就是拷贝的时候,要先判断这个注解标注的方法,符合这个方法,才会进行拷贝) |
@InheritInverseConfiguration | 逆向映射 |
@Named | 自定义方法,配合qualifiedByName一起使用 |
@MappingTarget | 一个对象的信息更新到另一个对象上,指明另一个对象是谁 |
三、使用步骤
第一步:
创建一个接口,以所在业务的对应Controller命名,比如案例的Controller为PersonAdminController,这个接口就叫PersonAdminMapper,并且在vo.personAdminController包下面,一个业务Controller对应一个Mapper。并在接口上加上@Mapper ,注意Mapstruct的注解都是在org.mapstruct
package com.ours.www.demo.controller.vo.personAdminController;
@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface PersonAdminoMapper {
}
第二步:
只需要接口中写业务需要的接口方法即可(这步就已经完成了)。
package com.ours.www.demo.controller.vo;
import com.ours.www.core.common.enums.GenderEnum;
import com.ours.www.core.framework.mvc.vo.PagerResponse;
import com.ours.www.demo.entity.PersonEntity;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
// 不加的话,会将null拷贝给目前对象。 加上后,例如
// 现在 source对象 age=15 name=null tagert对象 age=99 name=zt ;拷贝后 tagert对象 age=15 name=zt 。 不会将name值变为null
public interface PersonAdminMapper {
// 固定写法,Controller或者Service层调用的时候使用INSTANCE变量。
PersonAdminMapper INSTANCE = Mappers.getMapper(DemoMapper.class);
// 请求参数变Entity
PersonEntity rquestToEntity(CreatePersonRequest source);
// Entity变返回结果
@Mappings({
@Mapping(source = "id", target = "_id"),// 默认相同属性名称都会拷贝,相同属性名称可以省略,不同属性名称必须@Mapping映射对应
@Mapping(target="auth2",ignore = true),// 忽略这个属性,不想拷贝的时候这样用。
})
CreatePersonResponse entityToCreateResponse(PersonEntity source);
}
第三步:
开发不需要写接口实现类,在Build的时候idea会自动生成实现类,build以后可以在target目录中看到生成的实现类。
第四步:
使用。如下面代码中第19行,需要将PersonEntity实例的属性值拷贝到最后返回结果CreatePersonResponse上面,只需要在PersonAdminMapper接口写一个接口方法即可。
该接口方法如下:
CreatePersonResponse entityToCreateResponse(PersonEntity source);// 将source对象拷贝到返回结果对象上。
@Tag(name = "人员管理端接口")// @Tag 用来设置 Controller 的名称和描述
@AdminRestController("/demo/user")
@CheckLicense(LicenseModuleEnum.ehr_personManager)
public class PersonAdminController {
private final PersonAdminService personAdminService;
public PersonAdminController(PersonAdminService personAdminService) {
this.personAdminService = personAdminService;
}
@Operation(summary = "添加人员")
@PostMapping("/create")
@CheckLicense(subs = SubLicenseEnum.level)
@OursRBAC({OrgTypeEnum.hrPersonMgr, OrgTypeEnum.hrPersonMgr4Main})
public R<CreatePersonResponse> createPerson(@Valid @RequestBody CreatePersonRequest createPersonRequest) {
PersonEntity entity = personAdminService.createPerson(createPersonRequest);
// 将source对象拷贝到返回结果CreatePersonResponse对象上
CreatePersonResponse createPersonResponse = PersonAdminMapper.INSTANCE.entityToCreateResponse(entity);
return R.ok(createPersonResponse);
}
}
第五步:
需要 idea中下载 mapstruct support 插件,安装重启Idea,这样方便书写Mapstruct的get代码。
更多Mapstruct高级用法参考下面文章,实际代码见下面的增删改查示例代码:
Mapstruct的CSDN参考文章:https://blog.csdn.net/qq_44732146/article/details/119968376
四、Mapstruct的枚举使用
/**
* 查询单个人员
*/
// Entity变返回结果
@Mappings({
// 语法说明:expression表示java表达式,java小括号里面内容就是一个方法,findEnumByValue是方法名,后面是该方法的两个参数。由于包权限问题,方法名和参数等根据情况需要写全类名。
// @Mapping(target="genderEnum",expression = "java(findEnumByValue(GenderEnum.class,source.getGender()))")// 相同包下可以省略全类名,但是由于GenderEnum、source、XxxMapper不在同一个包下,所以需要改成下行代码
// @Mapping(target="genderEnum",expression = "java(com.ours.www.core.common.enums.OursBaseEnum.findEnumByValue(com.ours.www.core.common.enums.GenderEnum.class,source.getGender()))")// 不同包需要全类名
// GenderEnum性别枚举举例: gender_male(1,"男"),
@Mapping(source = "gender", target = "gender"),// 枚举映射 普通属性值-》转化为枚举值 例如: 1-》1 备注:相同的可以省略不写,本行代码可以省略
@Mapping(target="genderDesc",expression = "java("+ findEnumDesByValue +"("+ genderEnum +",source.getGender()))"),// 枚举映射 普通属性值-》转化为枚举描述 例如: 1-》男
@Mapping(target="genderEnum",expression = "java("+ findEnumByValue +"("+ genderEnum +",source.getGender()))"),// 枚举映射 普通属性值-》转化为枚举对象 例如: 1-》GenderEnum
})
ViewPersonResponse entityToViewResponse(PersonEntity source);