mapstruct使用与进阶

mapstruct

好久没有去写博客了,今天突然使用到了一些相对高级的mapstruct用法,所以总结一下。本篇文章带你走进mapstruct,从实际生产角度去灵活的使用这个强大的工具

置顶还是要贴上官网地址滴,毕竟官网是最详细的:mapstruct官网

1 什么是mapstruct

mapstruct是一个对象映射工具将对象相互转换。举个例子,如果你有使用过DTO、VO这些鬼东西那么你一定知道,在对象之间进行转换是一件比较麻烦的事情,下面构造两个对象,他们的属性如下所示,

public class UserVo{
    private String username;
    private String password;
    private String email;
}

public class UserDTO {
    private String username;
    private String email;
}

传统的方式我们会使用这些方法去实现这两个对象之间的转换:

  1. 构造对应的对象,例如new UserVo(),然后把UserDTO中的属性值一个个的setUserVo中去,这个过程有多痛苦就不用我多说了
  2. 再高级点的呢就是利用BeanUtils进行转换,例如BeanUtils.copyProperties(userVo,userDTO),省去了很多过程。但是BeanUtils是基于反射做的对象属性映射,效率是不高的
  3. 此时我们思考,有没有什么办法,去通过set的方式给对象赋值因为此方式比反射的效率要高,且程序员还不用去写那么多代码呢?于是mapstruct就来了

2 mapstruct基础使用

maven中pom.xml引入座标和插件

    <properties>
            <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
    </properties>

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

    <build>
        <plugins>
            <!-- <plugin>  如果是springboot项目就放开
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>-->
            <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>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

现在我们还是使用第一节构造的两个对象,来实现对象的转换,使用的方法比较简单,创建UserMapper接口

@Mapper(componentModel = "spring")   // 如果使用的是spring,那么mapstruct可以将自身添加到spring容器中,实现注入使用
public interface UserMapper {

    UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );	// 如果使用spring则不需要去实例化该对象,而是从容器中获取

    @Mappings({})
    UserVo dto2Vo(UserDTO userDTO);

    @Mappings({})
    UserDTO vo2DTO(UserVo userVo);
}

使用:UserDTO to UserVo

public class Test {
    public static void main(String[] args) {
		UserDTO userDTO = new UserDTO("username","password","email");
        System.out.println(UserMapper.INSTANCE.dto2Vo(userDTO))
    }
}
// 输出结果为username: 'username',email:'email'

如果是UserVo转换为UserDTO呢,因为UserVo的字段是比UserDTO字段少的,所以UserDTOpassword属性为null

如果你细心的话,你会看到在你的target目录下,自动编译生成了UserMapperImpl.class,打开看看你就知道了其中的道理

3 高级使用

3.1 @Mapping注解

在上述的例子我们是没有写@Mapping注解的,用一个空数组代替了,其实实际使用的时候我们免不了要去编写@Mapping注解去自定义目标字段的映射操作。

@Mapping少不了的就是target属性,意思是目标字段

下面举个例子更方便的理解,javabean如下,为了便于理解source和target属性我对字段名进行了区分:

public class CarDTO{
    private String brand;
    private Double price;
    private User user;
}

public class CarVO {
    private String voBrand;
    private Double voPrice;
    private String customer;	// 购买人
}

public class User {
    private String username;
    private Integer age;
}

还是将CarDTO转换为CarVo,我们编写一个CarMapper类,这时候如果不使用@Mapping注解就无法很好的将属性进行赋值了:

@Mapper(componentModel = "spring")   // 如果使用的是spring,那么mapstruct可以将自身添加到spring容器中,实现注入使用
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );	// 如果使用spring则不需要去实例化该对象,而是从容器中获取

    @Mappings({
        @Mapping(source = "brand",target = "voBrand"),
        @Mapping(source = "price",target = "voPrice"),
        @Mapping(source = "user.username",target = "customer")
    })
    CarVo dto2Vo(CarDTO carDTO);

}

通过上述的例子就可以实现CarDTO到CarVo的转换操作,这是一种比较常见的情况,没有其他的操作只是多了一层嵌套

3.2 Java Expression

@Mapping还有一个属性十分重要就是expression,通过expression可以更灵活的对字段进行转换操作。

可以通过expression="java()"的方式去调用java代码,例如调用某个utils的方法,我们可以这样使用expression=java(com.github.test.Utils.getValue())

举个例子,例如我们需要对的UserVocustomer字段值进行一个逻辑判断,如果年龄大于18就返回成年人,否则返回未成年。这时候我们就不得不使用expression来进行操作啦,语法格式也是很简单。直接看代码如下所示:

记住target属性是必须的

@Mapper(componentModel = "spring")   // 如果使用的是spring,那么mapstruct可以将自身添加到spring容器中,实现注入使用
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );	// 如果使用spring则不需要去实例化该对象,而是从容器中获取

    @Mappings({
        @Mapping(source = "brand",target = "voBrand"),
        @Mapping(source = "price",target = "voPrice"),
        @Mapping(expression = "java(CarMapper.getCustomer(carDTO.getUser().getAge()))",target = "customer")
    })
    CarVo dto2Vo(CarDTO carDTO);

    static String getCustomer(Integer age) {
        return age>18 ? "成年人" : "未成年";
    }

}

3.3 可能遇到的问题

使用的时候不遇到问题是不可能的,你可能会遇到:

  • 在有多个返回类型为同一类型,输入参数为同一类型时,例如String getUsername(String username)String getPassword(String password)这两个方法,你在编译的时候就会报错。因为你没有标识它们,mapstruct提供了@Named注解,根据名称去区分不同的方法从而实现编译,然后引用的时候使用qualifiedByName属性进行使用,如下所示:
@Mapper(componentModel = "spring")   // 如果使用的是spring,那么mapstruct可以将自身添加到spring容器中,实现注入使用
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );	// 如果使用spring则不需要去实例化该对象,而是从容器中获取

    @Mappings({
        @Mapping(source = "brand",target = "voBrand"),
        @Mapping(source = "price",target = "voPrice"),
        @Mapping(target = "customer", source="age" ,qualifiedByName = "customer")
    })
    CarVo dto2Vo(CarDTO carDTO);

    @Named("customer")
    static String getCustomer(Integer age) {
        return age>18 ? "成年人" : "未成年";
    }

    @Named("brand")
    static String getBrand(Integer age) {	// 随意举的例子,造成入参和返回值都是同一类型的情况
        return "hahah";
    }

}

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java MapStruct是一个代码生成器,用于处理Java bean之间的映射。它通过在编译时生成映射代码来提高性能,并且可以自定义映射逻辑。以下是使用Java MapStruct的步骤: 1. 添加MapStruct依赖项到Maven或Gradle项目中。 2. 创建一个Java接口,该接口定义了要映射的源和目标bean之间的映射方法。 3. 在接口上使用@Mapper注释,指定MapStruct生成的实现类的名称。 4. 在映射方法上使用@Mapping注释,指定源和目标bean属性之间的映射关系。 5. 在Maven或Gradle项目中运行编译命令,以生成MapStruct实现类。 6. 在代码中使用MapStruct生成的实现类来执行bean之间的映射。 下面是一个使用Java MapStruct的简单示例: 1. 添加MapStruct依赖项到Maven或Gradle项目中。 ```xml <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-jdk8</artifactId> <version>1.4.2.Final</version> </dependency> ``` 2. 创建一个Java接口,该接口定义了要映射的源和目标bean之间的映射方法。 ```java @Mapper public interface CarMapper { CarDto carToCarDto(Car car); } ``` 3. 在接口上使用@Mapper注释,指定MapStruct生成的实现类的名称。 ```java @Mapper(componentModel = "spring") public interface CarMapper { CarDto carToCarDto(Car car); } ``` 4. 在映射方法上使用@Mapping注释,指定源和目标bean属性之间的映射关系。 ```java @Mapper(componentModel = "spring") public interface CarMapper { @Mapping(source = "numberOfSeats", target = "seatCount") CarDto carToCarDto(Car car); } ``` 5. 在Maven或Gradle项目中运行编译命令,以生成MapStruct实现类。 6. 在代码中使用MapStruct生成的实现类来执行bean之间的映射。 ```java @Autowired private CarMapper carMapper; public void example() { Car car = new Car("Morris", 5); CarDto carDto = carMapper.carToCarDto(car); } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值