前提:在实习过程中师兄建议我学习一下mapstruct这个插件,在学习这个插件前我们先了解一下在企业开发时候需要的一些名词的概念
PO:持久对象,一个PO对应一条记录,不包含任何对于数据库的操作
POJO:无规则简单对象,一个中间对象可以转化为PO,DTO,VO
注意:POJO持久化变为PO,POJO传输过程为DTO,POJO用作表示层为VO
BO:业务逻辑对象,可以接受多个对象
DTO(TO):Data Transfer Object 数据传输对象
VO:value object 值对象 / view object 表现层对象
mapstruct的作用用来处理对象之间的相互转换,只需要实现mapper借口不需要去映射实现
引入依赖
org.mapstruct mapstruct-jdk8 1.2.0.Final org.mapstruct mapstruct-processor 1.2.0.Final
注意:在mybatis中我们使用了mapper注解,他起到了标志接口并且能主动被扫描到的作用,注意我们在这里使用新的注解
import org.mapstruct.Mapper;//mapper注解,能帮助主动创建接口实现类 import org.mapstruct.factory.Mappers;//可以通过class文件获取到对象
@mapper的属性:
- default: 这是默认的情况,mapstruct 不使用任何组件类型, 可以通过Mappers.getMapper(Class)方式获取自动生成的实例对象。
- cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
- spring: 生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入
- jsr330: 生成的实现类上会添加@javax.inject.Named 和@Singleton注解,可以通过 @Inject注解获取
定义实体类
// 实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder//这个注解可以实现可以通过builder方法对于对象进行赋值
public class User {
private Integer id;
private String name;
private String createTime;
private LocalDateTime updateTime;
}
// 被映射类VO1:和实体类一模一样
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO1 {
private Integer id;
private String name;
private String createTime;
private LocalDateTime updateTime;
}
// 被映射类VO1:比实体类少一个字段
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO2 {
private Integer id;
private String name;
private String createTime;
}
定义接口,实体类可以和被映射的对象字段一致,或者少几个
@Mapper(componentModel = "spring")
public interface UserCovertBasic {
//mapps.getMapper(接口class文件),可以获取到接口的实现类
UserCovertBasic INSTANCE = Mappers.getMapper(UserCovertBasic.class);
UserVO1 toConvertVO1(User source);
User fromConvertEntity1(UserVO1 userVO1);
UserVO2 toConvertVO2(User source);
}
可以直接通过instance访问方法
通过mvn中的complier命令查看到生成的Imp代码
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2021-10-14T17:09:56+0800",
comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_301 (Oracle Corporation)"
)
@Component
public class UserCovertBasicImpl implements UserCovertBasic {
@Override
public UserVO1 toConvertVO1(User source) {
if ( source == null ) {
return null;
}
UserVO1 userVO1 = new UserVO1();
userVO1.setId( source.getId() );
userVO1.setName( source.getName() );
userVO1.setCreateTime( source.getCreateTime() );
userVO1.setUpdateTime( source.getUpdateTime() );
return userVO1;
}
@Override
public User fromConvertEntity1(UserVO1 userVO1) {
if ( userVO1 == null ) {
return null;
}
User user = new User();
user.setId( userVO1.getId() );
user.setName( userVO1.getName() );
user.setCreateTime( userVO1.getCreateTime() );
user.setUpdateTime( userVO1.getUpdateTime() );
return user;
}
@Override
public UserVO2 toConvertVO2(User source) {
if ( source == null ) {
return null;
}
UserVO2 userVO2 = new UserVO2();
userVO2.setId( source.getId() );
userVO2.setName( source.getName() );
userVO2.setCreateTime( source.getCreateTime() );
return userVO2;
}
}
复杂一些,当类型不一致怎么办
对接口进行一个修改使用到@Mappers和@Mapper注解
//targer:目标字段,expression表达式:将不符合要求的字段换为符合要求的字段类型
@Mappings({
@Mapping(target = "createTime", expression = "java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),
})
当字段名不一致怎么办
// source为原实体类字段名,target为将要转换为的类型名字
@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName")
})
UserVO4 toConvertVO(User source);
User fromConvertEntity(UserVO4 userVO4);
如果实体类引用了枚举类型,那么插件可以自动为我们插入数据,不需要做任何·转换



