MapStruct使用方式

为什么不用BeanUtils.copyProperties?

因为 BeanUtils 低效(反射)

MapStruct 在编译时生成代码,不会使用反射机制

1. 入门

1.1 安装

<!-- 引入 mapstruct -->
<!--它提供了 MapStruct 所需的主要注解和工具方法,例如 @Mapper, @Mapping 等注解以及 Mappers.getMapper() 方法。-->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<!--为你的 @Mapper 注解的接口或抽象类生成实现-->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.4.2.Final</version>
    <scope>compile</scope>
</dependency>

1.2 测试代码

@SpringBootTest
public class ATest {

    @Test
    void test1() {
        // 创建源对象
        User user = new User();
        user.setId(1L);
        user.setName("张三");
        user.setAge(25);

        UserDTO dto = UserMapper.INSTANCE.userToDto(user);
        System.out.println(dto); // UserDTO(id=1, userName=张三, age=25)
    }
}

// 源对象
@Data
class User {
    private Long id;
    private String name;
    private Integer age;
    // Getters 和 Setters
}

// 目标对象
@Data
class UserDTO {
    private Long id;
    private String userName;
    private Integer age;
    // Getters 和 Setters
}

@Mapper
interface UserMapper {
    // 获取映射器实例
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @Mapping(source = " name", target = "userName")
    UserDTO userToDto(User user);
}

 

2. 高级用法

2.1 字段名不同的映射

@Mapper
public interface UserMapper {
    @Mapping(source = "name", target = "userName")
    UserDTO toDTO(User user);

    List<UserDTO> toList(List<User> users); // 可以自动转换
}

2.2 普通类型转换

示例:String 类型转换为 Integer 类型

原理:它会在映射接口中查找 签名匹配 的方法

@Mapper
public interface UserMapper {
    @Mapping(source = "ageStr", target = "age")
    UserDTO toDTO(User user);

    // 自定义转换方法, 转换器会自动识别参数匹配的方法
    default Integer stringToInt(String ageStr) {
        return ageStr == null ? null : Integer.valueOf(ageStr);
    }
}

2.3 常量映射

@Mapping(target = "status", constant = "ACTIVE")

2.4 默认值映射

当源属性为 null 时,可以为目标属性设置默认值。

@Mapping(source = "count", target = "total", defaultValue = "0")

2.5 表达式映射

@Mapping(target = "timestamp", expression = "java(source.getDate().getTime())")
@Mapping(target = "date", expression = "java(new java.util.Date(source.getTime()))")

2.6 日期格式

对于日期和字符串之间的映射,可以指定日期格式。

内部使用SimpleDateFormat自动转换日期

@Mapping(source = "time", target = "time", dateFormat = "yyyy-MM-dd") // target的time为string类型
// 类似于
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(simpleDateFormat.format(new Date()));

2.7 多个源对象映射到一个目标对象

@Mapper
public interface UserMapper {
    @Mapping(source = "user.name", target = "userName")
    @Mapping(source = "address.city", target = "city") // 这里需要存在getCity()方法存在, 会自动调用
    UserDTO toDTO(User user, Address address);
}

2.8 忽略属性

@Mapping(target = "age", ignore = true) // 忽略age属性转换
UserDTO toDTO(User user);

2.9 支持自定义方法和组件映射

@Mapping(source = "time", target = "time", qualifiedByName = "dateToStr") // 主要是自己选择方法
UserDTO userToDto(User user);

@Named("dateToStr")
default String dateToStr(Date date) {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    return simpleDateFormat.format(date);
}

2.10 使用 @MapperConfig 统一配置

本身并不涉及 Spring 的配置管理,因此不需要 @Configuration 注解

@MapperConfig
public interface CentralConfig {
    @Mapping(target = "id", ignore = true)
}

最终代码

@SpringBootTest
public class ATest {

    @Test
    void test1() {
        // 创建源对象
        User user = new User();
        user.setId(1L);
        user.setName("张三");
        user.setAge("25");
        user.setTime(new Date(1734431222395L));
        Address address = new Address();
        address.setStreet("street111");
        address.setCity("city111");
        user.setAddress(address);

        UserDTO dto = UserMapper.INSTANCE.userToDto(user);
        System.out.println(dto);
    }
}

@Data
class User {
    private Long id;
    private String name;
    private String age;
    private Date time;
    private Address address;
}
@Data
class UserDTO {
    private Long id;
    private String userName;
    private Integer age;
    private String time;
    private AddressDTO addressDTO;
}

@Data
class Address {
    private String street;
    private String city;
}
@Data
class AddressDTO {
    private String CityAndStreet;
}

@Mapper
interface UserMapper {
    // 获取映射器实例
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @Mapping(source = " name", target = "userName")  // 同类型转换
    @Mapping(source = "age", target = "age")  // 不同类型转换
    @Mapping(source = "time", target = "time", qualifiedByName = "dateToStr")  // 自定义转换方法(自己选择方法)
    @Mapping(source = "address", target = "addressDTO")  // 不同对象类型转换
    UserDTO userToDto(User user);

    // 字符串年龄转整型年龄
    default Integer strToInt(String age) {
        return age == null ? null : Integer.valueOf(age);
    }

    // Address转AddressDTO
    default AddressDTO addToDTO(Address address) {
        String cityAndStreet = address.getCity() + address.getStreet();
        AddressDTO addressDTO = new AddressDTO();
        addressDTO.setCityAndStreet(cityAndStreet);
        return addressDTO;
    }

    @Named("dateToStr")
    default String dateToStr(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(date);
    }
}

 

3. MapStruct 常用注解

@Mapper:标记接口为映射器。

@Mapping:定义属性映射规则(如字段名不同、类型转换)。

@InheritInverseConfiguration:反向映射。

@MappingTarget:用于更新已有对象。

@MapperConfig:定义通用映射配置。

@BeanMapping:进一步配置映射行为。

@IterableMapping:集合映射。

@MapMapping:Map 类型映射。

 

4. 插件

 

5. 原理

Mapstruct 是在 java 文件到 class 这一步帮我们实现了转换方法,即做了预处理,提前编译好文件,类似 Lombok

以下是自动生成的实现类

package cn.gaosanjin.cuit;

class UserMapperImpl implements UserMapper {
    UserMapperImpl() {
    }

    public UserDTO userToDto(User user) {
        if (user == null) {
            return null;
        } else {
            UserDTO userDTO = new UserDTO();
            userDTO.setUserName(user.getName());
            userDTO.setAge(this.strToInt(user.getAge()));
            userDTO.setTime(this.dateToStr(user.getTime()));
            userDTO.setAddressDTO(this.addToDTO(user.getAddress()));
            userDTO.setId(user.getId());
            return userDTO;
        }
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇