實體映射類庫(modelmapper和MapStruct)

ModelMapper

1. 簡單使用

(1) 引入maven 

        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>1.1.0</version>
        </dependency>

 (2) 簡單操作

//創建 ModelMapper  類
ModelMapper modelMapper = new ModelMapper();
// S 實體相同字段映射到 T 實體
T map = modelMapper.map(S s, T.class);
//集合映射
 List<T> map = modelMapper.map(List<S> s, new TypeToken<List<T>>() {}.getType());

2. 組件與配置

(1) modelMapperAPI

//未有對象映射
BEntity bEntity = modelMapper.map(AEntity aEntity,BEntity.class);
//已有對象映射
modelMapper.map(AEntity aEntity,BEntity bEntity);
//使用泛型
Type type = new TypeToken<List<T>>() {}.getType();//定義泛型,用於映射list
modelMapper.map(AEntity aEntity,Type type);
//驗證映射,目標對象有字段沒有映射報錯
modelMapper.validate();
//添加轉換器
modelMapper.addConverter(Converter<S, D> converter);
//添加映射規則
modelMapper.addMappings(PropertyMap<S, D> propertyMap);
//獲取配置類,可查看和修改
Configuration configuration = modelMapper.getConfiguration();
//創建映射
TypeMap< AEntity,BEntity> typeMap =modelMapper.createTypeMap(AEntity.class,BEntity.class);

(2) 類型映射

//字段映射
   //添加映射字段
    typeMap.addMapping(BEntity::getAField,CEntity::setHField);
    //添加映射字段
    typeMap.addMappings(mapper -> mapper.map(BEntity::getAField,CEntity::setGField));
    //忽略映射字段
    typeMap.addMappings(mapper -> mapper.skip(CEntity::setEField));
    //添加轉換器映射
    typeMap.addMappings(mapper -> mapper.using(Converter<String, String> converter).map(BEntity::getAField,CEntity::setFField))
    //添加提供者映射
    typeMap.addMappings(mapper ->mapper.with(Provider<String>) context).map(BEntity::getAField,CEntity::setFField) )
    //添加過濾條件映射
    typeMap.addMappings(mapper ->mapper.when(Condition<String,String>) condition).map(BEntity::getAField,CEntity::setFField));
    //深度映射 對象->對象字段->字段 ---> 對象 -> 字段
    typeMap.addMappings(mapper -> mapper.map(src -> src.getCEntity().getEField(), BEntity::setAField));
    //深度映射 對象->對象字段->字段 ---> 對象->對象字段 -> 字段
    typeMap.addMappings(mapper -> mapper.<String>map(src -> src.getCEntity().getFField(), (dest, v) -> dest.getCEntity().setHField(v)));
//設置提供者
    //字段提供者,爲目標字段提供值,
    typeMap.setPropertyProvider(Provider<D> provider)
    //對象提供者,在有沒目標對象映射時,可自定義提供目標對象
    typeMap.setProvider(Provider<D> provider)
//設置映射條件
    //對象條件
    typeMap.setCondition(Condition<?, ?> condition);
    //字段條件,當對象條件不通過時,不會執行字段條件
    typeMap.setPropertyCondition(Condition<?, ?> condition);
//設置轉換器
    //對象轉換器,可用來 處理映射 ,返回目標對象,有該轉換器,其他不生效
    typeMap.setConverter(Converter<S, D> converter);
    //沒有setConverter時執行,在進行字段映射前執行
    typeMap.setPreConverter(Converter<S, D> converter);
    //沒有setConverter時執行,在進行字段映射時執行
    typeMap.setPropertyConverter(Converter<S, D> converter);
    //沒有setConverter時執行,在進行字段映射後執行
    typeMap.setPostConverter(Converter<S, D> converter);

(3) 配置

//控制類配置
configuration .setFullTypeMatchingRequired(true);//需要完整類型匹配
configuration .setFieldMatchingEnabled(true);//字段匹配已啓用
configuration .setSkipNullEnabled(true);//跳過空值已啓用
configuration .setAmbiguityIgnored(true);//忽略歧義
configuration .setImplicitMappingEnabled(true);//隱式映射已啓用
//訪問級別配置
configuration .setMethodAccessLevel(Configuration.AccessLevel.PACKAGE_PRIVATE);//方法訪問級別
modelMapper.getConfiguration().setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);//字段訪問級別
//命名方式
configuration .setSourceNameTokenizer(NameTokenizers.CAMEL_CASE);//來源名稱命名方式
configuration .setDestinationNameTokenizer(NameTokenizers.CAMEL_CASE);//目標名稱命名方式
//名稱轉換方式
configuration .setSourceNameTransformer(NameTransformers.JAVABEANS_MUTATOR);//來源名稱轉換方式
configuration .setDestinationNameTransformer(NameTransformers.JAVABEANS_MUTATOR);//目標名稱轉換方式
//命名約定
configuration .setDestinationNamingConvention(NamingConventions.JAVABEANS_ACCESSOR);//目標地命名約定
configuration .setSourceNamingConvention(NamingConventions.JAVABEANS_ACCESSOR);//來源命名約定
//匹配策略
configuration .setMatchingStrategy(MatchingStrategies.LOOSE);
//設置提供者
configuration .setProvider((Provider<String>) provider->{
            return "";
        });
//設置條件
configuration .setPropertyCondition((Condition<String,String>) condition ->{
            return true;
        });

可以配置常量:

命名約定( NamingConventions) NamingConventions.NONE 表示沒有命名約定,該約定適用於所有屬性名稱
NamingConventions.JAVABEANS_ACCESSOR 根據JavaBeans約定查找合格的訪問者
NamingConventions.JAVABEANS_MUTATOR 根據JavaBeans約定查找合格的mutator
名稱轉化器(NameTransformer) NameTransformers.JAVABEANS_ACCESSOR 根據JavaBeans約定轉換訪問者名稱
NameTransformers.JAVABEANS_MUTATOR 根據JavaBeans  set方法轉換變量名稱

             命名方式

      (NameTokenizers)

NameTokenizers.CAMEL_CASE 根據[ 駝峯]對屬性和類名進行標記
NameTokenizers.UNDERSCORE 用[下劃線標記]屬性和類的名稱
匹配策略(MatchingStrategies) MatchingStrategies.STANDARD 智能匹配源和目標屬性
MatchingStrategies.LOOSE 鬆散匹配源屬性和目標屬性
MatchingStrategies.STRICT 嚴格匹配源和目標屬性
訪問級別(AccessLevel) Configuration.AccessLevel.PUBLIC 公開,公共的
Configuration.AccessLevel.PROTECTED 同一包中
Configuration.AccessLevel.PACKAGE_PRIVATE 同一子包中
Configuration.AccessLevel.PRIVATE 同一類中

(3) 映射器

添加字段映射,及各字段映射處理

//自定義映射

        PropertyMap<AEntity,CEntity> propertyMap = new PropertyMap<AEntity, CEntity>() {
            @Override
            protected void configure() {
                /**使用自定義轉換規則*/
                map(source.getAField(), destination.getBField());//主動替換屬性
                map().setAField(source.getBField());/BField字段賦值給AField
                using(toUppercase).map(source.getAField(),destination.getBField());//使用自定義轉換規則
                with(personProvider).map(source.getBField(),destination.getBField());//使用自定義屬性提供覆蓋
                skip(destination.getAField());//過濾指定屬性,非對象
                skip().setDtoOnlyProperty(null);//過濾指定屬性,對象
                when(condition).map().setAField("value");//條件過濾屬性,條件符合賦值value
            }
        };

(4) 轉換器

可進行字段數據處理,類型轉換等操作.

 //定義轉換器
Converter<S, D> toUppercase = new AbstractConverter<S, D>() {
            @Override
            protected Dconvert(S source) {
            //處理原對象,返回目標對象
                return source;
            }
        };
//lambda表達式方式
Converter<String, String> converter = ctx -> ctx.getSource() == null ? null : ctx.getSource();

(5) 提供者

可用於設置映射條件,條件滿足進行條件映射.可通過 Configuration 和 TypeMap 配置,[typeMap.setProvider]可設置一個目標對象;[typeMap.setPropertyProvider] 可爲 源對象 字段 提供值;Configuration 可同時設置對象與字段屬性,處理需判斷類型

//轉換內容提供者
Provider<String> personProvider = new AbstractProvider<String>() {
           @Override
            public String get() {
            //返回要添加的內容
                return "自定義提供者";
            }
        };
//lambda表達式方式
Provider<String> provider = req -> new String();

(6) 條件

可用於設置映射條件,條件滿足進行條件映射.可通過 Configuration 和 TypeMap 配置

//創建自定義條件轉換 注:以下Condition 可添加兩泛值Condition<?,?>
 Condition condition =new Condition() {
            @Override
            public boolean applies(MappingContext mappingContext) {
                //處理字段,返回false不映射
                return false;
            }
        };
//lambda表達式方式
Condition notNull = ctx -> ctx.getSource() != null;
//內置條件
    //原對象字段值爲空不映射
    Condition notNull1 = Conditions.isNotNull();
    //原對象字段值爲空映射
    Condition isNull = Conditions.isNull();
    //判斷原對象字段類型,符合映射
    Condition isType = Conditions.isType(String.class);
    //條件取交集
    Condition and = Conditions.and(Condition c1,Condition c2);
    //條件取反集
    Condition not = Conditions.not(Condition  c);
    //條件取並集
    Condition or = Conditions.or(Condition c1,Condition c2);

MapStruct

1. 簡單使用

(1) 引入maven

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.2.0.Final</version>
        </dependency>

(2) 定義接口

package com.example.demo.mapstruct;
import com.example.demo.pojo.ABean;
import com.example.demo.pojo.BBean;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface Converter {
    Converter  INSTANCE = Mappers.getMapper(Converter.class);
    @Mappings({
        @Mapping(source = "aField", target = "bField"),
    })
    BBean domain2dto(ABean aBean);
   //默認處理方法
   default BBean domain2dto1(ABean aBean) {
        //hand-written mapping logic
    }
}

(3) 簡單操作

 BBean bBean = PersonConverter.INSTANCE.domain2dto(ABean aBean);

2. 常用註解

@Mapper 只有在接口加上這個註解, MapStruct 纔會去實現該接口

        componentModel屬性,主要是指定實現類的類型,一般用到兩個
                default:默認,可以通過Mappers.getMapper(Class)方式獲取實例對象
                spring:在接口的實現類上自動添加註解@Component,可通過@Autowired方式注入
@Mapping:屬性映射,若源對象屬性與目標對象名字一致,會自動映射對應屬性
        source:源屬性
        target:目標屬性
        dateFormat:String到Date日期之間相互轉換,通過SimpleDateFormat,該值爲SimpleDateFormat的日期格式
        ignore:忽略這個字段
@Mappings:配置多個@Mapping
@MappingTarget用於更新已有對象
@InheritConfiguration用於繼承配置

4. 應用詳解

(1) 添加默認方法

default Bean1 defaultConvert(Bean2 bean2) {
    //進行映射處理及其他處理
        return bean1;
    }

(2) 使用abstract class來代替接口

package com.example.demo.mapstruct;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public abstract class Converter  {
    Converter  INSTANCE = Mappers.getMapper(Converter.class);
    @Mappings({
        @Mapping(source = "aField", target = "bField"),
    })
    public abstract BBean domain2dto(ABean aBean);
}

(3) 可以使用多個參數

   @Mappings({
            @Mapping(source = "bean1.field1", target = "field1"),  
            @Mapping(source = "bean2.field1", target = "field2")
    })
    Bean3 toUserRoleDto(Bean1 bean1, Bean2 bean2);

(4) 直接使用參數作爲屬性值

    @Mappings({
            @Mapping(source = "field", target = "field") 
    })
    Bean useParameter(String field);
(5) 更新對象屬性
@Mappings({
            @Mapping(source = "field", target = "field")
    })
    void update(Bean2 bean2, @MappingTarget Bean1 bean1);//@MappingTarget 指定目標對象
(6) 使用Spring依賴注入
//添加 componentModel 屬性
@Mapper(componentModel = "spring")
public interface ConverterMapper {}
// 自動注入
@Autowired
private ConverterMapper  mapper;
(7) 自定義類型轉換
//@Mapper註解加uses屬性
@Mapper( uses = { MyConversion.class})
//自定義轉換器,field爲對應的轉換的字段 MyConversion|conversion自定義
public class MyConversion{
    public String conversion(String field) {
            return field;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章