MapStruct(entity優雅的轉dto)

開發中我們可能使用JPA、通用Mapper或者MyBatis-Plus去查詢數據,而這類框架都是返回的實體,實體是和數據庫中的表是一一對應的,而作為接口的返回值我們無需把整個實體都暴露給前端,通常會將實體轉換成另一個DTO對象來返回,通常有以下轉換方式:

  • 自己寫代碼手動轉換(這種方式代碼量多,而且不優雅)

  • BeanUtils.copyProperties(entity, dto),這種方式是通過反射來實現的,一般反射效率相對有點低

  • 使用ModelMapper框架(這種方式是通過反射來實現的,一般反射效率相對有點低)

  • 使用MapStruct框架(這種方式是在編譯器自動生成轉換代碼,將原來的手動改為自動,相對於使用反射實現的此種方式效率更好)

綜合比較性能、問題排查、文檔、成熟度、擴展性等因素來考慮,MapStruct 是一個不錯的選擇,實體映射轉換各個工具比較 https://java.libhunt.com/compare-mapstruct-vs-selma

MapStruct(entity優雅的轉dto)

  • MapStruct官網地址: http://mapstruct.org/,

  • GitHub示例程序:https://github.com/mapstruct/mapstruct-examples

1. 添加依賴 和 配置插件

注意:如果使用了lombok應儘量使用比較高的版本,maven-compiler-plugin 插件也最好使用較高的版本。否則有可能報這個錯:

<code>Error:(12, 5) java: No property named "xxx" exists in source parameter(s). Did you mean "null"?
/<code>
<code>
    UTF-8
    1.8
    1.8
    1.4.1.Final
    1.18.12



    
        org.mapstruct
        mapstruct
        ${org.mapstruct.version}
    

    
        org.projectlombok
        lombok
        ${org.projectlombok.version}
        provided
    

    
        org.apache.commons
        commons-lang3
    



    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    1.8
                    1.8
                    
                        
                            org.mapstruct
                            mapstruct-processor
                            ${org.mapstruct.version}
                        
                        
                            org.projectlombok
                            lombok
                            ${org.projectlombok.version}
                        
                    
                
            
        
    

/<code>

2. 實體

<code>@Getter
public enum UserStatusEnum {

   NORMAL(0, "正常"),
   LOCK(1, "鎖定");


   private Integer code;
   private String desc;


   UserStatusEnum(Integer code, String desc) {
      this.code = code;
      this.desc = desc;
   }
}
/<code>
<code>@Data
public class UserInfo {
    private String address;
    private String remark;
}
/<code>
<code>@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private UserStatusEnum userStatusEnum;
    private Date createTime;

    private UserInfo userInfo;
}
/<code>

3. DTO

<code>@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserDTO {

    private Long id;
    private String realName;
    private Integer status;
    private String address;
    private String password;

    private String createTimeFormat;
}
/<code>

4. 實體與DTO屬性映射配置

<code>@Mapper(componentModel="spring")
public interface UserConverter {

    @Mappings({
        @Mapping(source = "name", target = "realName"),
        @Mapping(target = "status", expression = "java(user.getUserStatusEnum().getCode())"),
        @Mapping(source = "createTime", target = "createTimeFormat", dateFormat = "yyyy-MM-dd HH:mm:ss"),
        @Mapping(source = "userInfo.address", target = "address"),
        @Mapping(target = "password", ignore = true)
    })
    UserDTO entity2dto(User user);
}
/<code> 
  • @Mapper 只有在接口加上這個註解,MapStruct 才會去實現該接口,@Mapper 裡有個 componentModel 屬性,主要是指定實現類的類型,一般用到兩個:
  • default:默認,可以通過 Mappers.getMapper(Class) 方式獲取實例對象。
  • spring:在接口的實現類上自動添加註解 @Component,可通過 @Autowired 方式注入。
  • @Mappings:配置多個@Mapping
  • @Mapping:屬性映射,若源對象屬性與目標對象名字一致,會自動映射對應屬性
  • source:源屬性
  • target:目標屬性
  • dateFormat:String 到 Date 日期之間相互轉換,通過 SimpleDateFormat,該值為 SimpleDateFormat的日期格式
  • expression:使用Java方法來格式化值
  • ignore: 忽略這個字段

@Mapper可以單獨放在一個類中配置,也可以在JPA或者MyBatis中的Mapper類中來配置。

手工編譯(mvn compile)或者啟動 IDE 的時候, 會自動在 target/classes 下生成對應的實現類。

MapStruct(entity優雅的轉dto)

5. Test

<code>@SpringBootTest
class SpringbootMapstructApplicationTests {

    @Autowired
    private UserConverter userConverter;


    @Test
    public void testMapStruct() {
        UserInfo userInfo = new UserInfo();
        userInfo.setAddress("上海市");
        userInfo.setRemark("此人非常懶");

        User user = new User();
        user.setId(1L);
        user.setName("周某人");
        user.setPassword("123456");
        user.setUserStatusEnum(UserStatusEnum.LOCK);
        user.setCreateTime(new Date());
        user.setUserInfo(userInfo);

        UserDTO userDTO = userConverter.entity2dto(user);
        System.out.println(userDTO);
    }
}
/<code>
MapStruct(entity優雅的轉dto)



分享到:


相關文章: