使用mapstruct实现BeanCopy

MapStruct是一个开源的Java映射框架,它可以帮助开发者在不同类型的Java对象之间进行无缝转换。通过使用注解配置映射规则,MapStruct可以自动生成高效的映射代码,减少手动编写转换逻辑的工作量。它支持在编译时生成映射代码,因此可以提供更好的性能和类型安全性。总的来说,MapStruct使Java对象之间的转换变得更加简单和高效。

1.使用MapStruct替换BeanUtils

在处理一般简单场景时,可以选择使用BeanUtils、Spring官方工具或其他第三方工具,它们功能相似。然而,对于复杂字段映射,这些工具可能不够强大,并且在进行批量转换时,效率也会受到影响。这时候,MapStruct就能很好地解决这两个问题。在编译时,MapStruct会自动生成映射代码,保证高性能、提前发现问题并让开发人员能够进行彻底的错误检查。

2.集成MapStruct

2.1.首先需要依赖他的相关的jar包
<!-- 引入mapstruct -->
<dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct</artifactId>
	<version>1.4.2.Final</version>
</dependency>

因为MapStruct需要在编译器生成转换代码,所以需要在maven-compiler-plugin插件中配置上对mapstruct-processor的引用,由于项目中已经使用了lombok和fluent-mybatis,
所以这两个也需要纳入管理,如果还有其他需要在编译器生成转换代码的组件,也需要纳入管理(可以保证编译的顺序)

注意:官网有坑,lombok一定要放在最前面,让其先生成get/set方法,否则mapstruct编译会找不到属性的get/set方法

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<version>3.8.1</version>
	<configuration>
		<source>1.8</source>
		<target>1.8</target>
		<encoding>utf-8</encoding>
		<!-- 管理自动生成代码,会按Path先后先顺序生成lombok放在前面,否则mapstruct使用时会找不到get方法 -->
		<annotationProcessorPaths>
			<path>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
				<version>1.18.16</version>
			</path>
			<path>
				<groupId>org.mapstruct</groupId>
				<artifactId>mapstruct-processor</artifactId>
				<version>1.4.2.Final</version>
			</path>

			<path>
				<groupId>com.github.atool</groupId>
				<artifactId>fluent-mybatis-processor</artifactId>
				<version>1.6.8</version>
			</path>
			<!-- other annotation processors -->
		</annotationProcessorPaths>
	</configuration>
</plugin>
2.2.我们需要定义一个做映射的接口(实体类和DTO代码省略)
/**
 * MapStruct实体类和DTO转换 类名不能以Mapper结尾,否则和fluent-mybatis冲突
 */
@Mapper
public interface MapStruct {
    MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);

    /**
     * 将ApiGroupEntity转成ApiGroupDto
     * @param entity
     * @return
     */
    @Mappings({
            @Mapping(source = "id", target = "id"),
            @Mapping(source = "name", target = "name"),
            @Mapping(source = "groupRemark", target = "groupRemark")
    })
    ApiGroupDto convertEntityToDto(ApiGroupEntity entity);
}

编译成功后,会在target下自动生成对应的实现类MapStructImpl

package com.cnhqd.scap.dataStation.mapper.mapstruct;

import com.cnhqd.scap.dataStation.dto.api.ApiGroupDto;
import com.cnhqd.scap.dataStation.entity.api.ApiGroupEntity;

public class MapStructImpl implements MapStruct {
    public MapStructImpl() {
    }

    public ApiGroupDto convertEntityToDto(ApiGroupEntity entity) {
        if (entity == null) {
            return null;
        } else {
            ApiGroupDto apiGroupDto = new ApiGroupDto();
            apiGroupDto.setId(entity.getId());
            apiGroupDto.setName(entity.getName());
            apiGroupDto.setGroupRemark(entity.getGroupRemark());
            apiGroupDto.setDomainInfo(entity.getDomainInfo());
            apiGroupDto.setRelProjectId(entity.getRelProjectId());
            apiGroupDto.setCreatePerson(entity.getCreatePerson());
            return apiGroupDto;
        }
    }
}
2.3.测试
public static void main(String[] args) {
    ApiGroupEntity entity = new ApiGroupEntity();
    entity.setId("123");
    entity.setGroupRemark("789");
    entity.setName("API分组");
    ApiGroupDto apiGroupDto = MapStruct.INSTANCE.convertEntityToDto(entity);
    System.out.println(apiGroupDto);
}

输出结果:

ApiGroupDto(id=123, name=API分组, groupRemark=789, domainInfo=null, relProjectId=null, createPerson=null)

Process finished with exit code 0

3.MapStruct的使用方法

MapStruct使用时只需使用映射类获取实例,调用对应方法即可

MapStruct.INSTANCE.convertEntityToDto(entity);

MapStruct支持属性名称不一致,属性类型不一致和多对一等多种方式,下面以简单的示例来展开

3.1属性名称不一致

需要转换的两个类属性名称不一致

/**
 * user类
 */
@Data
@AllArgsConstructor
public class User {
    private String id;
    private String name;
    private int age;
}
/**
 * userDto
 */
@Data
public class UserDto {
    private String userId;
    private String userName;
    private int userAge;
}

映射方法

@Mappings({
       @Mapping(source = "id", target = "userId"),
       @Mapping(source = "name", target = "userName"),
       @Mapping(source = "age", target = "userAge")
})
UserDto convertDto(User entity);

测试

public static void main(String[] args) {
    User user = new User("123", "张三", 25);
    UserDto userDto = EntityConvertDtoMapper.INSTANCE.convertDto(user);
    System.out.println(userDto);
}

输出结果:

UserDto(userId=123, userName=张三, userAge=25)
3.2属性类型不一致

需要转换的两个类属性类型不一致User的id为long,UserDto为String

@Data
@AllArgsConstructor
public class User {
    private long id;
    private String name;
    private int age;
}
@Data
public class UserDto {
    private String id;
    private String name;
    private int age;
}

映射方法
通过expression属性指定java表达式,表达式中的方法可以自定义。本例用String.valueOf()

@Mappings({
       @Mapping(target = "id", expression = "java(java.lang.String.valueOf(entity.getId()))")
})
UserDto convertDto(User entity);

测试

public static void main(String[] args) {
    User user = new User(123, "张三", 25);
    UserDto userDto = EntityConvertDtoMapper.INSTANCE.convertDto(user);
    System.out.println(userDto);
}

结果:

UserDto(id=123, name=张三, age=25)
3.3多对一

两个实体类转成一个Dto

@Data
@AllArgsConstructor
public class User {
    private long id;
    private String name;
    private int age;
}

@Data
@AllArgsConstructor
public class UserInfo {
    private long id;
    private String address;
    private String position;
}

@Data
public class UserDto {
    private String id;
    private String name;
    private int age;
    private String address;
    private String position;
}

映射方法

@Mappings({
        @Mapping(source = "user.id", target = "id"),
        @Mapping(source = "user.name", target = "name"),
        @Mapping(source = "user.age", target = "age"),
        @Mapping(source = "info.address", target = "address"),
        @Mapping(source = "info.position", target = "position")
})
UserDto convertDto(User user, UserInfo info);

测试:

public static void main(String[] args) {
    User user = new User(123, "张三", 25);
    UserInfo info = new UserInfo(123, "西安市", "产品经理");
    UserDto userDto = EntityConvertDtoMapper.INSTANCE.convertDto(user, info);
    System.out.println(userDto);
}

结果:UserDto(id=123, name=张三, age=25, address=西安市, position=产品经理)

3.4批量copy

一个Mappings映射,可以对应多个转换方法,例如:

@Mappings({
        @Mapping(source = "id", target = "userId"),
        @Mapping(source = "name", target = "userName"),
        @Mapping(source = "age", target = "userAge")
})
// 单条数据copy
UserDto convertDto(User entity);

// 批量copy
List<UserDto> convertListDto(List<User> entity);

如有问题,欢迎评论、指正!

4 和spring集成
@Mapper(componentModel = "spring")
public interface DataQualityJobCalculateDelayInfoConverter {

    /**
     * entity to dto
     * @param list
     * @return
     */
    List<DataQualityJobCalculateDelayInfoDto> toDtoList(List<DataQualityJobCalculateDelayInfo> list);

    DataQualityJobCalculateDelayInfoDto toDto(DataQualityJobCalculateDelayInfo info);

    DataQualityJobCalculateDelayInfo toEntity(DataQualityJobCalculateDelayInfoDto info);
}

在Spring中的使用

@Autowired
private DataQualityJobCalculateDelayInfoConverter converter;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值