首页 > 其他分享 >MapStruct对象映射转换

MapStruct对象映射转换

时间:2024-05-26 16:56:03浏览次数:16  
标签:Mapper 转换 映射 UserVo MapStruct Mapping source User

前言

2024.05.26,项目中用到了MapStruct,今天对项目中的一个实体类进行改动,发现不起作用,一顿排查下来发现是MapStruct搞错的,因此打算系统整理一下MapStruct的用法。

介绍

在实际开发中我们经常需要做DTO、VO、Entity对象之间的转换,在开发中常见的做法有两种:

MapStruct可以单独使用,也可以配合Spring框架一起使用

MapStruct实现对象之间转换的原理是基于get、set来实现的,来查看一下示例的生成的代码,非常简单
image.png

起步

  1. 导入依赖
    org.mapstruct.mapstruct包含必要的注解,例如@Mapping
    org.mapstruct.mapstruct-processor中包含注解生成器的实现类

注意:因为Lombok会生成setter、getter,所以如果项目中使用了lombok,需要在pom.xml将lombok写在mapstruct的前面

<dependency>
		<groupId>org.mapstruct</groupId>
		<artifactId>mapstruct</artifactId>
		<version>1.5.5.Final</version>
</dependency>

<dependency>
		<groupId>org.mapstruct</groupId>
		<artifactId>mapstruct-processor</artifactId>
		<version>1.5.5.Final</version>
</dependency>
  1. 这是我们的类,此处使用lombok生成getter、setter,如果不使用lombok需要手动写getter、setter
    若源类型中的属性名和类型与目标类型中的相同,则可以自动完成转换,不需要额外的标注。
    User.java
@Data
public class User {
    private String userName;

    private String password;

    private String sex;

    private Integer age;
}

UserVo.java

@Data
public class UserVo {
    private String userName;

    private String sex;

    private Integer age;
}
  1. 定义一个Mapper接口
    接口中的方法就是要实现对象类型转换的方法
    注意:
  • 方法参数是源对象类型
  • 方法返回值类型是要转换成的目标对象类型
    在这个接口中我们定义了一个方法toUserVo,参数类型是源对象类型User,方法返回值类型是我们需要转换成的目标对象类型UserVo
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ObjectConventor {

    UserVo toUserVo(User user);
    
}
  1. 示例
    public static void main(String[] args) {
        User user = new User();
        user.setUserName("XiaoMing");
        user.setAge(18);
        user.setSex("M");
        user.setPassword("123456");
        // 获取自动生成的映射器的实现类
        ObjectConventor mapper = Mappers.getMapper(ObjectConventor.class);
        // 调用对象类型转换方法
        UserVo userVo = mapper.toUserVo(user);
        System.out.println(userVo);
    }

在编译期间,会自动根据Mapper接口中的方法的参数和返回值类型自动生成实现类
我们使用Mappers.getMapper即可获取到指定的Mapper接口的实现类,调用方法即可完成对象之间的转换。

我们来看一下UserVo toUserVo(User user)这个方法的实现,就是利用setter、getter生成的
image.png

在Spring中使用

普通使用MapStruct我们需要手动获取mapper的实现类,但是在Spring中,我们可以直接从容器中通过依赖住的方式来获取Mapper的实现类。
只需要在Mapper注解中设置属性componentModel为字符串spring

@Mapper(componentModel = "spring")
public interface ObjectConventor {

    UserVo toUserVo(User user);

}

当然也可以使用MapStruct中内置的常量,如下所示

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface ObjectConventor {

    UserVo toUserVo(User user);

}

在需要使用的地方通过@Autowired注入即可使用,示例

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    ObjectConventor objectConventor;

}

注意:@Mapper.component的值有多个,说两个常用的:

  • default:默认值,需要手动通过Mappers.getMapper()来获取mapper的实现类
  • spring:可以通过Spring容器依赖注入的方式获取mapper的实现类

常规使用

mapping

在MapStruct中,若两个类型中的属性名称相同,则会自动完成转换。
如果遇到对象类型的属性名称不一致,则可以利用@Mapping在接口方法上进行标注,
例如User.image要转换UserVo.avatarUrl
target用来指定要处理的目标类型的属性,source用来指定源类型的属性名

@Mapper
public interface ObjectConventor {

    @Mapping(target = "avatarUrl", source = "image")
    UserVo toUserVo(User user);

}

mapping.expression

如果属性名称相同,但属性类型不相同:

  • 如果是基本数据类型和包装类之间转换,mapstruct会进行拆箱、装箱,我们不需要处理
  • 包装类与String之间的转换,mapStruct自动处理,不需要处理
  • 日期与String之间的转换
    除了以上情况之外的类型不相同,我们需要借助@Mapping.expression手动进行处理,
    使用@Mapping.expression可以完成对目标属性的特殊处理
    例如:User.address是Object类型,要转换为UserVo.address为String类型
@Mapper
public interface ObjectConventor {

    @Mapping(target = "avatarUrl", source = "image")
    @Mapping(target = "address", expression = "java(source.getAddress().getProvince() + source.getAddress().getCity() )")
    UserVo toUserVo(User source);

}

查看生成的代码
image.png

注意:在@Mapping中不可以同时出现sourceexpression,因为MapStruct会把整个express作为整体去xxx.setTarget(expression)执行

常量赋值

如果要给对象中的属性赋值常量,则可以使用constant属性
注意:constant与source不可同时出现

@Mapper
public interface ObjectConventor {

    @Mapping(target = "avatarUrl", source = "image")
    @Mapping(target = "country", constant = "China")
    UserVo toUserVo(User source);

}

空值处理

当source中的属性为null时,可以我target赋值默认值

  • defaultValue默认值
  • defaultExpression默认表达式
@Mapper
public interface ObjectConventor {

    @Mapping(target = "avatarUrl", source = "image")
    @Mapping(target = "sex", source = "sex", defaultValue = "未知")
    @Mapping(target = "status", source = "disable", defaultExpression = "java( com.demo.utils.UserUtils.getDefaultStatus() )")
    UserVo toUserVo(User source);

}

@Mappings

一个方法上有多个Mapping,可以统一放到@Mappings中,

@Mapper
public interface ObjectConventor {


    @Mappings({
            @Mapping(target = "avatarUrl", source = "image"),
            @Mapping(target = "sex", source = "sex", defaultValue = "未知"),
            @Mapping(target = "status", source = "disable", defaultExpression = "java( com.demo.utils.UserUtils.getDefaultStatus() )")
    })
    UserVo toUserVo(User source);

}

嵌套类型处理

通过属性.属性的方式即可

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface ObjectConventor {

    @Mapping(target = "country", source = "address.country")
    UserVo toUserVo(User source);
}

如果是复杂的嵌套类型,则推荐额外再定义一个类型转换方法,MapStruct会自动去调用

SpringBean注入

在Mapper中注入Spring Bean,实现在mapper调用SpringBean去处理
由于interfac无法实现实现依赖注入,因此需要修改Mapper为抽象类abstract class,所有的方法也都需要修改成abstract

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public abstract class ObjectConventor {

    @Autowired
    UserService userService;

    @Mapping(target = "roles", expression = "java( userService.getRoles(source.getUserName()) )")
    abstract UserVo toUserVo(User source);

}

自定义映射逻辑

由于Java8中的interface支持default方法,因此可以在Mapper中自定义映射逻辑
示例:

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface ObjectConventor {

    default UserVo toUserVo(User user) {
        UserVo userVo = new UserVo();
        userVo.setUserName(user.getUserName());
        userVo.setAge(user.getAge());
        return userVo;
    }
    
}

日期格式化

Date与String之间的转换,可以规定日期格式
生成的代码会自动去调用SimpleDateFormat去格式化日期

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface ObjectConventor {

    @Mapping(target = "createDate", dateFormat = "yyyy-MM-dd HH:mm:ss")
    UserVo toUserVo(User source);
}

踩坑点注意

  1. 修改了属性类型或新增、减少了属性,生成的实现类中并没有变化
    解决方法:需要先手动删除maven打包后的文件,然后再重新启动程序即可
    image.png

  2. 生成的对象中的属性全部为null,并且生成的实现类中并没有使用getter、setter
    image.png

解释:由于lombok和MapStruct都是作用于编译期间,由于MapStruct和Lombok的工作顺序问题,MapStruct在Lombok之前执行,MapStruct检测此时的参数类型和返回值类型还没有getter、setter,导致没有去调用getter、setter

解决方式:调整pom.xml中Lombok和MapStruct的引入顺序,要保证Lombok写在MapStruct之前
image.png

  1. 要完成集合元素类型之间的转换,为保证MapStruct能够正确生成目标对象,需要先定义单个对象转换的方法。
    示例:要完成List<User>List<UserVo>的转换,不可以在Mapper只定义这一个方法,也需要将单个元素之间的转换User转换UserVo的方法定义出来
    正确示例:
    image.png

标签:Mapper,转换,映射,UserVo,MapStruct,Mapping,source,User
From: https://www.cnblogs.com/itkkk/p/18213928

相关文章

  • 时间戳与yyyy-mm-dd hh:mm:ss格式之间的互相转换
    将时间戳转化为yyyy-mm-ddhh:mm:ssfunctionbackTime(value){//value必须是一个毫秒级的时间戳哈;//如果出现的不是一个毫秒级的时间戳,将会出现转化为1970开始letdate=newDate(value);//获取年份、月份和日期letyear=date.getFullYear();//......
  • nginx-端口复用,不同域名映射到不同服务中
    我使用docker容器运行NGINX,并将主机的80端口映射到容器的8080端口中。[root@harbor20240526]#dockerpsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTS......
  • 国产平替 16/20/24/32-bit 高精度 Σ-Δ 模数转换器芯片
    信格勒微电子的芯片产品已通过行业头部大厂导入验证,深受百万终端客户好评。而且因为fullycompatible.板子拿来,换个芯片,性能更佳。MCU不用改ccode。平替CirrusLogic芯片SIG5632平替CS5532BS(32-bit)速率从CS5532BS的3.84kSPS提高到30.72kSPS,功耗更低,增加5ppm/℃的内......
  • 【使用Python3实现一个音视频播放的工具,同时实现一些自动化的功能,比如视频格式转换,视
    最近有个想法,就是使用python工具自动识别视频文件中的高潮部分#1,主要用途可以有以下几个:转换视频格式识别体育比赛中的高潮部分同样也适用识别电影中的高潮部分截取视频文件中的高潮部分,做成一个视频集锦2,搜索了一圈。使用以下组合开发了一个雏形项目。命名为movie项目。......
  • 深入理解虚拟 物理地址转换,页表--基于ARMV8
    1.页表转换寄存器描述符1.1,页表/页目录结构基于前言中的内核配置,内核采用39位虚拟地址,因此可寻址范围为2^39=512G,采用(linux默认为五级页表,另外还有PUD,P4D,由于本文只配置三级,其他两项不予罗列)3级页表结构,分别为:PGD(PageGlobalDirectory)b......
  • 通过qemu-img工具转换镜像格式
    应用场景华为云支持导入vhd、vmdk、qcow2、raw、vhdx、qcow、vdi、qed、zvhd或zvhd2格式镜像文件。其他镜像文件,需要转换格式后再导入。本节操作指导您使用开源qemu-img工具转换镜像格式。方案构架本节提供本地为Windows操作系统和Linux操作系统的转换镜像格式的操作方法。 ......
  • 推荐一款全新的4K视频处理转换工具:VideoProc Converter AI
    VideoProc(4K视频处理转换工具)是一款可以帮助用户对视频进行格式转换,画面编辑,甚至还可以支持网站下载视频,录制桌面屏幕等,是一款名副其实的多媒体编辑全家桶神器。软件特点作为功​​能强大的继任者,VideoProc集成了UHD视频转换器/压缩器(You*Tube)视频下载器和视频编辑器,使......
  • 将 MOV 转换为 MP4 的 10 个最佳工具
    在当今的数字时代,内容创作和消费正处于巅峰,对多功能和兼容媒体格式的需求从未如此之高。在众多可用的视频格式中,MOV和MP4因其在各种设备和平台中的广泛使用而脱颖而出。然而,将MOV文件转换为更通用兼容的MP4格式的需求已成为用户寻求确保其视频可在所有设备和平台上播放......
  • 基本数据类型和字符串转换
    基本数据类型和字符串转换中8种包装类提供不同类型间的转换方式:Number父类中提供的6种方法。parseXXX()静态方法valueof()静态方法注意:需保证类型兼容,否则抛出NumberFormatException异常。源代码:publicclassDemo01{publicstaticvoidmain(String[]args){//基本数据类......
  • 【达梦问题解决】to_date转换之【文字与格式字符串不匹配】
    【问题描述】因为要转换的值中包含了不属于时间格式的字符(T,Z),这可能是数据迁移时时间参数设置不对导致的。具体没有进行考究【问题解决】使用DATE分隔符解决【手册链接】格式符解释实际分隔符的处理办法【自定义转换函数】这里的自定函数是不完善的,因为我的数......