java对象间的关系映射工具-mapstruct的使用

1.前言

在现在一个多模块的系统中,随着系统的不断迭代,导致各个系统之间的model 不断地增多。如DTO VO BO 等多个对象之间的属性拷贝就是一个不小的工作量。

当然可选的方案还有beanutils(注意使用Spring的,Apache的性能很差),但是BeanUtils只能拷贝同属性的当遇到被映射的属性数据类型被修改或者被映射的字段名被修改,则会导致映射失败。而 mapstruct 就是把我们可能会遇到的情况都给考虑到了。所以MapStruct更加好用。

官方文档
  • Github地址:https://github.com/mapstruct/mapstruct/
  • 使用例子:https://github.com/mapstruct/mapstruct-examples

2.使用教程

2.1 了解 @Mapper注解

@Mapper 注解的 componentModel 属性,componentModel 属性用于指定自动生成的接口实现类的组件类型,这个属性支持四个值:

  • default: 这是默认的情况,mapstruct 不使用任何组件类型, 可以通过Mappers.getMapper(Class)方式获取自动生成的实例对象。
  • cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
  • spring: 生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入
  • jsr330: 生成的实现类上会添加@javax.inject.Named 和@Singleton注解,可以通过 @Inject注解获取

2.2具体使用

引入依赖
<dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <!-- jdk8以下就使用mapstruct 带 jdk8可以使用jdk8的一些新特性 -->
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.3.0.Final</version>
        </dependency>

            <!--  注解处理器,根据注解自动生成mapper的实现。 -->
            <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.3.0.Final</version>
        </dependency>

    </dependencies>
编写Mapper接口
  • 编写bean

这里我们编写几个bean、vo等用来进行测试。

// 实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    private Integer id;
    private String name;
    private String createTime;
    private LocalDateTime updateTime;
}

// 需要转换的类型一
// 被映射类VO1:和实体类部分字段不一致
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO1 {
    private Integer id;
    private String userName;
    private String crTime;
    private LocalDateTime updateTime;

}
// 需要转换的类型二
// 被映射类VO2:比实体类少一个字段
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO2 {
    private Integer id;
    private String name;
    private String createTime;

}

注意:下面指定类型为SpringUserCovertBasic MAPPER = Mappers.getMapper(UserCovertBasic.class);

这两种方式取一个即可。第一种则可以直接@Autowrid,而后者可以直接调用UserCovertBasic.MAPPER使用。

// 编写转换接口
@Mapper(componentModel = "spring")
public interface UserCovertBasic {
    UserCovertBasic MAPPER = Mappers.getMapper(UserCovertBasic.class);

    /**
     * 不一致的字段 通过 注解转换
     * User --> UserV01
     * @return
     */
    @Mappings({
            @Mapping(target = "userName", source = "name"),
            @Mapping(target = "crTime", source = "createTime")
    })
    UserVO1 toConvertVO1(User source);

    /**
     * 不一致的字段 通过 注解转换
     * User V01 --> User
     * @return
     */
    @Mappings({
            @Mapping(target = "name", source = "userName"),
            @Mapping(target = "createTime", source = "crTime")
    })
    User fromConvertEntity1(UserVO1 userVO1);

    /**
     * 字段数量类型相同,只是字段多,可以直接转换
     * @param source
     * @return
     */
    UserVO2 toConvertVO2(User source);

    /**
     * 字段多的转为少的
     * @param source
     * @return
     */
    UserVO2 fromConvertEntity(UserVO2 source);

}

编写测试入口
package com.njit.mapstruct.web;

import com.njit.mapstruct.bean.User;
import com.njit.mapstruct.bean.UserVO1;
import com.njit.mapstruct.bean.UserVO2;
import com.njit.mapstruct.mapper.UserCovertBasic;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class TestController {

    @Autowired
    private UserCovertBasic userCovertBasic;

    @GetMapping("convert")
    public Object convertEntity() {

        User user1 = new User();

        user1.setId(1);
        user1.setName("zyd");
        user1.setCreateTime("2020-04-01 11:05:07");
        user1.setUpdateTime(LocalDateTime.now());
        List<Object> objectList = new ArrayList<>();

        objectList.add(user1);

        // 使用mapstruct
        UserVO1 userVO1 = userCovertBasic.toConvertVO1(user1);
        objectList.add("userVO1:" + userCovertBasic.toConvertVO1(user1));
        objectList.add("userVO1转换回实体类user:" + userCovertBasic.fromConvertEntity1(userVO1));

        // 输出转换结果
        UserVO2 userVO2 = userCovertBasic.toConvertVO2(user1);
        objectList.add("userVO2:" + " | " + userCovertBasic.toConvertVO2(user1));
        objectList.add("userVO2转换回实体类user:" + " | " + userCovertBasic.fromConvertEntity(userVO2));

        // 使用BeanUtils
        UserVO2 userVO22 = new UserVO2();
        BeanUtils.copyProperties(user1, userVO22);
        objectList.add("userVO22:" + " | " + userVO22);

        return objectList;
    }
}

启动测试
package com.njit.mapstruct.web;

import com.njit.mapstruct.bean.User;
import com.njit.mapstruct.bean.UserVO1;
import com.njit.mapstruct.bean.UserVO2;
import com.njit.mapstruct.mapper.UserCovertBasic;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class TestController {

    @Autowired
    private UserCovertBasic userCovertBasic;

    @GetMapping("convert")
    public Object convertEntity() {

        User user1 = new User();

        user1.setId(1);
        user1.setName("zyd");
        user1.setCreateTime("2020-04-01 11:05:07");
        user1.setUpdateTime(LocalDateTime.now());
        List<Object> objectList = new ArrayList<>();

        objectList.add(user1);

        // 使用mapstruct
        UserVO1 userVO1 = userCovertBasic.toConvertVO1(user1);
        objectList.add("userVO1:" + userCovertBasic.toConvertVO1(user1));
        objectList.add("userVO1转换回实体类user:" + userCovertBasic.fromConvertEntity1(userVO1));

        // 输出转换结果
        UserVO2 userVO2 = userCovertBasic.toConvertVO2(user1);
        objectList.add("userVO2:" + " | " + userCovertBasic.toConvertVO2(user1));
        objectList.add("userVO2转换回实体类user:" + " | " + userCovertBasic.fromConvertEntity(userVO2));

        // 使用BeanUtils
        UserVO2 userVO22 = new UserVO2();
        BeanUtils.copyProperties(user1, userVO22);
        objectList.add("userVO22:" + " | " + userVO22);

        return objectList;
    }
}

返回值
[{"id":1,"name":"zyd","createTime":"2020-04-01 11:05:07","updateTime":"2021-07-05T23:02:51.624"},"userVO1:UserVO1(id=1, userName=zyd, crTime=2020-04-01 11:05:07, updateTime=2021-07-05T23:02:51.624)","userVO1转换回实体类user:User(id=1, name=zyd, createTime=2020-04-01 11:05:07, updateTime=2021-07-05T23:02:51.624)","userVO2: | UserVO2(id=1, name=zyd, createTime=2020-04-01 11:05:07)","userVO2转换回实体类user: | UserVO2(id=1, name=zyd, createTime=2020-04-01 11:05:07)","userVO22: | UserVO2(id=1, name=zyd, createTime=2020-04-01 11:05:07)"]

我们点开接口,可以看到自动生成的实现类

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-07-05T23:02:27+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_231 (Oracle Corporation)"
)
@Component
public class UserCovertBasicImpl implements UserCovertBasic {

    @Override
    public UserVO1 toConvertVO1(User source) {
        if ( source == null ) {
            return null;
        }

        UserVO1Builder userVO1 = UserVO1.builder();

        userVO1.userName( source.getName() );
        userVO1.crTime( source.getCreateTime() );
        userVO1.id( source.getId() );
        userVO1.updateTime( source.getUpdateTime() );

        return userVO1.build();
    }

    @Override
    public User fromConvertEntity1(UserVO1 userVO1) {
        if ( userVO1 == null ) {
            return null;
        }

        UserBuilder user = User.builder();

        user.name( userVO1.getUserName() );
        user.createTime( userVO1.getCrTime() );
        user.id( userVO1.getId() );
        user.updateTime( userVO1.getUpdateTime() );

        return user.build();
    }

    @Override
    public UserVO2 toConvertVO2(User source) {
        if ( source == null ) {
            return null;
        }

        UserVO2Builder userVO2 = UserVO2.builder();

        userVO2.id( source.getId() );
        userVO2.name( source.getName() );
        userVO2.createTime( source.getCreateTime() );

        return userVO2.build();
    }

    @Override
    public UserVO2 fromConvertEntity(UserVO2 source) {
        if ( source == null ) {
            return null;
        }

        UserVO2Builder userVO2 = UserVO2.builder();

        userVO2.id( source.getId() );
        userVO2.name( source.getName() );
        userVO2.createTime( source.getCreateTime() );

        return userVO2.build();
    }
}

参考链接

参考1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值