属性映射框架-MapStruct

article/2025/6/23 2:23:20

在这里插入图片描述

属性映射框架-MapStruct

文章目录

  • 属性映射框架-MapStruct
  • 一、作用
  • 二、MapStruct 简介
    • 2.1 是什么
    • 2.2 竞品框架
    • 2.3 适合场景
  • 三、入门案例
    • 3.1 项目需求
    • 3.2 代码实现
  • 四、入门案例解析
  • 五、MapStruct 实战
    • 5.1 当属性正常映射时
    • 5.2 当某个属性要忽略映射
    • 5.3 当某个属性要求设置默认值时
    • 5.4 当属性名不一致时
    • 5.5 当源对象是多个时
    • 5.6 当属性为对象时
    • 5.7 当目标对象已经存在时
    • 5.8 当属性类型对不上时
      • 5.8.1 源是时间,目标是字符串
      • 5.8.2 源是字符串,目标是枚举
    • 5.9 当源是集合时
  • 六、SpringBoot集成
  • 七、项目实战

一、作用

MapStruct 是一个基于 Java 注解处理器的代码生成工具,主要用于简化 Java Bean 之间的映射转换。它通过编译时生成类型安全的映射代码,替代了传统手动编写转换逻辑的繁琐过程,显著提升开发效率和代码质量。

二、MapStruct 简介

2.1 是什么

官网:https://mapstruct.org/

在这里插入图片描述

What

MapStruct是一个代码生成器,它极大地简化了基于约定优于配置方法的Java Bean类型之间映射的实现。

生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。

大白话:一种代码生成器,解决Java Bean间属性映射

Why

MapStruct是一个Java注解处理器,用于自动生成对象之间的映射代码。在多层应用程序中,通常需要在不同的对象模型(如实体和数据传输对象DTOs)之间进行映射。手动编写这些映射代码既繁琐又容易出错。MapStruct通过自动化这个过程来简化这项工作。

大白话:Java各种O中来回转换既繁琐又容易出错,MapStruct可以轻松解决

注意点:Java各种O后面会解释,这里理解为Java Bean即可

How

MapStruct是一个注解处理器,它被插入到Java编译器中,可以在命令行构建(Maven,Gradle等)中使用,也可以从您喜欢的IDE中使用。

MapStruct使用合理的默认值,但在配置或实现特殊行为时,它会避开您的方式。

大白话:可手动可自动

案例感受一下:

需求:属性复制

public class User{private String uname;private String pwd;
}public class Person{private String name;private String password;
}

没用MapStruct之前

User u = new User("dafei", "666");
Person p = new Person();
p.setName(u.getUname());
p.setPassword(u.getPwd());    

用了MapStruct之后

User u = new User("dafei", "666");
Person p = UserMapper.INSTANCE.toPerson(u);

当前字段少,感受不出MapStruct魅力,如果复制的字段是100,200个时,就有你哭的啦。

2.2 竞品框架

看到这,肯定有小可爱说,直接用BeanUtil.copyProperties 不就得了么?那来比较一下。

市面上实现上面属性复制/映射的框架/方法有很多

  • Spring BeanUtils
  • Cglib BeanCopier
  • Apache BeanUtils
  • Dozer
  • orika
  • MapStruct
  • JSON 序列化 再反序列化
工具实现方式缺点说明
MapStructgetter/setter方法需要了解注解和配置项语法JSR269注解处理器在编译期自动生成Java Bean转换代码,支持可配置化,扩展性强
orika动态生成字节码首次调用耗时较久,性能适中采用javassist类库生成Bean映射的字节码,之后直接加载执行生成的字节码文件
Spring BeanUtils反射机制不支持名称相同但类型不同的属性转换
Apache BeanUtils反射机制需要处理编译期异常,性能最差
dozer反射机制性能差使用reflect包下Field类的set(Object obj, Object value)方法进行属性赋值
BeanCopier反射机制BeanCopier只拷贝名称和类型都相同的属性。即便基本类型与其对应的包装类型也不能相互转换;使用ASM的MethodVisitor直接编写各属性的get/set方法
JSON 序列化 再反序列化借助其他Json工具转换源对象先转json字符串,再转目标对象,慢

实现1000000次属性拷贝:

@Data
public class Source {private Long id;private String name;private Date birth;private Double money;private List<String> sms;private BigDecimal price;
}
@Data
public class Target {private Long id;private String name;private Date birth;private Double money;private List<String> sms;private BigDecimal price;
}

第一次:

Apache BeanUtilsSpring BeanUtilsMapStructOrikaDozerBeanCopier
5.06478990.26214970.02319920.494166215.28181630.0086604

第二次:

Apache BeanUtilsSpring BeanUtilsMapStructOrikaDozerBeanCopier
5.13250040.26599470.02365350.482508715.77854510.0097842

第三次:

Apache BeanUtilsSpring BeanUtilsMapStructOrikaDozerBeanCopier
4.91202560.27924790.02352940.509464815.70236850.0094256

从上面的测试

性能由高到低

BeanCopier > MapStruct > Spring BeanUtils > Orika > Apache BeanUtils > Dozer

​ 1 2.5 30 54 520 1665

结论:

按理 BeanCopier 性能最佳,但是它有个明显的缺陷:属性名与类型必须完全匹配才能转换

MapStruct 最好

2.3 适合场景

MapStruct适用于各种Java Bean之间的转换场景,包括但不限于以下情况:

  1. DTO(Data Transfer Object)数据接收对象 和 Entity(PO)即实体类它与数据库表中的字段是一一对应的之间的转换。
  2. 不同版本API之间的数据映射。
  3. 前端页面展示数据和后端数据模型之间的转换。

大白话:各种O之间转换

问题:Java中有哪些O,为什么存在各种O

  • POJO(plian ordinary java object)

    简单普通的Java对象,就是最简单的Java对象,最基本的Java Bean只是在属性上加上get和set方法

  • PO(Persistent Object)
    持久对象,与数据库表中字段一一对应,一般一个表对应一个PO,直接与数据库的crud操作相关。

  • VO(Value Object)
    VO有人理解为Value Object,也有人理解为View Object,无论是那种定义,其表达的意思是:表现层对象,用于业务层之间的数据传递,其作用与PO类似,但是其是与页面层相关,一般将页面层的数据封装成一个VO传递给页面,此处的VO可以继承与PO以减少冗余代码。

  • DTO(Data Trasfer Object)
    数据传输对象,一般用于向外提供仅需的数据,此处类似于VO的作用,如从数据库中查询出有30个字段,但是接口所需其中的10个字段,那么可在此处将10个字段封装成一个DTO提供给外部接口,以隐藏数据层的字段,也可减少数据的传输,提高系统性能。

  • BO(Business Object)/DO(Domain Object)
    业务对象/域对象,一般写在业务层,当业务逻辑比较复杂时,可能会用到比较多的业务对象,这样就可以将多个PO、VO封装成一个BO对象用于数据传递。

  • DAO(Data AccessObject)
    数据访问对象,就是一般我们所说的DAO层,用于连接数据库与service层的桥梁,用于对数据的访问(不是对数据库的访问),并且持久化数据层对象

在这里插入图片描述

大白话:各种O简单理解就是各个层级间数据流转对象

三、入门案例

3.1 项目需求

需求:实现将User对象属性拷贝到UserDTO中

3.2 代码实现

步骤1:创建项目

新建Maven项目:MapStrust-demo

步骤2:导入依赖

说明:这里使用的是-JDK-17

<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.34</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.6.3</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.6.3</version></dependency></dependencies>

步骤3:创建实体对象

@Data
@Accessors(chain = true)
public class User {private Long id;private String name;private String password;
}@Data
@Accessors(chain = true)
public class UserDTO {private Long id;private String name;private String password;
}

步骤4:编写映射接口

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );UserDTO userToUserDTO(User user);
}

这里有个注意点:@Mapper 是MapStruct 的, 注意跟MyBatis的 @Mapper区别

步骤5:拷贝实现

public class App {@Testpublic void testHello(){User user = new User().setId(1L).setName("dafei").setPassword("666");UserDTO userDTO = UserMapper.INSTANCE.userToUserDTO(user);System.out.println(user);System.out.println(userDTO);}
}
User(id=1, name=dafei, password=666)
UserDTO(id=1, name=dafei, password=666)

四、入门案例解析

  • lombok
@Data
@Accessors(chain = true)
public class User {private Long id;private String name;private String password;
}

@Data : 这个是lombok 插件,在编译期给User对象添加或重写get/set/toString/hashCode/equals等方法

@Accessors(chain = true)让User对象set方法改成链式方法

public User setId(Long id){this.id = id;return this
}
....

呈现出来的效果

User user = new User().setId(1L).setName("dafei").setPassword("666");
  • @Mapper
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );UserDTO userToUserDTO(User user);
}

@Mapper 这个Mapper注解跟MyBatis的@Mapper注解功能类似,就是将贴到的接口通过动态代理方式直接创建出接口实现类:UserMapperImpl

在这里插入图片描述

public class UserMapperImpl implements UserMapper {public UserMapperImpl() {}public UserDTO userToUserDTO(User user) {if (user == null) {return null;} else {UserDTO userDTO = new UserDTO();userDTO.setId(user.getId());userDTO.setName(user.getName());userDTO.setPassword(user.getPassword());return userDTO;}}
}

观察就会发现底层实现原理就是普通的GET/SET操作

  • Mappers

一个工具类,如果说@Mapper注解是MapStruct框架推门者,Mappers就是MapStruct框架引路者

贴了@Mapper注解的接口会在项目运行时会在内存中动态创建一个实现类对象,那Mappers工具类就是将对象摆放到前台啦。

//获取Mapper接口实现类对象
UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );

Mappers 是一个工厂类,通过传入的字节码对象,获取Mapper接口实现类,然后进行方法调用。

UserDTO userToUserDTO(User user);

五、MapStruct 实战

5.1 当属性正常映射时

需求:将Person 转换成PersonDTO

import lombok.Data;
import lombok.AllArgsConstructor;
@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.Data;
@Data
public class PersonDTO {private String name;private int age;
}
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);PersonDTO toDTO(Person person);
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18);System.out.println(person);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person);System.err.println(dto);}
}
Person(name=dafei, age=18)
PersonDTO(name=dafei, age=18)

5.2 当某个属性要忽略映射

需求:将Person转换成PersonDTO,忽略age属性

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;
}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);@Mapping(target = "age", ignore = true)PersonDTO toDTO(Person person);
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18);System.out.println(person);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person);System.err.println(dto);}
}
Person(name=dafei, age=18)
PersonDTO(name=dafei, age=0)

5.3 当某个属性要求设置默认值时

需求:将Person转成PersonDTO,当name属性为null时,设置默认值:xiaofei

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;
}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);//当源对象name属性值为null时,使用默认值@Mapping(target = "name", defaultValue = "xiaofei")PersonDTO toDTO(Person person);
}
public class App {public static void main(String[] args) {Person person = new Person(null, 18);System.out.println(person);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person);System.err.println(dto);}
}
Person(name=null, age=18)
PersonDTO(name=xiaofei, age=18)

5.4 当属性名不一致时

需求:将Person转成PersonDTO,属性名不一致要做映射

import lombok.Data;
import lombok.AllArgsConstructor;
@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.Data;
@Data
public class PersonDTO {private String nameDTO;private int ageDTO;
}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);@Mappings({@Mapping(source = "name", target = "nameDTO"),@Mapping(source = "age", target = "ageDTO")})PersonDTO toDTO(Person person);
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18);System.out.println(person);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person);System.err.println(dto);}
}
Person(name=dafei, age=18)
PersonDTO(nameDTO=dafei, ageDTO=18)

5.5 当源对象是多个时

需求:将Person, Phone转成PersonDTO

即:PersonDTO(name, age, phone) = Person(name, age) + Phone(id, phone)

import lombok.Data;
import lombok.AllArgsConstructor;
@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Phone {private Long id;private String phone;
}
import lombok.Data;@Data
public class PersonDTO {private String name;private int age;private String phone;
}

在这里插入图片描述

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);@Mappings({@Mapping(source = "person.name", target = "name"),@Mapping(source = "person.age", target = "age"),@Mapping(source = "phone.phone", target = "phone")})PersonDTO toDTO(Person person, Phone phone);
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18);System.out.println(person);Phone phone = new Phone(1L, "13700000000");System.out.println(phone);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person, phone);System.err.println(dto);}
}
Person(name=dafei, age=18)
Phone(id=1, phone=13700000000)
PersonDTO(name=dafei, age=18, phone=13700000000)

5.6 当属性为对象时

需求:将Person, Phone转成PersonDTO, 其中Phone是PersonDTO的属性

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Phone {private Long id;private String phone;
}
import lombok.Data;@Data
public class PersonDTO {private String name;private int age;private Phone phone;
}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);@Mappings({@Mapping(source = "person.name", target = "name"),@Mapping(source = "person.age", target = "age"),@Mapping(source = "phone.id", target = "phone.id"),@Mapping(source = "phone.phone", target = "phone.phone"),})PersonDTO toDTO(Person person, Phone phone);
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18);System.out.println(person);Phone phone = new Phone(1L, "13700000000");System.out.println(phone);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person, phone);System.err.println(dto);}
}
Person(name=dafei, age=18)
Phone(id=1, phone=13700000000)
PersonDTO(name=dafei, age=18, phone=Phone(id=1, phone=13700000000))

5.7 当目标对象已经存在时

需求:将Person转成PersonDTO, 其中PersonDTO对象已经提前被创建好了

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;
}
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);void copy(Person source, @MappingTarget PersonDTO target);
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18);System.out.println(person);PersonDTO dto = new PersonDTO("xiaofei", 17);PersonMapper.INSTANCE.copy(person, dto);System.err.println(dto);}
}
Person(name=dafei, age=18)
PersonDTO(name=dafei, age=18)

5.8 当属性类型对不上时

5.8.1 源是时间,目标是字符串

需求:将Person转成PersonDTO,Person有个属性是Date类型

import lombok.AllArgsConstructor;
import lombok.Data;import java.util.Date;@Data
@AllArgsConstructor
public class Person {private String name;private int age;private Date birth;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;private String birth;
}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);@Mapping(target = "birth", dateFormat = "yyyy-MM-dd")PersonDTO toDTO(Person person);
}
import java.util.Date;public class App {public static void main(String[] args) {Person person = new Person("dafei", 18, new Date());System.out.println(person);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person);System.err.println(dto);}
}
Person(name=dafei, age=18, birth=Thu Dec 05 18:01:28 CST 2024)
PersonDTO(name=dafei, age=18, birth=2024-12-05)

5.8.2 源是字符串,目标是枚举

需求:将Person转成PersonDTO,PersonDTO有个属性是枚举类型

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;private String sex;
}
import lombok.Getter;public enum Sex {MAN("男"), WOMAN("女"),YAO("妖");@Getterprivate String name;private Sex(String name){this.name = name;}
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;private Sex sex;
}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);@Mapping(target = "sex", source = "sex",  qualifiedByName = "mapStringToSex")PersonDTO toDTO(Person person);@Named("mapStringToSex")default Sex mapStringToSex(String sex){if (sex == null) {return null;}switch (sex) {case "男":return Sex.MAN;case "女":return Sex.WOMAN;case "妖":return Sex.YAO;default:throw new IllegalArgumentException("Unknown sex: " + sex);}}
}
public class App {public static void main(String[] args) {Person person = new Person("dafei", 18, "男");System.out.println(person);PersonDTO dto = PersonMapper.INSTANCE.toDTO(person);System.err.println(dto);}
}

5.9 当源是集合时

需求:将 List<Person>转成 List<PersonDTO>

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;
}
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;import java.util.List;@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);List<PersonDTO> toDTOList(List<Person> personList);
}
import java.util.ArrayList;
import java.util.List;public class App {public static void main(String[] args) {List<Person> personList = new ArrayList<>();for (int i = 0; i < 10; i++){personList.add(new Person("dafei_" + i, i));}List<PersonDTO> personDTOS = PersonMapper.INSTANCE.toDTOList(personList);personDTOS.forEach(System.out::println);}
}

六、SpringBoot集成

MapStruct基本操作算差不多了,来看下在SpringBoot环境下,该如何操作

步骤1:将项目改造成SpringBoot环境

<parent><artifactId>spring-boot-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.7.11</version>
</parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency>

步骤2:具体代码

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Person {private String name;private int age;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class PersonDTO {private String name;private int age;
}
import org.mapstruct.Mapper;@Mapper(componentModel = "spring")
public interface PersonMapper {PersonDTO toDTO(Person person);
}

这里要注意@Mapper(componentModel = "spring") 表示将PersonMapper对象创建并交个Spring容器管理

步骤3:测试

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}

测试类

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class MapperTest {//直接引入即可@Autowiredprivate PersonMapper personMapper;@Testpublic void testDto(){Person person = new Person("dafei", 18);PersonDTO personDTO = personMapper.toDTO(person);System.out.println(personDTO);}
}

七、项目实战

需求:实现Bean对转换DTO, List<Bean> 转换List<DTO> Map<String, Bean>转换 Map<String, DTO>

步骤1:定义2个实体bean与DTO

import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class User {private Long id;private String username;private String password;
}import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class UserDTO {private Long id;private String username;private String password;
}
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Employee {private Long id;private String username;private String password;
}import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class EmployeeDTO {private Long id;private String username;private String password;
}

步骤2:转换规则与实现

import java.util.List;
import java.util.Map;/*** bean and dto transformation base mapper* @param <T>* @param <V>*/
public interface BaseConverter<T,V> {V bean2dto(T bean);T dto2bean(V dto);List<V> beans2dtoList(List<T> beans);List<T> dtoList2beans(List<V> dtoList);Map<String,V>beanMap2dtoMap(Map<String,T> beanMap);Map<String,T>dtoMap2beanMap(Map<String,V>dtoMap);Map<String,List<T>>dtoMapList2beanMapList(Map<String,List<V>>dtoMap);Map<String,List<V>>beanMapList2dtoMapList(Map<String,List<T>>beanMap);
}
import org.mapstruct.Mapper;@Mapper(componentModel = "spring")
public interface UserConverter extends BaseConverter<User, UserDTO>{
}
import org.mapstruct.Mapper;@Mapper(componentModel = "spring")
public interface EmployeeConverter extends BaseConverter<Employee, EmployeeDTO>{
}

步骤3:启动与测试

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.Arrays;
import java.util.List;@SpringBootTest
public class MapperTest {@Autowiredprivate UserConverter userConverter;@Autowiredprivate EmployeeConverter employeeConverter;@Testpublic void testDto(){User user = new User(1L, "dafei", "666");UserDTO userDTO = userConverter.bean2dto(user);List<UserDTO> userDTOList = userConverter.beans2dtoList(Arrays.asList(new User(2L, "xiaofei", "777")));System.out.println(userDTO);System.out.println(userDTOList);Employee employee = new Employee(1L, "dafei", "666");EmployeeDTO employeeDTO = employeeConverter.bean2dto(employee);List<EmployeeDTO> employeeDTOList = employeeConverter.beans2dtoList(Arrays.asList(new Employee(2L, "xiaofei", "777")));System.out.println(employeeDTO);System.out.println(employeeDTOList);}
}

http://www.hkcw.cn/article/dCPLZgUeHR.shtml

相关文章

switch-case判断

switch-case判断 #include <stdio.h> int main() {int type;printf("请输入你的选择&#xff1a;\n");scanf("%d",&type);getchar();switch (type){case 1:printf("你好&#xff01;");break;case 2:printf("早上好&#xff01;…

德拜温度热容推导

目录 一、背景与基本假设 一、态密度的定义 二、从波矢空间出发 三、振动模式数与波矢体积关系 四、模式总数计算 五、态密度求导 六、德拜频率确定与归一化条件 二、内能表达式的推导 三、态密度代入与变量替换 四、求比热容 五、低温时&#xff08;&#xff09; …

Android Framework层RenderThread指令队列深度调试实战指南

简介 在移动应用开发过程中,UI渲染性能优化是提升用户体验的关键环节。Android的RenderThread作为硬件加速渲染的核心线程,其指令队列的处理效率直接影响着应用的流畅度。本篇文章将深入探讨如何在Android Framework层对RenderThread指令队列进行调试和优化,帮助开发者解决…

BLE协议全景图:从0开始理解低功耗蓝牙

BLE(Bluetooth Low Energy)作为一种针对低功耗场景优化的通信协议,已经广泛应用于智能穿戴、工业追踪、智能家居、医疗设备等领域。 本文是《BLE 协议实战详解》系列的第一篇,将从 BLE 的发展历史、协议栈结构、核心机制和应用领域出发,为后续工程实战打下全面认知基础。 …

深入理解C#异步编程:原理、实践与最佳方案

在现代软件开发中&#xff0c;应用程序的性能和响应能力至关重要。特别是在处理I/O密集型操作&#xff08;如网络请求、文件读写、数据库查询&#xff09;时&#xff0c;传统的同步编程方式会导致线程阻塞&#xff0c;降低程序的吞吐量。C# 的异步编程模型&#xff08;async/aw…

如何查看电脑电池性能

检查电脑电池性能的方法如下&#xff1a; 按下winR键&#xff0c;输入cmd回车&#xff0c;进入命令行窗口 在命令行窗口输入powercfg /batteryreport 桌面双击此电脑&#xff0c;把刚刚复制的路径粘贴到文件路径栏&#xff0c;然后回车 回车后会自动用浏览器打开该报告 红…

高考加油!UI界面生成器!

这个高考助力标语生成器具有以下特点&#xff1a; 视觉设计&#xff1a;采用了蓝色为主色调&#xff0c;搭配渐变背景和圆形装饰元素&#xff0c;营造出宁静而充满希望的氛围&#xff0c;非常适合高考主题。 标语生成&#xff1a;内置了超过 100 条精心挑选的高考加油标语&a…

fork函数小解

学了好久终于搞懂fork函数的一些作用 1. fork函数作用&#xff1a;用于创建新的子进程 这是fork最根本的功能&#xff0c;在父进程里创建新的子进程、 但是创建新的子进程之后呢&#xff1f; 子进程和父进程的关系是什么样的&#xff1f; 为什么fork得到的子进程返回值为0&am…

5月31日day41打卡

简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 → Batch…

配置前端控制器

一、DispatcherServlet 详解 在使用 Spring MVC 框架构建 Web 应用时&#xff0c;DispatcherServlet是整个请求处理流程的核心。本文将深入解析DispatcherServlet的作用、工作原理及其在 Spring MVC 架构中的关键地位。 1.DispatcherServlet 是什么&#xff1f; DispatcherS…

使用PowerBI个人网关定时刷新数据

使用PowerBI个人网关定时刷新数据 PowerBI desktop连接mysql&#xff0c;可以设置定时刷新数据或在PowerBI服务中手动刷新数据,步骤如下&#xff1a; 第一步&#xff1a; 下载网关。以个人网关为例&#xff0c;如图 第二步&#xff1a; 双击网关&#xff0c;点击下一步&…

Dest建筑能耗模拟仿真功能简介

Dest建筑能耗模拟仿真功能简介 全球建筑能耗占终端能源消费的30%以上&#xff0c;掌握建筑能耗模拟是参与绿色建筑认证&#xff08;如LEED、WELL&#xff09;、超低能耗设计、既有建筑节能改造的必备能力。DEST作为国内主流建筑能耗模拟工具&#xff0c;广泛应用于设计院、咨询…

Vue2+Vuex通过数组动态生成store数据(分组模式)

在项目开发中,将数据集中存储在Vuex的store中,能便于数据的统一管理和维护。开发者可以在一个地方对数据进行操作和更新,以避免在组件中分散管理数据带来的混乱和复杂性。 对于状态数据较多情况下,界面操作数据又是数组结构,因业务需求,数组内每个元素都需要单独定义一个…

生成式AI模型学习笔记

文章目录 生成式AI模型1. 定义2. 生成式模型与判别式模型3. 深度生成式模型的类型3.1 能量模型3.2 变分自编码3.2.1 变分自编码器&#xff08;Variational Autoencoder, VAE&#xff09;简介3.2.2 代码示例&#xff08;以 PyTorch 为例&#xff09; 3.3 生成对抗网络3.4 流模型…

DAY 16 numpy数组与shap深入理解

一、NumPy 数组基础笔记 1. 理解数组的维度 &#xff08;Dimensions&#xff09; NumPy 数组的维度 &#xff08;Dimension&#xff09; 或称为 轴 &#xff08;Axis&#xff09; 的概念&#xff0c;与我们日常理解的维度非常相似。 直观判断&#xff1a; 数组的维度层数通常…

Maven 安装与配置指南(适用于 Windows、Linux 和 macOS)

Apache Maven 是一款广泛应用于 Java 项目的项目管理和构建工具。 本文提供在 Windows、Linux 和 macOS 系统上安装与配置 Maven 的详细步骤&#xff0c;旨在帮助开发者快速搭建高效的构建环境。 一、前置条件&#xff1a;安装 Java Development Kit (JDK) Maven 依赖于 Java …

Java对象克隆:从浅到深的奥秘

浅克隆与深克隆在Java中的应用及区别 核心概念 浅克隆 复制对象时仅克隆基本数据类型字段&#xff0c;引用类型字段共享原对象引用。实现方式&#xff1a; class Person implements Cloneable {String name;Address address; // 引用类型字段Overrideprotected Object clone…

【HW系列】—日志介绍

文章目录 一、日志介绍二、Apache日志详解1. 日志存放位置2. 日志类型3. 日志级别4. 常用日志分析命令&#xff08;Linux环境&#xff09; 三、IIS日志详解四、日志分析工具&#xff1a;360星图 一、日志介绍 为什么要使用日志 故障诊断&#xff1a;快速定位系统错误根源安全审…

cuda_fp8.h错误

现象&#xff1a; cuda_fp8.h错误 原因&#xff1a; CUDA Toolkit 小于11.8,会报fp8错误&#xff0c;因此是cuda工具版本太低。通过nvcc --version查看 CUDA Toolkit 是 NVIDIA 提供的一套 用于开发、优化和运行基于 CUDA 的 GPU 加速应用程序的工具集合。它的核心作用是让开发…

内容中台构建数字化管理新路径

数字化内容管理核心架构 现代企业数字化内容管理的核心架构依托于动态元数据架构构建策略与多源数据智能整合体系的双重支撑。通过建立三层架构模型——数据采集层、逻辑处理层与应用服务层&#xff0c;系统能够实现跨平台内容资产的统一索引与语义关联。其中&#xff0c;Bakl…