MapStruct 对象映射
MapStruct 对象映射
MapStruct 是一个非常实用的 Java 对象映射工具,它可以帮助你轻松地完成不同类型之间的转换。相对于手动进行对象映射,MapStruct 可以减少很多模板代码的编写,提高开发效率,同时也可以减少因手动映射而产生的错误。
MapStruct 在处理简单对象转换时效果非常好,而且易于学习和使用。它提供了很多自定义配置和扩展点,可以满足各种不同场景下的需求。
总的来说,MapStruct 是一款非常实用的 Java 对象映射工具,特别适合处理简单对象转换的场景。如果项目需要进行大量对象映射,那么可以考虑使用 MapStruct 来提高开发效率和减少错误。
官方手册:MapStruct 1.5.3.Final Reference Guide
注:对于mapstruct这个映射框架,并没有非常深入的学习,选择用的时候再去详细查的方式,所以你现在看到的文章内容并不是mapstruct的全部功能,不能满足个人需求时,可以再查阅下其它文章;当然后续我也会不断完善这篇文章,将实际项目中涉及到转换的方式记录下来,当作笔记,以便后续查询。
样例
第一步,导入依赖:
<!-- 对象映射框架-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
需要注意的是,mapstruct与lombok都是在编译前运行,所以这个插件需要有先后顺序,也就是lombok先执行,否则mapstruct参数使用到了通过lombok的@Data注解的参数,会出现字段不能正常获取的问题,解决办法(设置编译插件):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!-- depending on your project-->
<source>${jdk.version}</source>
<!-- depending on your project-->
<target>${jdk.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.plugin.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.plugin.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
第二步,编写一个example(同类型、名字,不需要配置):
public class Example {
private String name;
private Integer age;
}
public class ExampleVo {
private String name;
private Integer age;
}
@Mapper
public interface ExampleConverter {
ExampleConverter INSTANCE = Mappers.getMapper(ExampleConverter.class);
ExampleVo toVo(Example example);
List<ExampleVo> toVo(List<Example> examples);
}
总结:
- 导入Maven依赖。
- 创建接口或者抽象类Mapper对象,并使用@Mapper注解。
- 通过Mappers工厂,创建INSTANCE实例。
- 编写bean对象转换规则,可使用@Mappings注解(类型、名称相同时,可省略@Mappings注解)或者default默认实现。
- 使用静态对象进行转换,例如ExampleConverter.INSTANCE.toVo();
案例
在java中bean的种类很多,如vo、pojo、dto等。出现需要bean类型转换的时候就可以使用mapstruct十分方便。
状态(数字转字符串)
例如:状态(0:禁用,1:启用)、性别(0:未知,1:男性,2:女性)Integer转String。
Bean对象:
// 省略不需要的代码
public class User {
/**
* 用户名
*/
private String username;
/**
* 昵称
*/
private String nickname;
/**
* 性别(0:未知,1:男性,2:女性)
*/
private Integer gender;
/**
* 状态(0:禁用,1:启用)
*/
private Integer status;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 省略其它不用的字段...
*/
}
@ApiModel("用户查询信息对象")
public class UserQueryVo {
@ApiModelProperty("账号")
private String username;
@ApiModelProperty("昵称")
private String nickname;
@ApiModelProperty("状态(0:禁用,1:启用)")
private String status;
@ApiModelProperty("性别(0:未知,1:男性,2:女性)")
private String gender;
@ApiModelProperty("创建时间")
private String createTime;
}
Mapper对象,这里涉及到不同Integer类型,代表不同的含义,处理方式使用@Named自定义转换规则,并在@Mapping注解qualifiedByName参数选择自定义转换规则:
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
@Named("status")
default String status(Integer status) {
String result;
switch (status) {
case 0:
result = "禁用";
break;
case 1:
result = "启用";
break;
default:
result = "-";
}
return result;
}
@Named("gender")
default String gender(Integer gender) {
String result;
switch (gender) {
case 0:
result = "未知";
break;
case 1:
result = "男性";
break;
case 2:
result = "女性";
break;
default:
result = "-";
}
return result;
}
@Mappings({
@Mapping(source = "username", target = "username", defaultValue = "-"),
@Mapping(source = "nickname", target = "nickname", defaultValue = "-"),
@Mapping(source = "status", target = "status", qualifiedByName = "status", defaultValue = "-"),
@Mapping(source = "gender", target = "gender", qualifiedByName = "gender"),
@Mapping(source = "createTime", target = "createTime", defaultValue = "-", dateFormat = "yyyy-MM-dd HH:mm:ss"),
})
UserQueryVo toVo(User data);
List<UserQueryVo> toVo(List<User> data);
@Mappings({
@Mapping(source = "username", target = "username"),
@Mapping(source = "phone", target = "mobile"),
})
User toPojo(UserQueryParam param);
}
实际代码:
@Override
public List<UserQueryVo> queryUsers(UserQueryParam param) {
// 转换
User user = UserConverter.INSTANCE.toPojo(param);
Page page = PageConverter.INSTANCE.toPojo(param);
// 查询
List<User> users = userMapper.selectUsers(user, page);
// 转vo
return UserConverter.INSTANCE.toVo(users);
}
页(计算偏移)
Bean对象:
@Data
@ApiModel("分页参数")
public class PageVo {
/**
* 页大小
*/
@Digits(fraction = 0, integer = 3, message = "长度不能超过3位,请输入合法参数!")
@NotNull(message = "参数不能为空!")
private Integer pageSize;
/**
* 页码
*/
@Digits(fraction = 0, integer = 3, message = "长度不能超过3位,请输入合法参数!")
@NotNull(message = "参数不能为空!")
private Integer pageNo;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Page {
/**
* 页大小
*/
private Integer pageSize;
/**
* 页码
*/
private Integer pageNo;
/**
* 偏移 = (pageNo - 1) * pageSize
*/
private Integer offset;
}
Mapper对象,使用expression来计算偏移:
@Mapper
public interface PageConverter {
PageConverter INSTANCE = Mappers.getMapper(PageConverter.class);
@Mappings({
@Mapping(source = "vo.pageSize", target = "pageSize"),
@Mapping(source = "vo.pageNo", target = "pageNo"),
@Mapping(target = "offset", expression = "java((vo.getPageNo() - 1) * vo.getPageSize())"),
})
Page toPojo(PageVo vo);
}