Java實體對映工具MapStruct使用詳解

AnakinSky發表於2021-11-05

1.序

通常在後端開發中經常不直接返回實體Entity類,經過處理轉換返回前端,前端提交過來的物件也需要經過轉換Entity實體才做儲存;通常使用的BeanUtils.copyProperties方法也比較粗暴,不僅效率低下(使用反射)而且僅對映相同名的屬性,多數情況下還需要手動編寫對應的轉換方法實現。
外掛MapStruct以介面方法結合註解優雅實現物件轉換,MapStruct生成器生成程式碼以更貼近原生的Setter、Getter方法處理屬性對映更為高效。
https://github.com/mapstruct/mapstruct/
https://github.com/mapstruct/mapstruct-examples

2.簡單用例

實體物件User

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

轉換物件UserVO

@Data
public class UserVO {
    private String name;
    private int age;
}

轉換介面

@Mapper
public interface UserConvert {
    UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
    @Mapping(source = "name", target = "userName")
    UserVO toVO(User entity);
}

使用示例

@Test
public void contextLoads() {
    User user = new User(0, "Tester", 1, "上海市徐彙區");
    UserVO userVO = UserConvert.INSTANCE.toVO(user);
}

3.使用詳解

1)關於介面註解@Mapper幾種屬性用法詳解

uses 使用其他手動編寫的或者其他Mapper介面覆寫相關的轉換方法,不能迴圈引用

@Mapper(uses=DateMapper.class)

imports 引用相關類,允許通過mapping.expression()mapping.defaultExpression()直接使用這些型別

@Mapper(imports = DateUtil.class)
public interface UserConvert {
    UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
    @Mappings({
            @Mapping(source = "name", target = "userName"),
            // 以指定方法轉換屬性,這裡如果不使用imports,則需要寫全引用類包路徑
            @Mapping(target = "birthday", expression = "java(DateUtil.formatDate(entity.getBirthday()))")
    })
    UserVO toVO(User entity);
}

unmappedSourcePolicyunmappedTargetPolicy 針對源型別/目標型別中未對映屬性的反饋策略,主要有三種:IGNORE,預設值,忽略未對映的欄位。WARN,警告。ERROR,報錯
typeConversionPolicy 針對有損轉換的反饋策略,例如Long轉Integer

@Mapper(unmappedSourcePolicy = ReportingPolicy.ERROR)

componentModel 指定生成對映器例項的模式,主要有四種:default,不主動生成例項,通常以Mappers.getMapper(Class)例項化。cdi,以CDI標準例項化對映器,使用@Inject注入相關例項,spring,Spring Bean方式例項化,jsr330,jsr330標準例項化

@Mapper(componentModel = "spring")
public interface UserConvert {
    @Mapping(source = "name", target = "userName")
    UserVO toVO(User entity);
}
@Autowired
private UserConvert userConvert;

implementationName 指定實現類名稱,對映生成器介面會自動生成實現類<CLASS_NAME>Impl,使用此屬性可避免類衝突
implementationPackage 指定實現類包路徑

config 指定配置類,由指定的@MapperConfig配置類,config匯入相關配置
配置類

@MapperConfig(
        uses = DateUtil.class,
        unmappedSourcePolicy = ReportingPolicy.WARN
)
public interface UserConfig {
}

匯入配置類

@Mapper(componentModel = "spring", config = UserConfig.class)

collectionMappingStrategy 集合對映策略,這裡注意集合對映時,如果集合中的型別已有對應轉換方法,集合轉換時會優先使用

@Mappings({
        @Mapping(source = "name", target = "userName"),
        @Mapping(target = "birthday", expression = "java(DateUtil.formatDate(entity.getBirthday()))")
})
UserVO toVO(User entity);
List<UserVO> collectionCvt(List<User> entities);

GENERATED CODE 生成器生成程式碼

public List<UserVO> collectionCvt(List<User> entities) {
    if (entities == null) {
        return null;
    } else {
        List<UserVO> list = new ArrayList(entities.size());
        Iterator var3 = entities.iterator();

        while(var3.hasNext()) {
            User user = (User)var3.next();
            // 集合轉換時優先使用了已定義的toVO方法
            list.add(this.toVO(user));
        }

        return list;
    }
}

nullValueMappingStrategy null作為源值對映策略;RETURN_NULL預設返回null, RETURN_DEFAULT返回預設值,對於物件會通過構造器自動構造物件返回,集合會返回空集合
當值為RETURN_DEFAULT時,如果對映規則中包含Mapping.expression、Mapping.constant必須手動判空處理,否則NPE

@MapperConfig(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)

NullValuePropertyMappingStrategy null作為源屬性對映策略;SET_TO_NULL預設返回null,SET_TO_DEFAULT返回預設值,IGNORE 忽略該值,以目標物件已存在的值為準

MappingInheritanceStrategy 繼承方法級對映配置策略:EXPLICIT 顯示使用InheritConfiguration生效。AUTO_INHERIT_FROM_CONFIG 自動繼承正向轉換的配置。AUTO_INHERIT_REVERSE_FROM_CONFIG 自動繼承反向轉換的配置。AUTO_INHERIT_ALL_FROM_CONFIG 都繼承

@MapperConfig(
        mappingInheritanceStrategy = MappingInheritanceStrategy.EXPLICIT
)
@InheritConfiguration
void cvtVO(User entity, @MappingTarget UserVO vo);

nullValueCheckStrategy 空值監測策略

2) 其他方法級別註解

@InheritInverseConfiguration 反向轉換時繼承對映規則

@Mapping 配置型別屬性的對映規則;
dateFormat 格式化日期

@Mapping(target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")

numberFormat 數字格式化

@Mapping(target = "price", numberFormat = "$#.00")

constant 常量

@Mapping(target = "age", constant = "0")

相關文章