MapStruct使用

1、首先创建一个maven项目

image

2、导入相关的依赖

注意:lombok的版本

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.qbb.mapstruct</groupId>
    <artifactId>mapstruct_demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <mapstruct.version>1.5.3.Final</mapstruct.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
    </dependencies>
</project>

3、准备相关测试类

VO >>>>>>>

CarVO

package com.qbb.vo;

import lombok.Data;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:47
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Data
@Accessors(chain = true)
public class CarVO {
    private Long id;
    private String code;
    private Double price;
    private String totalPrice;
    private String publishTime;
    private String brand;
    private Boolean hasPart;
    private DriverVO driverVO;
}

DriverVO

package com.qbb.vo;

import lombok.Data;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:49
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Data
@Accessors(chain = true)
public class DriverVO {
    private Long driverId;
    private String fullName;
}

PartVO

package com.qbb.vo;

import lombok.Data;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:54
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Data
@Accessors(chain = true)
public class PartVO {
    private Long partId;
    private String partName;
}

DTO >>>>>>>

CarDTO

package com.qbb.dto;

import lombok.Data;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:43
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Data
@Accessors(chain = true)
public class CarDTO {
    private Long id;
    private String code;
    private double price;
    private double totalPrice;
    private LocalDateTime publishTime;
    private String brand;
    private List<PartDTO> partDTOList;
    private DriverDTO driverDTO;
}

DriverDTO

package com.qbb.dto;

import lombok.Data;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:46
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Data
@Accessors(chain = true)
public class DriverDTO {
    private Long id;
    private String name;
}

PartDTO

package com.qbb.dto;

import lombok.Data;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:46
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Data
@Accessors(chain = true)
public class PartDTO {

    private Long partId;
    private String partName;
}

4、案例

(1) 默认映射@Mapper

先创建一个convert

package com.qbb.convert;

import com.qbb.dto.CarDTO;
import com.qbb.vo.CarVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:59
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Mapper
public interface CarConvert {
    //
    CarConvert CONVERT = Mappers.getMapper(CarConvert.class);

    /**
     * dto ---> vo
     *
     * @param carDTO
     * @return
     */
    CarVO dto2vo(CarDTO carDTO);
}

CarTest测试

package com.qbb;

import com.qbb.convert.CarConvert;
import com.qbb.dto.CarDTO;
import com.qbb.dto.DriverDTO;
import com.qbb.dto.PartDTO;
import com.qbb.vo.CarVO;
import org.junit.Test;

import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  22:05
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
public class CarTest {
    @Test
    public void test01() {
        CarDTO carDTO = new CarDTO();
        carDTO.setId(999L);
        carDTO.setCode("123321");
        carDTO.setPrice(199999.999D);
        carDTO.setTotalPrice(999999.99D);
        carDTO.setPublishTime(LocalDateTime.now());
        carDTO.setBrand("奔驰");
        carDTO.setPartDTOList(Arrays.asList(new PartDTO().setPartId(1L).setPartName("零件1"),
                new PartDTO().setPartId(2L).setPartName("零件2")));
        carDTO.setDriverDTO(new DriverDTO().setId(1L).setName("张三"));

        CarVO carVO = CarConvert.CONVERT.dto2vo(carDTO);
        System.out.println("carVO = " + carVO);
    }
}

结果
image

默认映射规则
- 同类型同名的属性自动映射
- mapstruct会进行自动类型转换
	- 8中基本类型和对应的包装类之间
	- 8中基本类型(包装类)和String之间
	- 日期和String之间

(2) @Mappings、@Mapping

在CarDTO和CarVO中加入几个测试属性
CarDTO

private String color;
private Boolean status;

CarVO

private String color;
private Integer stat;

测试

package com.qbb.convert;

import com.qbb.dto.CarDTO;
import com.qbb.dto.DriverDTO;
import com.qbb.vo.CarVO;
import com.qbb.vo.DriverVO;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;

import java.util.List;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @date 2022-11-14  21:59
 * @tags 我爱的人在很远的地方, 我必须更加努力
 */
@Mapper
public interface CarConvert {
    //
    CarConvert CONVERT = Mappers.getMapper(CarConvert.class);

    /**
     * dto ---> vo
     *
     * @param carDTO
     * @return
     */
    @Mappings({
            @Mapping(source = "totalPrice", target = "totalPrice", numberFormat = "#.0"), // 指定格式化规则
            @Mapping(source = "publishTime", target = "publishTime", dateFormat = "yyyy-MM-dd HH:mm:ss"), // 指定日期格式化
            @Mapping(target = "color", ignore = true), // 忽略某个字段映射
            //@Mapping(source = "brand",target = "brandName"), // 字段名不一致映射
            @Mapping(source = "driverDTO", target = "driverVO"), // 引用对象的映射 使用到下面的方法 driverDTO2DriverVO
            @Mapping(source = "status", target = "stat", qualifiedByName = "boolean2Integer") // 自定义映射
    })
    CarVO dto2vo(CarDTO carDTO);

    /**
     * DriverDTO ---> DriverVO
     *
     * @param driverDTO
     * @return
     */
    @Mapping(source = "id", target = "driverId")
    @Mapping(source = "name", target = "fullName")
    DriverVO driverDTO2DriverVO(DriverDTO driverDTO);

    /**
     * 自定义映射
     *
     * @return
     */
    @Named("boolean2Integer")
    default Integer boolean2Integer(Boolean bool) {
        if (bool) return 1;
        return 0;
    }

    /**
     * 自定义映射2
     */
    @AfterMapping // @AfterMapping表示自动转换方法完成后,自动调用本方法
    default void dto2voAfter(CarDTO carDTO, @MappingTarget CarVO carVO) { // @MappingTarget表示CarVO是已经赋值了的
        if (carDTO.getStatus()) carVO.setStat(1);
        else carVO.setStat(0);
    }

    /**
     * 批量转换
     *
     * @param carDTOS
     * @return
     */
    @BeanMapping(ignoreByDefault = true) // 忽略默认映射,只映射@Mapping指定的映射
    @Mapping(source = "id", target = "id")
    List<CarVO> lsitDTO2ListVO(List<CarDTO> carDTOS);
}

5、@MappingTarget用法

我们使用@mapping时,转换器给帮我们new一个对象,这样的话源对象的属性会丢失。。。这就很尴尬~所以MapStruct提供了@MappingTarget注解解决这个问题

// 使用@mapping时,转换器给帮我们new一个对象
@Override
    public DeptVO deptToDeptVO(Dept dept) {
        if ( dept == null ) {
            return null;
        }
		// 尴尬点~~~~
        DeptVO deptVO = new DeptVO();

        deptVO.setDeptId( dept.getDeptId() );
        deptVO.setDeptName( dept.getDeptName() );
        deptVO.setStaff( dept.getStaff() );
        deptVO.setTel( dept.getTel() );
        deptVO.setDeleted( dept.getDeleted() );
        deptVO.setVersion( dept.getVersion() );
        deptVO.setGmtCreate( dept.getGmtCreate() );
        deptVO.setGmtModified( dept.getGmtModified() );

        return deptVO;
    }

例如:
我想把部门dept中的部门名和部门id等等属性转换到UserVO中

/**
     * 追加更新属性
     * 可以有返回值也可以无返回值
     *
     * @param userVO 源对象
     * @param dept
     */
UserVO appendAttrToUserVO(Dept dept, @MappingTarget UserVO userVO);

转换器生成的代码

@Override
    public UserVO appendAttrToUserVO(Dept dept, UserVO userVO) {
        if ( dept == null ) {
            return userVO;
        }

        userVO.setDeptId( dept.getDeptId() );
        userVO.setDeleted( dept.getDeleted() );
        userVO.setVersion( dept.getVersion() );
        userVO.setGmtCreate( dept.getGmtCreate() );
        userVO.setGmtModified( dept.getGmtModified() );
        userVO.setDeptName( dept.getDeptName() );
        userVO.setStaff( dept.getStaff() );
        userVO.setTel( dept.getTel() );

        return userVO;
    }

结果:

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "userId": 1,
    "userName": "1665646693248",
    "age": 1,
    "email": "ab@c.c",
    "deptId": 10,
    "deleted": false,
    "version": 4,
    "gmtCreate": "2020-10-30 03:48:19",
    "gmtModified": "2022-10-13 07:36:20",
    "deptName": "1665646580778",
    "staff": 20,
    "tel": "88886666"
  }
}

注意:@MappingTarget注解没有任何属性,source bean(源对象) 和 target bean(目标对象) 的属性必须一致,才能映射,否则不会映射,但也不报错!!! 当然如果,可以自定义方法转换,参考上面的

6、与Spring整合

与Spring整合非常容易,主需要在注解中加入一个属性,其实就是给他帮我们生成的实现类上加入了一个@Component,所以我们后面就可以使用@Autowired @Resource注入即可

@Mapper(componentModel = "spring")

代码仓库:https://gitee.com/Ybbit/map-struct.git

posted @   我也有梦想呀  阅读(87)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示