MapStruct使用學習


MapStruct通過一些接口定義,能自動生成實現類,將一個類轉換為另一個類。

引用

<properties>
    <org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

這個依賴有兩個問題

不支持lombok@Data等注解

如果接口引用的類通過@Data標記,由於標記生成getter/setter等方法,但是在生成mapstruct mapper類時看不到,會導致編譯找不到屬性的問題。

解決方法:引入mapstruct-processor,同時去掉plugin中的annotationProcessorPaths

...
    <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct-processor</artifactId>
      <version>1.3.1.Final</version>
      <scope>provided</scope>
    </dependency>
...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
...

Spring中無法通過@Autowired注入接口

這是因為生成的Mapper實現類,沒有被標注@Component,通過添加maven編譯參數defaultComponentModel可以解決:

...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <compilerArgs>
            <arg>-Amapstruct.defaultComponentModel=spring</arg>
          </compilerArgs>
        </configuration>
      </plugin>
...

修改以后,我在eclipse中沒有自動重新編譯,需要clean再重新編譯才生效。

引用Mapper

INSTANCE方式

接口中定義一個單例,其他地方引用,官方講的比較清楚:

@Mapper
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDto carToCarDto(Car car);
}
//引用Mapper
Car car = ...;
CarDto dto = CarMapper.INSTANCE.carToCarDto( car );

通過@Autowired依賴注入

需要前面配置的defaultComponentModel=spring,才能在代碼中注入:

@Autowired
CarMapper carMapper;

其實上面的配置時全局的,也可以在mapper定義中,增加標記:

@Mapper(componentModel = "spring")
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDto carToCarDto(Car car);
}

這樣也行,只不過需要一個一個的Mapper都添加,不是那么方便了。

使用

可以轉換復雜的結構類型,默認是同名的屬性進行轉換的。

按照官方文檔的說明,生成的Mapper代碼也是盡量符合手寫代碼,通過getter/setter設置,沒有使用反射,這也是為什么通過lombok添加getter/setter會生成不成功的原因。

也支持通過注解,將不同名字的類型進行自動轉換。

我實驗的代碼:

//源類型
@Data
public class TbUserCustomDO {
    private List<TbUser> users;

    private String fieldA;

    private String field2;
}
//TbUser也是一個自定義類
@Data
public class TbUser implements Serializable {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated
}	
//目的類
@Data
public class TbUserDemoDTO {
    private List<TbUserDTO> users;

    private String field1;

    private String field2;
}
//這里TbUserDTO與源類中的TbUser不完全相同(少一些字段),但是注意每個已有字段名稱是相同的
public class TbUserDTO {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
}	
//Mapper類
@Mapper
public interface TbUserCustomConverter {

    //這里把fieldA對應到field1,因為名稱不同
    @Mapping(source = "fieldA", target = "field1")
    TbUserDemoDTO doToDTO(TbUserCustomDO cDo);
}
    //注入Mapper
    @Autowired
    TbUserCustomConverter tbUserCustomConverter;
    ...
    //使用,這里List和屬性都能成功轉換
    TbUserCustomDO cDo = ...
    TbUserDemoDTO dto = tbUserCustomConverter.doToDTO(cDo);
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM