美文网首页
如何优雅的转换对象

如何优雅的转换对象

作者: bailiyi | 来源:发表于2020-01-20 19:56 被阅读0次

    什么是样板代码

    样板代码就是那些和主要逻辑无关,却又不得不写的代码.
    比如一段常见的实体类映射代码:

        public User toUser(UserAddr addr, UserInfo info) {
            User user = new User();
            user.setAddr( addr.getAddress() );
            user.setCountry( addr.getCountry() );
            user.setCity( addr.getCity() );
            user.setName( info.getNameCn() );
            user.setAge( info.getAge() );
            return user;
        }
    

    我们想把某个对象的属性赋值给另一个对象时,不可避免的要写上一大堆get/set之类的操作.
    就算使用BeanUtils.copyProperties()方法,也只能消除同名属性的get/set操作.
    那有没有一种方法,可以完全消除这种样板代码呢?
    有的.

    使用mapstruct的效果

    先不说怎么用,咱们先看看效果,觉得有用,咱们再往下看.
    首先,写一个映射接口

    @Mapper(componentModel = "spring")
    public interface UserDOMapper {
        @Mapping(source = "info.nameCn",target = "name")
        @Mapping(source = "addr.address",target = "addr")
        User toUser(UserAddr addr, UserInfo info);
    }
    

    然后就可以使用了

    @Autowired
    private UserDOMapper userDOMapper;
    public User toUser(UserAddr addr, UserInfo info) {
        return userDOMapper.toUser(addr,info);
    }
        
    

    修改前后的toUser作用完全相同,这效果可还行?

    mapstruct的简单使用

    引入依赖

    <properties>
            <org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
    </properties>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-jdk8</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
    

    编写映射器:产生新对象

    @Mapper(componentModel = "spring")
    public interface UserDOMapper {
        @Mapping(source = "info.nameCn",target = "name")
        @Mapping(source = "addr.address",target = "addr")
        User toUser(UserAddr addr, UserInfo info);
    }
    

    如果是要产生新对象,可以按照如上写法编写映射器.
    source表示数据来源,target表示要赋值的变量.
    比如@Mapping(source = "addr.address",target = "addr")就表示,把入参addr的address变量的值,赋值给User中的addr变量.
    看下UserAddr和User定义会更清楚些:

    public class UserAddr {
        private String country;
        private String city;
        private String address;
        ...
    }
    
    public class User {
        private String name;
        private Integer age;
        private String country;
        private String city;
        private String addr;
        ...
    }
    

    如果是变量的名字和数据类型都相同,则不需要显示的声明映射关系,默认会给复制.

    编写映射器:给对象填充值

    如果是要给已存在的对象填充值,可以按照下面这样写:

        @Mapping(source = "addr.address",target = "addr")
        void fillUser(UserAddr addr,@MappingTarget User user);
    

    @MappingTarget表示被填充的对象.
    其他规则还是跟之前一样

    原理

    看完了使用,咱们来看下mapstruct是怎么做到这些事的.
    实际上,mapstruct是一个代码生成器,在编译项目的时候,它会为映射器生成实现类.
    比如下面这个映射器:

    @Mapper(componentModel = "spring")
    public interface UserDOMapper {
        @Mapping(source = "info.nameCn",target = "name")
        @Mapping(source = "addr.address",target = "addr")
        User toUser(UserAddr addr, UserInfo info);
    }
    

    在编译之后,会在target中生成如下实现类:

    @Component
    public class UserDOMapperImpl implements UserDOMapper {
    
        @Override
        public User toUser(UserAddr addr, UserInfo info) {
            if ( addr == null && info == null ) {
                return null;
            }
    
            User user = new User();
    
            if ( addr != null ) {
                user.setAddr( addr.getAddress() );
                user.setCountry( addr.getCountry() );
                user.setCity( addr.getCity() );
            }
            if ( info != null ) {
                user.setName( info.getNameCn() );
                user.setAge( info.getAge() );
            }
    
            return user;
        }
    }
    

    总结

    本次向大家介绍了一种减少样板代码,提高开发效率的工具mapstruct
    其本质是一个代码生成器
    相比使用反射的BeanUtils.copyProperties()而言,mapstruct的效率更高,代码可追溯性也更好.
    推荐大家使用.
    更多用法请见官方文档,十分详细且易读
    https://mapstruct.org/documentation/reference-guide/

    系列文章总目录:https://mp.weixin.qq.com/s/56JgXLArTAEDj1f3y4arLA

    相关文章

      网友评论

          本文标题:如何优雅的转换对象

          本文链接:https://www.haomeiwen.com/subject/hwfszctx.html