POJO转VO,让你不再痛苦

作者: jerrik | 来源:发表于2018-12-20 15:51 被阅读10次

    在开始之前,我们来说一说传统的代码开发风格:
            首先,我们要有dao、service、controller三层结构。dao用来操作DB,service层封装具体的业务逻辑,Controller层面向前端页面。复杂点的项目会引入一个bo层,也就是dao和service的中间层。比如单表的一些相对复杂的操作封装在bo里,service层只处理实体与实体之间的关系。
            当我们需要在前端页面展示多个实体数据的时候,我们是这样做的:
    1.新建一个vo对象
    2.vo对象包含我们所需要返回的实体属性
    3.然后通过各类properties copy工具来复制属性
    过程非常的无聊、甚至痛苦,但是又毫无办法。
    得益于有了mapStruct这个组件,让pojo转vo不在痛苦。

    一、mapStruct环境准备

    导入依赖,一般是结合lombok一起使用,不然略显单调(lombok的使用说明可以查看之前文章):

            <dependency>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-jdk8</artifactId>
                <version>1.2.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.2.0.Final</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.18</version>
            </dependency>
    

    其实还有另外一种方式,就是基于maven插件的做法,就可以不用导入mapstruct-processor了。

         <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.5.1</version>
               <configuration>
                   <source>${java.version}</source>
                   <target>${java.version}</target>
                   <encoding>${java.encoding}</encoding>
                   <annotationProcessorPaths>
                       <path>
                           <groupId>org.mapstruct</groupId>
                           <artifactId>mapstruct-processor</artifactId>
                           <version>${org.mapstruct.version}</version>
                       </path>
                   </annotationProcessorPaths>
               </configuration>
        </plugin>
    

    但是一般还是使用的第一种方式。
    然后在idea->settings->annotation processors->启用注解处理


    二、使用

    准备一个Goods 对象和User对象:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public class Goods {
        private Integer id;
        private String descs;
        private double prices;
        private String name;
        private String about;
    }
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public class User {
        private int userId;
        private String userName;
        private int age;
        private String description;
    }
    

    现在我需要拿到商品和用户信息,只需要新建一个DTO--GoodsInfoDTO:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    @ToString
    public class GoodsInfoDto {
        private Integer goodsId;
        private String descs;
        private double goodsPrices;
        private String goodsName;
        private String about;
        private int userId;
        private String userName;
        private int age;
        private String userDescs;
    }
    

    然后一个一个的set属性吗?NO,来看mapStruct怎么做的。
    新建一个converter类,名字随意,我这里叫GoodsInfoConverter

    @Mapper
    public interface GoodsInfoConverter {
        GoodsInfoConverter INSTANCE = Mappers.getMapper(GoodsInfoConverter.class);
        @Mappings({@Mapping(source = "goods.id", target = "goodsId"),
                @Mapping(source = "goods.prices", target = "goodsPrices"),
            @Mapping(source = "goods.name",target = "goodsName"),
            @Mapping(source = "user.description",target = "userDescs"),
        }
        )
        public GoodsInfoDto goods2GoodsInfoDto(Goods goods, User user);
    }
    

    其中的GoodsInfoConverter INSTANCE = Mappers.getMapper(GoodsInfoConverter.class);必不可少,类似于一个SPI接口,就可以让你再客户端通过GoodsInfoConverter.INSTANCE获取到它的实例。
    下面的@Mappings就是对象-DTO之间的映射关系,这里要转换goodsuser对象到DTO,所以传入了两个参数。其中的source是需要转换的对象属性,如果有多个对象需要转换,则需要在前面加入对应的对象名,例如goods.id,用过hibernate的同学会觉得格外小清新~.其中的target是DTO中的属性名,如果需要转换的对象和DTO属性名相同,则不需要配置。还有一些其它参数,我就不一一介绍了。

    最重要的一步,就是编译,mvn clean一下:
    你会发现在target目录的generated-sources下会生成一个GoodsInfoConverterImpl:

    @Generated(
        value = "org.mapstruct.ap.MappingProcessor",
        date = "2018-12-20T15:44:31+0800",
        comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_181 (Oracle Corporation)"
    )
    public class GoodsInfoConverterImpl implements GoodsInfoConverter {
    
        @Override
        public GoodsInfoDto goods2GoodsInfoDto(Goods goods, User user) {
            if ( goods == null && user == null ) {
                return null;
            }
    
            GoodsInfoDto goodsInfoDto = new GoodsInfoDto();
    
            if ( goods != null ) {
                goodsInfoDto.setGoodsPrices( goods.getPrices() );
                goodsInfoDto.setGoodsName( goods.getName() );
                goodsInfoDto.setGoodsId( goods.getId() );
                goodsInfoDto.setDescs( goods.getDescs() );
                goodsInfoDto.setAbout( goods.getAbout() );
            }
            if ( user != null ) {
                goodsInfoDto.setUserDescs( user.getDescription() );
                goodsInfoDto.setUserId( user.getUserId() );
                goodsInfoDto.setUserName( user.getUserName() );
                goodsInfoDto.setAge( user.getAge() );
            }
    
            return goodsInfoDto;
        }
    }
    

    完全是自动生成的,你不需要管。当我们mvn打包的时候会自动将该文件打包进去。
    客户端怎么使用呢?来看一下:

            Goods goods = new Goods();
            goods.setId(3);
            goods.setDescs("飞机");
            goods.setPrices(32000.0D);
            goods.setName("无人机");
    
            User user = new User();
            user.setUserId(13581);
            user.setUserName("jerrik");
            user.setAge(25);
            user.setDescription("帅小伙");
    
            GoodsInfoDto goodsInfoDto = GoodsInfoConverter.INSTANCE.goods2GoodsInfoDto(goods,user);
            System.out.println(goodsInfoDto);
    
    //GoodsInfoDto(goodsId=3, descs=飞机, goodsPrices=32000.0, goodsName=无人机, about=null, userId=13581, userName=jerrik, age=25, userDescs=帅小伙)
    

    是不是很简单,而且省去了很多事,比bean copy的性能也要好。完全是基于set来实现的。

    三、注意事项

    mapStruct集成lombok时,lombok的版本设置成新版本吧。反正笔者1.16.8的lombok会报错,提示Mappings找不到映射的属性,1.16.18是可以编译通过的。如果你觉得这些还不够用,可以去查看官网,谢谢~

    相关文章

      网友评论

        本文标题:POJO转VO,让你不再痛苦

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