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);
    
posted @ 2020-03-31 22:31  mosakashaka  阅读(893)  评论(2编辑  收藏  举报