属性映射框架-MapStruct
属性映射框架-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 序列化 再反序列化
工具 | 实现方式 | 缺点 | 说明 |
---|---|---|---|
MapStruct | getter/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 BeanUtils | Spring BeanUtils | MapStruct | Orika | Dozer | BeanCopier |
---|---|---|---|---|---|
5.0647899 | 0.2621497 | 0.0231992 | 0.4941662 | 15.2818163 | 0.0086604 |
第二次:
Apache BeanUtils | Spring BeanUtils | MapStruct | Orika | Dozer | BeanCopier |
---|---|---|---|---|---|
5.1325004 | 0.2659947 | 0.0236535 | 0.4825087 | 15.7785451 | 0.0097842 |
第三次:
Apache BeanUtils | Spring BeanUtils | MapStruct | Orika | Dozer | BeanCopier |
---|---|---|---|---|---|
4.9120256 | 0.2792479 | 0.0235294 | 0.5094648 | 15.7023685 | 0.0094256 |
从上面的测试
性能由高到低
BeanCopier > MapStruct > Spring BeanUtils > Orika > Apache BeanUtils > Dozer
1 2.5 30 54 520 1665
结论:
按理 BeanCopier 性能最佳,但是它有个明显的缺陷:属性名与类型必须完全匹配才能转换
MapStruct 最好
2.3 适合场景
MapStruct适用于各种Java Bean之间的转换场景,包括但不限于以下情况:
- DTO
(Data Transfer Object)数据接收对象
和 Entity(PO)即实体类它与数据库表中的字段是一一对应的
之间的转换。 - 不同版本API之间的数据映射。
- 前端页面展示数据和后端数据模型之间的转换。
大白话:各种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);}
}