java基础之mapstruct

PO,Persistent Object,持久对象,对应数据库表的对象模型。

DTO,Data Transfer Object,传输对象,前端发给后端的请求对象。

VO,View Object,视图对象,后端返回给前端的对象。

讲解一下最新的对象拷贝工具:mapstruct

经常看到的问题就是entity---->vo这种关系的赋值,也就是两个对象之间进行相互赋值的关系。

如果说两个对象的属性是相同的还好,如果是不同的,那么可能就非常麻烦的来进行转换了。

  • 加入依赖:
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.4.2.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.4.2.Final</version>
        </dependency>

然后在插件位置上进行配置:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <annotationProcessorPaths>
                        <!-- 必须要加, 否则生成不了 MapperImpl 实现类 -->
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>1.4.2.Final</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.20</version>
                        </path>
                        <!-- 如果是 0.1.0 有可能出现生成了maptruct的实现类, 但该类只创建了对象, 没有进行赋值 -->
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>0.2.0</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.guang.mapstruct.MapstructApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

然后编写两个类测试:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    private Integer id;
    private String name;
    private Double price;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductVO {
    private Integer id;
    private String name;
    private Double price;
}

然后编写一个接口:

import com.guang.mapstruct.pojo.Product;
import com.guang.mapstruct.pojo.ProductVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ProductMapper {

    ProductMapper mapper = Mappers.getMapper(ProductMapper.class);


    /**
     * 将product转换成productvo
     *
     * @param product
     * @return
     */
    @Mappings({
            @Mapping(source = "id", target = "id"),
            @Mapping(source = "name", target = "name"),
            @Mapping(source = "price", target = "price")
    })
    ProductVO product2VO(Product product);

}

编写测试代码:

    @Test
    void contextLoads() {
        Product product = new Product(1, "apple", 3.00);
        ProductVO productVO = ProductMapper.mapper.product2VO(product);
        System.out.println(productVO);
    }

控制台输出:

ProductVO(id=1, name=apple, price=3.0)

其实应用并非都是如此,还可以来给不同属性名字的类来进行赋值。

修改实体类属性之后:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    private Integer id;
    private String name;
    private Double price;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductVO {
    private Integer pid;
    private String pname;
    private Double price;
}
@Mapper
public interface ProductMapper {

    ProductMapper mapper = Mappers.getMapper(ProductMapper.class);


    /**
     * 将product转换成productvo
     *
     * @param product
     * @return
     */
    @Mappings({
            @Mapping(source = "id", target = "pid"),
            @Mapping(source = "name", target = "pname"),
            @Mapping(source = "price", target = "price")
    })
    ProductVO product2VO(Product product);

}

结果发现控制台还是一样的。

那么我们查看一下对应的实现类:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-11-01T01:31:14+0800",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_301 (Oracle Corporation)"
)
public class ProductMapperImpl implements ProductMapper {

    @Override
    public ProductVO product2VO(Product product) {
        if ( product == null ) {
            return null;
        }

        ProductVO productVO = new ProductVO();

        productVO.setPid( product.getId() );
        productVO.setPname( product.getName() );
        productVO.setPrice( product.getPrice() );

        return productVO;
    }
}

从这里可以看出来也是非常的简单的操作。

再来试一个:

@Mapper
public interface ProductMapper {

    ProductMapper mapper = Mappers.getMapper(ProductMapper.class);


    /**
     * 将product转换成productvo
     *
     * @param product
     * @return
     */
    @Mappings({
            @Mapping(source = "id", target = "pid"),
            @Mapping(source = "name", target = "pname"),
            @Mapping(source = "price", target = "price")
    })
    ProductVO product2VO(Product product);

    /**
     * 集合转换成集合操作
     * @param productList
     * @return
     */
    List<ProductVO> list2VO(List<Product> productList);

}

测试方法:

    @Test
    public void testList2List(){
        List<Product> productList = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            productList.add(new Product(i,"apple"+i,3.00));
        }
        List<ProductVO> productVOS = ProductMapper.mapper.list2VO(productList);
        for (ProductVO productVO : productVOS) {
            productVO.setPid(7);
            System.out.println(productVO);
        }
        System.out.println("-----------------");
        productList.forEach(System.out::println);
    }

控制台打印:

ProductVO(pid=7, pname=apple0, price=3.0)
ProductVO(pid=7, pname=apple1, price=3.0)
ProductVO(pid=7, pname=apple2, price=3.0)
ProductVO(pid=7, pname=apple3, price=3.0)
ProductVO(pid=7, pname=apple4, price=3.0)
ProductVO(pid=7, pname=apple5, price=3.0)
-----------------
Product(id=0, name=apple0, price=3.0)
Product(id=1, name=apple1, price=3.0)
Product(id=2, name=apple2, price=3.0)
Product(id=3, name=apple3, price=3.0)
Product(id=4, name=apple4, price=3.0)
Product(id=5, name=apple5, price=3.0)

那么看一下具体的实现类:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-11-01T01:46:02+0800",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_301 (Oracle Corporation)"
)
public class ProductMapperImpl implements ProductMapper {

    @Override
    public ProductVO product2VO(Product product) {
        if ( product == null ) {
            return null;
        }

        ProductVO productVO = new ProductVO();

        productVO.setPid( product.getId() );
        productVO.setPname( product.getName() );
        productVO.setPrice( product.getPrice() );

        return productVO;
    }

    @Override
    public List<ProductVO> list2VO(List<Product> productList) {
        if ( productList == null ) {
            return null;
        }
		// 可以看到这里在循环的调用上面的方法来进行实现
        List<ProductVO> list = new ArrayList<ProductVO>( productList.size() );
        for ( Product product : productList ) {
            list.add( product2VO( product ) );
        }

        return list;
    }
}

除此之外,再见一个比较秀的操作:

将两个类合并成一个类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Category {
    private String type;
}


@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    private Integer id;
    private String name;
    private Double price;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderVO {
    private String orderType;
    private String name;
}



这里是想将Category中的type和Product中的name赋值给OrderVO中的属性中来

那么在Mapper中继续来进行配置

@Mapper
public interface ProductMapper {

    ProductMapper mapper = Mappers.getMapper(ProductMapper.class);


    /**
     * 将product转换成productvo
     *
     * @param product
     * @return
     */
    @Mappings({
            @Mapping(source = "id", target = "pid"),
            @Mapping(source = "name", target = "pname"),
            @Mapping(source = "price", target = "price")
    })
    ProductVO product2VO(Product product);

    /**
     * 集合转换成集合操作
     * @param productList
     * @return
     */
    List<ProductVO> list2VO(List<Product> productList);

    /**
     * 将Category中的category和Product中的product属性赋值给OrderVO
     * @param category
     * @param product
     * @return
     */
    @Mappings({
            @Mapping(source = "category.type",target = "orderType"),
            @Mapping(source = "product.name",target = "name")
    })
    OrderVO createVO(Category category,Product product);

}

那么测试一下:

    @Test
    public void testCreateOrderVO(){
        Category category = new Category("电子产品");
        Product product= new Product(1,"lianxiang",2.00);
        OrderVO orderVO = ProductMapper.mapper.createVO(category, product);
        System.out.println(orderVO);
    }

控制台输出打印:

OrderVO(orderType=电子产品, name=lianxiang)

看一下对应的实现类:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-11-01T02:00:52+0800",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_301 (Oracle Corporation)"
)
public class ProductMapperImpl implements ProductMapper {

    @Override
    public ProductVO product2VO(Product product) {
        if ( product == null ) {
            return null;
        }

        ProductVO productVO = new ProductVO();

        productVO.setPid( product.getId() );
        productVO.setPname( product.getName() );
        productVO.setPrice( product.getPrice() );

        return productVO;
    }

    @Override
    public List<ProductVO> list2VO(List<Product> productList) {
        if ( productList == null ) {
            return null;
        }

        List<ProductVO> list = new ArrayList<ProductVO>( productList.size() );
        for ( Product product : productList ) {
            list.add( product2VO( product ) );
        }

        return list;
    }

    @Override
    public OrderVO createVO(Category category, Product product) {
        if ( category == null && product == null ) {
            return null;
        }

        OrderVO orderVO = new OrderVO();

        if ( category != null ) {
            orderVO.setOrderType( category.getType() );
        }
        if ( product != null ) {
            orderVO.setName( product.getName() );
        }

        return orderVO;
    }
}

最后一个,转换的方法:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
    private Integer goodId;
    private String goodName;
    private Double goodPrice;
    /**
     * 0代表下架
     * 1代表正常
     */
    private Integer status;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductVO {
    private Integer pid;
    private String pname;
    private Double price;
    private Boolean status;
}

mapper接口编写:

@Mapper
public interface GoodsMapper {

    GoodsMapper mapper = Mappers.getMapper(GoodsMapper.class);

    @Mappings({
            @Mapping(source = "goodId", target = "pid"),
            @Mapping(source = "goodName", target = "pname"),
            @Mapping(source = "goodPrice", target = "price"),
            // 但是这里需要做一个转换操作
            @Mapping(source = "status", target = "status",qualifiedByName = "transfer")
    })
    ProductVO goods2VO(Goods goods);



    @Named("transfer")
    default Boolean transfer(Integer status) {
        return status == 1;
    }

}

编写对应的测试类:

    @Test
    public void testTransfer(){
        Goods goods = new Goods(1,"APPLE",2.13,0);
        ProductVO productVO = GoodsMapper.mapper.goods2VO(goods);
        System.out.println(productVO);
    }

对应的输出:

ProductVO(pid=1, pname=APPLE, price=2.13, status=false)
上一篇:Maven - 一篇带你理解 AnnotationProcessorPaths 使用


下一篇:丢弃掉那些BeanUtils工具类吧,MapStruct真香,mysql性能调优与架构设计PDF