欢迎来到信息岛!
adminAdmin  2024-09-28 10:08 信息岛 显示边栏 |   抢沙发  31 
文章评分 0 次,平均分 0.0

MapStruct-Plus

MapStruct增加包

下面介绍一个 MapStruct 的增强包 —— MapStruct Plus,一个注解,可以生成两个类之间的转换接口,使 Java 类型转换更加便捷、优雅。

入门示例

官网地址:https://www.mapstruct.plus

源码地址:https://github.com/ZhaoRd/mapstruct-spring-plus

添加依赖

<dependencies>

        <!-- spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Mapstruct-plus -->
        <dependency>
            <groupId>io.github.linpeilie</groupId>
            <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
            <version>1.4.4</version>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
            <scope>provided</scope>
        </dependency>

        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.34</version>
                        </path>
                        <path>
                            <groupId>io.github.linpeilie</groupId>
                            <artifactId>mapstruct-plus-processor</artifactId>
                            <version>1.4.4</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>0.2.0</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

定义两个类

  • User
@Data
@AllArgsConstructor
@NoArgsConstructor

public class User {
    private String username;
    private int age;
    private boolean young;
}
  • UserDto
@Data
@AllArgsConstructor
@NoArgsConstructor

public class UserDTO {
    private String username;
    private int age;
    private boolean young;
}

指定对象映射关系

User 或者 UserDTO 上面增加注解 —— @AutoMapper,并设置 targetType 为对方类。

@AutoMapper(target = UserDTO.class)
public class User {
    // ...
}

测试

@SpringBootTest
public class QuickStartTest {

    @Resource
    private Converter converter;

    @Test
    public void test() {
        User user = new User();
        user.setUsername("jack");
        user.setAge(23);
        user.setYoung(false);

        UserDTO userDto = converter.convert(user, UserDTO.class);
        System.out.println(userDto);    // UserDto{username='jack', age=23, young=false}

        User newUser = converter.convert(userDto, User.class);
        System.out.println(newUser);    // User{username='jack', age=23, young=false}

    }

}

小结

引入依赖后,使用 Mapstruct Plus 步骤非常简单。

  1. 给需要转换的类添加 AutoMapper 注解
  2. 获取 Converter 实例,调用 convert 方法即可

特性

完全兼容 Mapstruct

Mapst实现了增强操作,如果之前已经使用了 Mapstruct,可以直接替换相关依赖。

单注解即可实现两个对象相互转换

例如快速开始中,只在 User 类上面增加注解 @AutoMapper,Mapstruct Plus 除了会生成 User -> UserDto 的转换接口,默认还会生成 UserDto -> User 的转换接口。

编译后,可以查看生成的类,如下:

自定义对象类型的属性自动转换

当两个需要转换的对象 AADto,其中的属性 BBDto 是自定义类型,并且也定义了 @AutoMapper 注解的话,在生成转换 AADto 时,会自动依赖属性 BBDto 的转换接口,实现其相应的属性转换。

例如:
分别有两组对象模型:汽车(Car) 和座椅配置(SeatConfiguration),其中 Car 依赖 SeatConfiguration。

两组对象结构一致,只不过代表层级不一样,这里拿 dto 层的对象定义举例:

  • CarDto
@AutoMapper(target = Car.class)
public class CarDto {
    private SeatConfigurationDto seatConfiguration;
}
  • SeatConfiguration
@AutoMapper(target = SeatConfiguration.class)
public class SeatConfigurationDto {
    private int seatCount;
}

测试:

@Test
public void carConvertTest() {
    CarDto carDto = new CarDto();
    SeatConfigurationDto seatConfigurationDto = new SeatConfigurationDto();
    seatConfigurationDto.setSeatCount(4);
    carDto.setSeatConfiguration(seatConfigurationDto);

    final Car car = converter.convert(carDto, Car.class);
    System.out.println(car);    // Car(seatConfiguration=SeatConfiguration(seatCount=4))

    assert car.getSeatConfiguration() != null;
    assert car.getSeatConfiguration().getSeatCount() == 4;
}

单个对象对多个对象进行转换

Mapstruct Plus 提供了 @AutoMappers 注解,支持配置多个目标对象,进行转换。

例如:有三个对象,UserUserDtoUserVOUser 分别要和其他两个对象进行转换。则可以按如下配置:

@Data
@AutoMappers({
    @AutoMapper(target = UserDto.class),
    @AutoMapper(target = UserVO.class)
})
public class User {
    // ...
}

Map 转对象

Mapstruct Plus 提供了 @AutoMapMapper 注解,支持生成 Map<String, Object> 转换为当前类的接口。同时,还支持 map 中嵌套 Map<String, Object> 转换为自定义类嵌套自定义类的场景。

其中,map 中的 value 支持的类型如下:

  • String
  • BigDecimal
  • BigInteger
  • Integer
  • Long
  • Double
  • Number
  • Boolean
  • Date
  • LocalDateTime
  • LocalDate
  • LocalTime
  • URI
  • URL
  • Calendar
  • Currency
  • 自定义类(自定义类也需要增加 @AutoMapMapper 注解

例如:

有如下两个接口:

  • MapModelA
@Data
@AutoMapMapper
public class MapModelA {

    private String str;
    private int i1;
    private Long l2;
    private MapModelB mapModelB;

}
  • MapModelB
@Data
@AutoMapMapper
public class MapModelB {

    private Date date;

}

测试:

@Test
public void test() {
    Map<String, Object> mapModel1 = new HashMap<>();
    mapModel1.put("str", "1jkf1ijkj3f");
    mapModel1.put("i1", 111);
    mapModel1.put("l2", 11231);

    Map<String, Object> mapModel2 = new HashMap<>();
    mapModel2.put("date", DateUtil.parse("2023-02-23 01:03:23"));

    mapModel1.put("mapModelB", mapModel2);

    final MapModelA mapModelA = converter.convert(mapModel1, MapModelA.class);
    System.out.println(mapModelA);  // MapModelA(str=1jkf1ijkj3f, i1=111, l2=11231, mapModelB=MapModelB(date=2023-02-23 01:03:23))
}

支持自定义转换

自定义属性转换

Mapstruct Plus 提供了 @AutoMapping 注解,该注解在编译后,会变为 Mapstruct 中的 @Mapping 注解,已经实现了几个常用的注解属性。

指定不同名称属性字段映射转换

例如,Car 类中属性 wheels 属性,转换 CarDto 类型时,需要将该字段映射到 wheelList 上面,可以在 wheels 上面增加如下注解:

@AutoMapper(target = CarDto.class)
public class Car {
    @AutoMapping(target = "wheelList")
    private List<String> wheels;
}
自定义时间格式化

在将 Date 类型的属性,转换为 String 类型时,可以通过 dateFormat 来指定时间格式化:

@AutoMapper(target = Goods.class)
public class GoodsDto {

    @AutoMapping(target = "takeDownTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
    private Date takeDownTime;

}
自定义数字格式化

当数字类型(doublelongBigDecimal)转换为 String 类型时,可以通过 numberFormat 指定 java.text.DecimalFormat 所支持的格式:

@AutoMapper(target = Goods.class)
public class GoodsDto {

    @AutoMapping(target = "price", numberFormat = "$#.00")
    private int price;

}
自定义 Java 表达式

@AutoMapping 提供了 expression 属性,支持配置一段可执行的 Java 代码,来执行具体的转换逻辑。

例如,当一个 List<String> 的属性,想要转换为用 , 分隔的字符串时,可以通过该配置,来执行转换逻辑:

@AutoMapper(target = UserDto.class)
public class User {

    @AutoMapping(target = "educations", expression = "java(java.lang.String.join(",", source.getEducationList()))")
    private List<String> educationList;

}

自定义类型转换器

@AutoMapping 注解提供了 uses 属性,引入自定义的类型转换器,来提供给当前类转换时使用。

实例场景:

项目中会有字符串用 , 分隔,在一些类中,需要根据逗号拆分为字符串集合。针对于这种场景,可以有两种方式:首先可以指定字段映射时的表达式,但需要对每种该情况的字段,都添加表达式,复杂且容易出错。

第二,就可以自定义一个类型转换器,通过 uses 来使用

public interface StringToListString {
    default List<String> stringToListString(String str) {
        return StrUtil.split(str);
    }
}

@AutoMapper(target = User.class, uses = StringToListStringConverter.class)
public class UserDto {

    private String username;
    private int age;
    private boolean young;
    @AutoMapping(target = "educationList")
    private String educations;
    // ......
}

测试:

@SpringBootTest
public class QuickStartTest {

    @Autowired
    private Converter converter;

    @Test
    public void ueseTest() {
        UserDto userDto = new UserDto();
        userDto.setEducations("1,2,3");

        final User user = converter.convert(userDto, User.class);
        System.out.println(user.getEducationList());    // [1, 2, 3]

        assert user.getEducationList().size() == 3;
    }
}
「点点赞赏,手留余香」

还没有人赞赏,快来当第一个赞赏的人吧!

admin给Admin打赏
×
予人玫瑰,手有余香
  • 2
  • 5
  • 10
  • 20
  • 50
2
支付

声明:本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

admin
Admin 关注:0    粉丝:0 最后编辑于:2024-10-20
这个人很懒,什么都没写

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享