当前位置: 首页 > news >正文

告别BeanUtils!MapStruct Plus快速入门与最佳实践

文章目录

前言

一、安装

二、单个对象转换

1.指定对象映射关系

2.编写测试代码

3.运行结果

4.原理解析 

三、自定义实体类属性转换 

1.自定义一个类型转换器

2.使用类型转换器

3.运行结果

四、工具类

总结

前言

在开发中,我们有VO、BO、POJO常见对象类型,分别服务于不同层次和常见,不同的对象类型

需要做转换,传统的方式我们使用set/get,但是一个一个手动写太繁琐和太麻烦,所以像

apache、Spring、hutool都提供了BeaenUtils工具类,那我们为什么还要使用MapStruct Plus

呢???主要是BeanUtils底层用的是反射,性能较差,而MapStruct Plus是编译期生成的,接近原

生代码效率,你就理解MapStruct Plus性能 > BeanUtils 比它厉害 牛逼就好了。MapStruct Plus是

MapStruct的PLUS版本,兼容MapStruct,额.....没学过MapStruc,不影响。

一、安装

注意:这里跟官网有点不一样,我们使用lombok,在 Maven 配置中引入 mapstruct-plus-

processor 和 lombok-mapstruct-binding 依赖是为了解决 ​编译期代码生成协同问题​​ 和 ​​Lombok

与 MapStruct 的兼容性问题​​。

Lombok 和 MapStruct 均依赖编译期注解处理器生成代码。若 Lombok 未先生成 getter/setter 方

法,MapStruct 将无法识别字段导致编译失败。lombok-mapstruct-binding 协调两者的处理顺序,

确保 Lombok 优先执行

从 Lombok 1.18.16 开始,必须引入该绑定库,否则 MapStruct 无法识别 Lombok 生成的构造器或

Builder 模式(如 @Builder 注解生成的类)。

<properties>
    <mapstruct-plus.version>最新版本</mapstruct-plus.version>
</properties>
<dependencies>
    <dependency>
        <groupId>io.github.linpeilie</groupId>
        <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
        <version>${mapstruct-plus.version}</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>    <!-- 这里根据自己的需要进行切换 -->
                <target>1.8</target>    <!-- 这里根据自己的需要进行切换 -->
                <annotationProcessorPaths>
                       <path>
                            <groupId>io.github.linpeilie</groupId>
                            <artifactId>mapstruct-plus-processor</artifactId>
                            <version>${mapstruct-plus.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>${mapstruct-plus.lombok.version}</version>
                        </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

二、单个对象转换

1.指定对象映射关系

在 User 或者 UserVo 上面增加注解 —— @AutoMapper,并设置 target 为对方类。
以下面代码举例,添加注解:@AutoMapper(target = UserVo.class)

User类:

@Data
@AutoMapper(target = UserVo.class)
public class User {
    private String username;
    private int age;
    private String password;
}

UserVo类:

@Data
@AutoMapper(target = User.class)
public class UserVo {
    private String username;
    private int age;
    private String password;
}

2.编写测试代码

@SpringBootTest
public class QuickStartTest {

    @Autowired
    private Converter converter;

    @Test
    public void test(){
        // 创建 User 对象
        User user = new User();
        user.setUsername("wen");
        user.setAge(18);
        user.setPassword("123456");

        // 使用 MapStruct plus 进行对象间转换:User =》 UserVo
        UserVo userVo = converter.convert(user, UserVo.class);
        // 输出转换之后的对象
        System.out.println(userVo);
        // 测试
        System.out.println("user.getUsername().equals(userVo.getUsername()) = " + user.getUsername().equals(userVo.getUsername()));
        System.out.println("user.getAge() == userVo.getAge() = " + user.getAge() +"---" + userVo.getAge());
    }
}

3.运行结果

4.原理解析 

User转为UserVo主要是UserVo userVo = converter.convert(user,UserVo.class);底层其实set/get实现。

  @Override
    public UserVo convert(User source) {
        if ( source == null ) {
            return null;
        }

        UserVo userVo = new UserVo();

        userVo.setTagList( stringToListConverter.stringToList( source.getTags() ) );
        userVo.setUsername( source.getUsername() );
        userVo.setAge( source.getAge() );

        return userVo;
    }

在target目录下的generated-source/annotations/com.taoran.mapstructplus.entity

三、自定义实体类属性转换 

想起手上有一个需求,前端传身份正反面图片URL,传的是List<String>,但是数据库保存是String

并且使用,相隔保存到收据库,可以使用MapStruct Plus的自定义实体类属性转换。

有两种方式,我们讲第二种。

1、@AutoMapping expression指定表达式:适合简单。

2、自定义一个类型转换器:适合复杂。

1.自定义一个类型转换器

String转List转换器

@Component
public class StringToListConverter {
    public List<String> stringToList(String str) {
        if (str == null) {
            return Collections.emptyList();
        }
        return Arrays.asList(str.split(","));
    }
}

List转String转换器

@Component
public class ListToStringConverter {
    public String listToString(List<String> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return String.join(",", list);
    }
}

2.使用类型转换器

@AutoMapper注解中使用uses指定转换器,转换器可以使用多个,并且需要在转换的属性加上

@AutoMapping注解,target指向另一个需要转化的属性。

User:

@Data
@AutoMapper(target = UserVo.class,uses = StringToListConverter.class)
public class User {
    private String username;
    private int age;
    private String password;

    @AutoMapping(target = "tagList")
    private String tags;
}

UserVo:

@Data
@AutoMapper(target = User.class,uses = ListToStringConverter.class)
public class UserVo {
    private String username;
    private int age;

    @AutoMapping(target = "tags")
    private List<String> tagList;
}

测试类:

    @Test
    public void test1() {
        // 创建一个 User 对象
        User user = new User();
        user.setUsername("wen");
        user.setAge(18);
        user.setPassword("123456");
        user.setTags("Java,Python,C++");

        // 转换
        UserVo userVo = converter.convert(user, UserVo.class);
        System.out.println(userVo);
    }

3.运行结果

四、工具类

package com.ailian.common.core.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import io.github.linpeilie.Converter;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.Map;

/**
 * Mapstruct 工具类
 * <p>参考文档:<a href="https://mapstruct.plus/introduction/quick-start.html">mapstruct-plus</a></p>
 *
 *
 * @author Michelle.Chung
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MapstructUtils {

    private final static Converter CONVERTER = SpringUtils.getBean(Converter.class);

    /**
     * 将 T 类型对象,转换为 desc 类型的对象并返回
     *
     * @param source 数据来源实体
     * @param desc   描述对象 转换后的对象
     * @return desc
     */
    public static <T, V> V convert(T source, Class<V> desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        return CONVERTER.convert(source, desc);
    }

    /**
     * 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象
     *
     * @param source 数据来源实体
     * @param desc   转换后的对象
     * @return desc
     */
    public static <T, V> V convert(T source, V desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        return CONVERTER.convert(source, desc);
    }

    /**
     * 将 T 类型的集合,转换为 desc 类型的集合并返回
     *
     * @param sourceList 数据来源实体列表
     * @param desc       描述对象 转换后的对象
     * @return desc
     */
    public static <T, V> List<V> convert(List<T> sourceList, Class<V> desc) {
        if (ObjectUtil.isNull(sourceList)) {
            return null;
        }
        if (CollUtil.isEmpty(sourceList)) {
            return CollUtil.newArrayList();
        }
        return CONVERTER.convert(sourceList, desc);
    }

    /**
     * 将 Map 转换为 beanClass 类型的集合并返回
     *
     * @param map       数据来源
     * @param beanClass bean类
     * @return bean对象
     */
    public static <T> T convert(Map<String, Object> map, Class<T> beanClass) {
        if (MapUtil.isEmpty(map)) {
            return null;
        }
        if (ObjectUtil.isNull(beanClass)) {
            return null;
        }
        return CONVERTER.convert(map, beanClass);
    }

}

总结

MapStruct Plus的用法还有很多,例如:Map转对象、类型转换、一个类与多个类之间转换、类循

环嵌套、类转换API等,具体可以看官网文档。

MapStruct Plus官网:MapStructPlus

MapStruct官网:MapStruct – Java bean mappings, the easy way!

相关文章:

  • C++ —— 智能指针
  • PH热榜 | 2025-04-03
  • 流量特征分析-蚁剑流量分析
  • leetcode_数组 56. 合并区间
  • Pod控制器之deployment
  • 2025 ArkTS语言开发入门之前言(二)
  • nginx中地理位置访问控制模块geo
  • 2025年【山东省安全员C证】考试题及山东省安全员C证考试内容
  • 【算法】筛质数
  • FlashDB移植
  • Redis 热key问题怎么解决?
  • 计算机毕业设计指南
  • 开发指南111-关闭所有打开的子窗口
  • Spring 中有哪些设计模式?
  • python入门之从安装python及vscode开始
  • 功耗日志抓取需求
  • (六)安卓开发中的Activity的启动、关闭和生命周期详解
  • 目录遍历(Directory traversal)漏洞总结
  • keepalived高可用介绍
  • VLAN(虚拟局域网)
  • 做报名链接的网站/郑州seo联系搜点网络效果好
  • 网站建设属于什么经济科目/网络推广理实一体化软件
  • 做网站图片自动切换/广告联盟有哪些平台
  • 柳州做网站的企业/网站快速排名服务
  • 南昌企业自助建站/网站长尾关键词排名软件
  • 国务院网站规划建设方案/营业推广的方式