mapstruct 优势
分布式系统中,应用与应用之间,还有单独的应用细分模块之后,DO 一般不会让外部依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具,毕竟每一个字段都 get/set 会很麻烦。
MapStruct 就是这样的一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。
对比类似功能的BeanUtils,mapstruct是在编译时期生成了相应的转换方法,主要是使用get/set,没有使用反射,在性能上更有优势。
mapstruct 使用
maven 依赖
<properties>
<java.version>1.8</java.version>
<mapstruct.version>1.3.1.Final</mapstruct.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
需要添加的主要有两个地方:
- 依赖
- maven插件
有一个比较坑的地方就是**不同版本的mapstruct,需要的lombok版本不一样。**比如说我这里用的mapstruct版本是 1.3.1.Final,lombok 的版本是1.18.12时没问题,但是如果lombok换成1.18.18,生成的代码就是有问题的。
举例使用
@Setter
@Getter
public class User {
private Long id;
private String username;
private String password;
private Integer sex;
private String other;
private LocalDateTime modifyTime;
private Long fieldLong;
}
@Setter
@Getter
public class UserDto {
private Long id;
private String username;
private String password;
private Integer gender;
private JSONObject other;
}
@Setter
@Getter
public class UserQo {
private Long id;
private String username;
private String password;
}
@Mapper
public interface UserMapping {
@Mappings({
@Mapping(target = "gender", source = "sex"),
@Mapping(target = "other", expression = "java(com.alibaba.fastjson.JSON.parseObject((user.getOther())))")
})
UserDto toUserDto(User user);
@Mappings({
@Mapping(target = "modifyTime", expression = "java(java.time.LocalDateTime.now())"),
@Mapping(target = "fieldLong", constant = "123456789L")
})
User toUser(UserQo userQo);
}
运行mvn clean install 命令后,生成的实现类
public class UserMappingImpl implements UserMapping {
@Override
public UserDto toUserDto(User user) {
if ( user == null ) {
return null;
}
UserDto userDto = new UserDto();
userDto.setGender( user.getSex() );
userDto.setId( user.getId() );
userDto.setUsername( user.getUsername() );
userDto.setPassword( user.getPassword() );
userDto.setOther( com.alibaba.fastjson.JSON.parseObject((user.getOther())) );
return userDto;
}
@Override
public User toUser(UserQo userQo) {
if ( userQo == null ) {
return null;
}
User user = new User();
user.setId( userQo.getId() );
user.setUsername( userQo.getUsername() );
user.setPassword( userQo.getPassword() );
user.setModifyTime( java.time.LocalDateTime.now() );
user.setFieldLong( (long) 123456789L );
return user;
}
}
对于不同属性的处理
对于不同属性的处理,我们一般采用在方法上使用 @Mapping 注解来解决。
-
属性名称不同时,我们这样处理:
@Mapping(target = “gender”, source = “sex”)
-
属性类型不同时,我们这样处理:
@Mapping(target = “other”, expression = “java(com.alibaba.fastjson.JSON.parseObject((user.getOther())))”)
这里是想要将string 转换成 json
-
源对象没有而目标对象需要的属性时,我们可以通过多种方式来设置默认值:
@Mapping(target = “modifyTime”, expression = “java(java.time.LocalDateTime.now())”),
@Mapping(target = “fieldLong”, constant = “123456789L”)
既可以通过表达式来处理,也可以设置常量。