Java实现MapStruct对象转换的示例代码

 更新时间:2024年12月06日 10:34:27   作者:scj1022  
本文主要介绍了MapStruct在Java中的对象转换使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、基本使用

1、Maven 引入

<properties>
    <lombok.version>1.18.30</lombok.version>
    <mapstruct.version>1.4.1.Final</mapstruct.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <optional>true</optional>
    </dependency>

    <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>
</dependencies>

2、基本使用

待转换的类

@Data
@Builder
public class UserDTO {
    private Long id;
    private Integer age;
    private String name;
}

转换目标类

@Data
public class UserVO {
    private Long id;
    private Integer age;
    private String name;
}

转换器

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface Converter {
    // 后续通过 INSTANT 调用转换方法
    Converter INSTANT = Mappers.getMapper(Converter.class);

    UserVO convert(UserDTO userDTO);
}

使用示例

public class Test {
    public static void main(String[] args) {
        UserDTO userDTO = UserDTO.builder().id(1L).age(18).name("scj").build();
        UserVO userVO = Converter.INSTANT.convert(userDTO);
        System.out.println(userVO);
    }
}

输出结果

UserVO(id=1, age=18, name=scj)

可以看到在 target 生成 转换器的实现类,并使用 get 和 set 进行转换,所以性能很高。

在这里插入图片描述

3、Spring Bean

MapStruct提供了依赖注入的机制,让我们能够在Spring的环境下,更优雅的获得Converter。

转换器

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface Converter {
    UserVO convert(UserDTO userDTO);
}

使用示例

@RestController
public class TestController {
    
    // 直接注入使用
    @Autowired
    private Converter converter;

    @GetMapping("/test")
    public void mapstructTest() {
        UserDTO userDTO = UserDTO.builder().id(1L).age(18).name("scj").build();
        UserVO userVO = converter.convert(userDTO);
        System.out.println(userVO);
    }
}

输出结果

UserVO(id=1, age=18, name=scj)

可以看到 target 中生成的实现类交给 Spring容器 管理了

在这里插入图片描述

二、类型一致的场景

1、字段名不一致

字段名不同,通过 target 和 source 属性指定映射关系(字段名一致可以省略)

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    @Mapping(target = "userName", source = "name")
    UserVO convert(UserDTO userDTO);
}

输出结果

UserVO(id=1, age=18, username=scj)

2、ignore

不需要映射的字段,可以设置 ignore = true

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    // 不需要映射的字段,指定 ignore = true
    @Mapping(target = "name", ignore = true)
    @Mapping(target = "age", ignore = true)
    UserVO convert(UserDTO userDTO);
}

输出结果

UserVO(id=1, age=null, name=null)

3、defaultValue

通过 defaultValue 设置默认值(仅当源对象的该属性值为 null 时)

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    // 只有为 null 的才会生效
    @Mapping(target = "id", defaultValue = "1")
    @Mapping(target = "age", defaultValue = "66")
    @Mapping(target = "name", defaultValue = "zs")
    UserVO convert(UserDTO userDTO);
}

使用示例

public class Test {
    public static void main(String[] args) {
        // id = null
        UserDTO userDTO = UserDTO.builder().age(18).name("scj").build();
        UserVO userVO = Converter.INSTANT.convert(userDTO);
        System.out.println(userVO);
    }
}

输出结果

UserVO(id=1, age=18, name=scj)

4、constant

通过 constant 为属性设置常量值,无论源对象的该属性值是否为 null

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    // 只有为 null 的才会生效
    @Mapping(target = "id", constant = "6")
    @Mapping(target = "age", constant = "66")
    @Mapping(target = "name", constant = "zs")
    UserVO convert(UserDTO userDTO);
}

使用示例

public class Test {
    public static void main(String[] args) {
        UserDTO userDTO = UserDTO.builder().id(1).age(18).name("scj").build();
        UserVO userVO = Converter.INSTANT.convert(userDTO);
        System.out.println(userVO);
    }
}

输出结果

UserVO(id=6, age=66, name=zs)

三、类型不一致的场景

1、默认转换

对于部分数据类型,如果属性类型不一致,会做默认的的转换并赋值。

包装类 相关:基本数据类型、字符串、其他包装类

// Integer -> int
target.setIntegerValue( source.getIntegerValue() );

// Integer -> Long
target.setIntegerValue( source.getIntegerValue().longValue() );

// Integer -> Double
target.setIntegerValue( source.getIntegerValue().doubleValue() );

// Integer -> String
target.setIntegerValue( String.valueOf( source.getIntegerValue() ) );

BigDecimal 相关:

// BigDecimal -> Integer/int
target.setDecimalValue( source.getDecimalValue().intValue() );

// BigDecimal -> Double/double
target.setDecimalValue( source.getDecimalValue().doubleValue() );

// BigDecimal -> String
target.setDecimalValue( source.getDecimalValue().toString() );

时间日期 相关

// Date -> LocalDateTime
target.setDateValue( LocalDateTime.ofInstant( source.getDateValue().toInstant(), ZoneId.of( "UTC" ) ) );

// LocalDateTime -> Date
target.setDateValue( Date.from( source.getDateValue().toInstant( ZoneOffset.UTC ) ) );

// Date -> String
target.setDateValue( new SimpleDateFormat().format( source.getDateValue() ) );

// LocalDateTime -> String
target.setDateValue( DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( source.getDateValue() ) );

枚举 相关

// Enum -> String
target.setEnumValue( source.getEnumValue().name() );

String 相关

// String -> Long/long
target.setStringValue( Long.parseLong( source.getStringValue() ) );

// String -> BigDecimal
target.setStringValue( new BigDecimal( source.getStringValue() ) );

// String -> Date
target.setStringValue( new SimpleDateFormat().parse( source.getStringValue() ) );

// String -> LocalDateTime
target.setStringValue( LocalDateTime.parse( source.getStringValue() ) );

// String -> Enum
target.setEnumValue( Enum.valueOf( Source.CustomEnum.class, source.getEnumValue() ) );

2、numberFormat

数字类型 转换为 字符串 时,可以通过 numberFormat 属性指定 格式

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    @Mapping(target = "integerValue", source = "integerValue", numberFormat = "#,##0")
    @Mapping(target = "doubleValue", source = "doubleValue", numberFormat = "#0.00")
    @Mapping(target = "decimalValue", source = "decimalValue", numberFormat = "#%")
    Target convert(Source source);
}
  • #,##0:表示数字使用千位分隔符。例如,1234567 将被格式化为 1,234,567
  • #0.00:表示数字保留两位小数。例如,666.666 将被格式化为 666.67
  • #%:表示将数字视为百分比。例如,0.75 将被格式化为 75%

3、dateFormat

时间日期 转换为 字符串 时,可以通过 dateFormat 属性指定 pattern

待转换的类

@Data
public class Source {
    private Date dateValue = new Date();
    private LocalDateTime localDateTimeValue = LocalDateTime.now();
}

转换目标类

@Data
public class Target {
    private String dateValue;
    private String localDateTimeValue;
}

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    @Mapping(target = "dateValue", source = "dateValue", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(target = "localDateTimeValue", source = "localDateTimeValue", dateFormat = "yyyy-MM-dd HH:mm:ss")
    Target convert(Source source);
}

输出结果

Target(dateValue=2024-09-26 19:27:41, localDateTimeValue=2024-09-26 19:27:41)

4、枚举值处理

待转换的类

@Data
public class Source {
    private SexEnum sexEnum = SexEnum.MAN;
}

转换目标类

@Data
public class Target {
    private String sex;
}

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    @Mapping(target = "sex", source = "sexEnum.desc")
    Target convert(Source source);
}

四、其他场景

1、对象嵌套(字段一致)

如果字段完全一致,会自动生成嵌套对象的 convert 方法。

待转换的类

@Data
public class Source {
    private Long id = 1L;
    private SourceInnerClass1 inner = new SourceInnerClass1();
}

@Data
class SourceInnerClass1 {
    private Long id = 11L;
    private List<SourceInnerClass2> innerList = Collections.singletonList(new SourceInnerClass2());
}

@Data
class SourceInnerClass2 {
    private Long id = 111L;
    private String value = "inner2";
}

转换目标类

@Data
public class Target {
    private Long id;
    private TargetInnerClass1 inner;
}

@Data
class TargetInnerClass1 {
    private Long id;
    private List<TargetInnerClass2> innerList;
}

@Data
class TargetInnerClass2 {
    private Long id;
    private String value;
}

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    Target convert(Source source);
}

输出

Target(id=1, inner=TargetInnerClass1(id=11, innerList=[TargetInnerClass2(id=111, value=inner2)]))

可以看到,所有嵌套对象的属性都做了自动映射

在这里插入图片描述

在这里插入图片描述

2、对象嵌套(字段不一致)

如果字段不一致,需要自己编写对应嵌套对象的 convert 方法,底层会自动调用。

待转换的类

@Data
public class Source {
    private Long id;
    private SourceInnerClass1 inner;
}

@Data
class SourceInnerClass1 {
    private Long id;
    private List<SourceInnerClass2> innerList;
}

@Data
class SourceInnerClass2 {
    private Long id;
    private String value;
}

转换目标类

@Data
public class Target {
    private Long id0;
    private TargetInnerClass1 inner0;
}

@Data
class TargetInnerClass1 {
    private Long id1;
    private List<TargetInnerClass2> innerList1;
}

@Data
class TargetInnerClass2 {
    private Long id2;
    private String value2;
}

转换器

@Mapper
public interface Converter {
    Converter INSTANT = Mappers.getMapper(Converter.class);

    @Mapping(target = "id0", source = "id")
    @Mapping(target = "inner0", source = "inner")
    Target convert(Source source);

    @Mapping(target = "id1", source = "id")
    @Mapping(target = "innerList1", source = "innerList")
    TargetInnerClass1 convert(SourceInnerClass1 source);

    @Mapping(target = "id2", source = "id")
    @Mapping(target = "value2", source = "value")
    TargetInnerClass2 convert(SourceInnerClass2 source);
}

使用示例

public class Test {
    public static void main(String[] args) {
        final Source source = new Source(1L, 18L, "scj", new SourceInner(1L, 18));
        final Target target = Converter.INSTANT.convert(source);
        System.out.println(target);
    }
}

输出

Target(id0=1, inner0=TargetInnerClass1(id1=11, innerList1=[TargetInnerClass2(id2=111, value2=inner2)]))

会按需调用对应对象的 convert 方法

在这里插入图片描述

3、自定义转换方法

使用 @Named 自定义转换方法,通过 qualifiedByName 属性指定,要和 @Named 的 value 对应

待转换的类

@Data
public class Target {
    private UserDTO targetUserDTO;
    private String targetUserJson;
}

转换目标类

@Data
public class Source {
    private String sourceUserJson;
    private UserDTO sourceUserDTO;
}

转换器

@Mapper
public interface Convert {

    Convert INSTANCE = Mappers.getMapper(Convert.class);

    @Mapping(target = "targetUserDTO", source = "sourceUserJson", qualifiedByName = "json2DTO")
    @Mapping(target = "targetUserJson", source = "sourceUserDTO", qualifiedByName = "dto2Json")
    Target convert(Source source);

    @Named("json2DTO")
    default UserDTO json2DTO(String userJson) {
        return JSON.parseObject(userJson, UserDTO.class);
    }

    @Named("dto2Json")
    default String dto2Json(UserDTO userDTO) {
        return JSON.toJSONString(userDTO);
    }
}

转换结果

Target(targetUserDTO=UserDTO(name=scj, age=18), targetUserJson={"age":66,"name":"zs"})

4、expression

通过 expression 可以指定 java 表达式,可以直接调用对应的方法。

转换器

@Mapper
public interface Convert {

    Convert INSTANCE = Mappers.getMapper(Convert.class);
    
    // 本类方法
    @Mapping(target = "targetUserDTO",  expression = "java(json2DTO(source.getSourceUserJson()))")
    // 非本类方法(类全名调用即可)
    @Mapping(target = "targetUserJson", expression = "java(com.alibaba.fastjson.JSON.toJSONString(source.getSourceUserDTO()))")
    // 枚举
    @Mapping(target = "sex", expression = "java(source.getSexEnum().getDesc())")
    Target convert(Source source);

    default UserDTO json2DTO(String userJson) {
        return JSON.parseObject(userJson, UserDTO.class);
    }
}

转换结果

Target(targetUserDTO=UserDTO(name=scj, age=18), targetUserJson={"age":66,"name":"zs"}, sex=男)

ConvertImpl

public class ConvertImpl implements Convert {
    @Override
    public Target convert(Source source) {
        if ( source == null ) {
            return null;
        }

        Target target = new Target();

        target.setTargetUserDTO( json2DTO(source.getSourceUserJson()) );
        target.setTargetUserJson( com.alibaba.fastjson.JSON.toJSONString(source.getSourceUserDTO()) );
        target.setSex( source.getSexEnum().getDesc() );

        return target;
    }
}

5、多个参数

待转换的类

@Data
public class Target {

    // source1

    private String strValue1;
    private Integer intValue1;

    // source2

    private String strValue2;
    private Integer intValue2;

    // field

    private String strValue;
    private Integer intValue;

}

转换目标类

@Data
public class Source1 {
	private String strValue = "s1";
    private Integer intValue = 1;
}

@Data
public class Source2 {
    private String strValue = "s2";
    private Integer intValue = 2;
}

转换器

@Mapper
public interface Convert {

    Convert INSTANCE = Mappers.getMapper(Convert.class);

    @Mapping(target = "strValue1", source = "s1.strValue")
    @Mapping(target = "intValue1", source = "s1.intValue")
    @Mapping(target = "strValue2", source = "s2.strValue")
    @Mapping(target = "intValue2", source = "s2.intValue")
    @Mapping(target = "strValue", source = "strValue")
    @Mapping(target = "intValue", source = "intValue")
    Target convert(Source1 s1, Source2 s2, String strValue, Integer intValue);
}

注意事项:如果字段名全部没有冲突,不需要 @Mapping,会自动对应。

五、推荐的IDEA插件

IDEA 搜索 MapStruct Support 安装即可,可以在使用MapStruct时获得更加丰富代码提示。

在这里插入图片描述

到此这篇关于Java实现MapStruct对象转换的示例代码的文章就介绍到这了,更多相关Java MapStruct对象转换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • JavaFx UI控件与代码间的绑定方法

    JavaFx UI控件与代码间的绑定方法

    这篇文章主要为大家详细介绍了JavaFx UI控件与代码间如何绑定,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • 解析如何开发FineReport的自定义控件

    解析如何开发FineReport的自定义控件

    FineReport作为插件化开发的报表软件,有些特殊需求的功能需要自己开发,开发的插件包帆软官方有提提供,可以去帆软论坛上找,本文将主要介绍如何开发一个自定义控件,这里讲讲方法论。需要的朋友一起来看下吧
    2016-12-12
  • SpringBoot整合JPA详细代码实例

    SpringBoot整合JPA详细代码实例

    这篇文章主要给大家介绍了关于SpringBoot整合JPA的相关资料,JPA(Java Persistence API)是Sun官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据,需要的朋友可以参考下
    2024-05-05
  • Sleuth+logback 设置traceid 及自定义信息方式

    Sleuth+logback 设置traceid 及自定义信息方式

    这篇文章主要介绍了Sleuth+logback 设置traceid 及自定义信息方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java selenium操作弹出对话框示例讲解

    java selenium操作弹出对话框示例讲解

    本文主要介绍java selenium操作弹出对话框,这里给大家整理了相关资料,并附示例代码和实现效果图,有兴趣的小伙伴可以参考下
    2016-08-08
  • java自定义封装StringUtils常用工具类

    java自定义封装StringUtils常用工具类

    这篇文章主要为大家详细介绍了java自定义封装StringUtils常用工具类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • Java结合百度云存储BCS代码分享

    Java结合百度云存储BCS代码分享

    最近云是一个很热门的新概念,仿佛任何东西只要跟云相关联,就立马高大上起来,额,我们也追随潮流吧,项目中也结合一下云!!
    2014-10-10
  • Spring的BeanFactoryPostProcessor接口示例代码详解

    Spring的BeanFactoryPostProcessor接口示例代码详解

    这篇文章主要介绍了Spring的BeanFactoryPostProcessor接口,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • mybatis分割字符串并循环,实现in多个参数的操作

    mybatis分割字符串并循环,实现in多个参数的操作

    这篇文章主要介绍了mybatis分割字符串并循环,实现in多个参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java获取Prometheus监控数据的方法实现

    Java获取Prometheus监控数据的方法实现

    本文主要介绍了Java获取Prometheus监控数据的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12

最新评论