栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MapStruct使用小结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MapStruct使用小结

前言

实体bean转化往往是不可避免的,从传统使用反射技术的的BeanUtil的copyProperties到Object mapping,基本止步于使用Annontion Processer实现的动态编译生成字节码。因为其是编译期自动生成的set/get调用代码,运行期的性能接近手写赋值(性能对比可以参见文章:Java对象属性拷贝组件——对象映射器Object mapping)。其次使用注解的方式声明对象转化和拷贝比较简洁,就像lombok一样避免了大量的手工重复代码的编写。

这里要介绍的是mapstruct,已经在项目中使用了一段时间了,和Lombok一样基本已经离不开了。这从一个侧面反映了Java Bean目前对数据实体的定义和管理存在可进化的地方。比如在流程的分层设计中,隔离DAO、Service、Controller层的各种实体DO、DTO、Req/Res对象需要隔离,隔离带来互转问题。

  • 官网:https://mapstruct.org/
  • Github地址:https://github.com/mapstruct/mapstruct/
基本用法 引入依赖

mapstruct需要JDK1.8,引入mapstruct 的jar,其只在源码和编译期需要,运行期不依赖;

要注意的是 IntelliJ IDEA 版本需要 2018.2.x +,因为此版本后的IDEA才支持 annotationProcessors

Enable annotation processing in IntelliJ (Build, Execution, Deployment -> Compiler -> Annotation Processors)

记得在IDEA中开启annotationProcessors 支持

...

    1.4.2.Final

...

    
        org.mapstruct
        mapstruct
        ${mapstruct.version}
        true
    

...

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

...

如果同时使用lombok,就是如下的配置

...

   
    org.projectlombok
    lombok
    ${lombok.version}
  
  
    org.mapstruct
    mapstruct-processor
    ${mapstruct.version}
  

...

实体Bean举例如下:

@Data
public class User {
    private long id;
    private String name;
    private List
addresses; } @Data public class AddressDto { private String cityCode; private String cityName; } @Data public class UserDto { private long id; private String name; private List addresses; } @Data public class AddressDto { private String cityCode; private String cityName; }
定义对应映射的接口
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserCopier {
    UserCopier INSTANCE = Mappers.getMapper(UserCopier.class);

    @Mappings({})
    UserDto userToDtoUser(User user);

    List userToDtoUser(List list);

}
映射接口使用
User user = new User();
user.setId(1);
Address address = new Address();
address.setCityCode("10");
address.setCityName("beijing");
user.setAddresses(Arrays.asList(address));
UserDto userDto = UserCopier.INSTANCE.userToDtoUser(user);

// 拷贝List
List users ...
List list =  UserCopier.INSTANCE.userToDtoUser(users);

可以看一下编译后自动生成了 UserCopierImpl 类

public class UserCopierImpl implements UserCopier {
    public UserCopierImpl() {
    }

    public UserDto userToDtoUser(User user) {
        if (user == null) {
            return null;
        } else {
            UserDto userDto = new UserDto();
            userDto.setId(user.getId());
            userDto.setName(user.getName());
            userDto.setAddresses(this.addressListToAddressDtoList(user.getAddresses()));
            return userDto;
        }
    }

    public List userToDtoUser(List list) {
        if (list == null) {
            return null;
        } else {
            List list1 = new ArrayList(list.size());
            Iterator var3 = list.iterator();

            while(var3.hasNext()) {
                User user = (User)var3.next();
                list1.add(this.userToDtoUser(user));
            }

            return list1;
        }
    }

    protected AddressDto addressToAddressDto(Address address) {
        if (address == null) {
            return null;
        } else {
            AddressDto addressDto = new AddressDto();
            addressDto.setCityCode(address.getCityCode());
            addressDto.setCityName(address.getCityName());
            return addressDto;
        }
    }

    protected List addressListToAddressDtoList(List
list) { if (list == null) { return null; } else { List list1 = new ArrayList(list.size()); Iterator var3 = list.iterator(); while(var3.hasNext()) { Address address = (Address)var3.next(); list1.add(this.addressToAddressDto(address)); } return list1; } } }
其他常用特性使用 属性映射

可以指定源和目标的字段,用于源对象和目标对象的属性名称不同的时候;

@Mappings({
	@Mapping(source = "userName", target = "loginName")
})
UserDto userToDtoUser(UserReq user);

可以指定嵌套对象的属性映射

把源对象的addressCityName赋值到目标的address成员对象的cityName属性, 把源对象的account成员对象的所有所有属性赋值到目标对象下相同属性上。

@Mappings({
	@Mapping(source = "addressCityName", target = "address.cityName")
    @Mapping(source = "account", target = ".")
})
UserDto userToDtoUser(UserReq user);
类型转化

MapStruct在许多情况下自动处理类型转换。例如,如果一个属性在源bean中是int类型,但在目标bean中是String类型,那么生成的代码将通过分别调用String#valueOf(int)和Integer#parseInt(String)透明地执行转换。

在所有Java基本数据类型及其相应的包装类型之间,例如int和Integer、boolean和boolean等。生成的代码是空感知的,即当将包装类型转换为相应的基本类型时,将执行空检查。

数值与日期格式化
@Mapper
public interface CarMapper {

    @Mapping(source = "price", numberFormat = "$#.00")
    CarDto carToCarDto(Car car);

    @IterableMapping(numberFormat = "$#.00")
    List prices(List prices);
    
    @Mapping(source = "manufacturingDate", dateFormat = "dd.MM.yyyy")
    CarDto carToCarDto(Car car);

    @IterableMapping(dateFormat = "dd.MM.yyyy")
    List stringListToDateList(List dates);
}
表达式

在映射时可以通过expression调用Java代码,在最终自动生成的

@Mapper
public interface SourceTargetMapper {

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

    @Mapping(target = "timeAndFormat",
         expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}

更多详细的用法可以参见官网的使用文档。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/584957.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号