当前位置:网站首页>【详细】快速实现对象映射的几种方式
【详细】快速实现对象映射的几种方式
2022-07-06 01:19:00 【菜鸟是大神】
项目开发过程中,经常需要编写model之间的转换,最常见的有:
- 实体转DTO
- DTO转实体
- …
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 实体:User
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String email;
private String username;
private String password;
private Integer gender;
private Date birthday;
}
// DTO:UserRegisterReq
@Data
public class UserRegisterReq {
private String username;
private String password;
private String confirmPassword;
private String email;
}
|
其中:
- UserRegisterReq是用户注册时,Controller层的请求入参
- User是用户实体
在执行注册时,我们需要将UserRegisterReq转换成User对象,再存储到数据库。此时,我们往往会编写类似如下的代码:
1 2 3 4 5 6 7 8 9 | @PostMapping("/users/reg")
public void reg(@RequestBody UserRegisterReq userRegisterReq) {
// 省略password 与 confirmPassword等值判断
User user = new User();
user.setEmail(userRegisterReq.getEmail());
user.setPassword(userRegisterReq.getPassword());
user.setUsername(userRegisterReq.getUsername());
// 保存user...
}
|
如上的代码虽然可行,但是如果类里面的field非常多,那么就会比较麻烦——我们写了一堆代码,只不过是为了实现对象的转换而已。
方法一、IDEA插件快速转换
IDEA提供GenerateAllSetter插件,可帮助我们快速生成上述代码。
- 插件主页:GenerateAllSetter - IntelliJ IDEs Plugin | Marketplace
- GitHub:GitHub - gejun123456/intellij-generateAllSetMethod: Intellij plugin to generate call to setter method value for class
演示如下图:

只需安装插件,然后按Alt + Enter(macOS则是Option + Enter),即可自动生成对象转换代码。
方法二、借助对象映射框架实现对象转换
方法一虽然很方便,但如果对象的字段非常多,那么还是会导致代码非常啰嗦,不够简洁。
事实上,Java生态有很多对象映射框架,专门帮助我们实现对象间的转换。这里笔者列出了业界相对常用的选项:
| 产品 | Dozer | Orika | MapStruct | CGLib BeanCopier | Spring BeanUtils | Apache BeanUtils |
|---|---|---|---|---|---|---|
| GitHub | dozer 1.9K stars | orika 1.2K stars | mapstruct 5K stars | cglib 4.3K stars | - | commons-beanutils 0.2K stars |
| 工作原理 | 大量反射,主要基于Field.set(obj, obj)为field赋值 | 基于javassist生成对象映射字节码,并加载生成的字节码文件 | 基于JSR269,在在编译期生成对象映射代码 | 基于ASM的MethodVisitor为field赋值 | 基于Spring反射工具类 | 基于反射 |
| 性能排名 | 5 | 2 | 1 | 4 | 3 | 6 |
虽然选项很多,但笔者目前只建议大家使用MapStruct。
MapStruct优势:
- 编译器生成Getter/Setter,无运行期性能损耗,性能强劲
- 基于JSR269,配置灵活
- 基于Getter/Setter,和自己手写Getter/Setter没有区别,搜索字段引用等较方便
缺点:
- 由于配置灵活,所以上手成本比其他组件稍微高一点点
MapStruct上手
配置IDE
参考 IDE Support – MapStruct ,配置你的IDE
整合
在项目中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
<!-- ref: https://mapstruct.org/documentation/installation/ --> <properties> <org.mapstruct.version>1.4.2.Final</org.mapstruct.version> </properties> ... <dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.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> <!-- depending on your project --> <target>1.8</target> <!-- depending on your project --> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> <!-- other annotation processors --> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>如果你的项目使用了Lombok,或使用了spring-boot-configuration-processor,则使用类似如下的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
<properties> <org.mapstruct.version>1.4.2.Final</org.mapstruct.version> </properties> ... <dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.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>8</source> <target>8</target> <encoding>UTF-8</encoding> <!-- https://mapstruct.org/documentation/installation/ --> <!-- https://mapstruct.org/documentation/stable/reference/html/#lombok --> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>0.1.0</version> </path> <path> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.4.1</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
使用
定义接口,代码类似如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
import com.itmuch.gogolive1.domain.User; import com.itmuch.gogolive1.domain.UserRegisterReq; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface UserConverter { /** * 固定写法:Mappers.getMapper(接口名.class); */ UserConverter INSTANCE = Mappers.getMapper(UserConverter.class); User toUser(UserRegisterReq req); }使用:
1 2 3 4 5 6
@PostMapping("/users/reg") public void reg2(@RequestBody UserRegisterReq userRegisterReq) { // 省略password 与 confirmPassword等值判断 User user = UserConverter.INSTANCE.toUser(userRegisterReq); // 保存user... }由代码可知,只需如下代码,即可将UserRegisterReq转换User。
1
User user = UserConverter.INSTANCE.toUser(userRegisterReq);
原理
编译代码,并在前面的UserConverter接口上,按快捷键 Command + Option + B (或点击 Navigate - Implementation(s) ) ,查找UserConverter的实现类,可跳转到类似如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-03-22T00:29:49+0800",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.9.1 (Azul Systems, Inc.)"
)
public class UserConverterImpl implements UserConverter {
@Override
public User toUser(UserRegisterReq req) {
if ( req == null ) {
return null;
}
UserBuilder user = User.builder();
user.email( req.getEmail() );
user.username( req.getUsername() );
user.password( req.getPassword() );
return user.build();
}
}
|
由代码可知,MapStruct在编译期间,生成了UserConverterImpl,并在其中实现了对象之间的转换。
和Spring整合
MapStruct支持与Spring整合,只需按如下步骤操作即可:
编写Mapper接口,并在其中添加
(componentModel = "spring")属性:1 2 3 4
@Mapper(componentModel = "spring") public interface UserSpringConverter { User toUser(UserRegisterReq req); }当使用时,只需注入
UserSpringConverter即可:1 2
@Autowired UserSpringConverter userSpringConverter;
这是因为,使用
(componentModel = "spring")后,生成的实现类会自动添加@Component注解
拓展
本文只是介绍了较为简单的例子,事实上,MapStruct支持非常灵活的配置,例如:
枚举映射
1 2 3 4 5 6 7 8 9 10 11 12
@Mapper public interface OrderMapper { OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class ); @ValueMappings({ @ValueMapping(target = "SPECIAL", source = "EXTRA"), @ValueMapping(target = "DEFAULT", source = "STANDARD"), @ValueMapping(target = "DEFAULT", source = "NORMAL") }) ExternalOrderType orderTypeToExternalOrderType(OrderType orderType); }自定义表达式映射:
1 2 3 4 5 6 7 8
@Mapper public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); @Mapping(target = "timeAndFormat", expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )") Target sourceToTarget(Source s); }
边栏推荐
- SPIR-V初窥
- Zhuhai laboratory ventilation system construction and installation instructions
- 程序员搞开源,读什么书最合适?
- The population logic of the request to read product data on the sap Spartacus home page
- Dynamic programming -- linear DP
- 037 PHP login, registration, message, personal Center Design
- General operation method of spot Silver
- Convert binary search tree into cumulative tree (reverse middle order traversal)
- JMeter BeanShell的基本用法 一下语法只能在beanshell中使用
- Who knows how to modify the data type accuracy of the columns in the database table of Damon
猜你喜欢

Basic process and testing idea of interface automation

ThreeDPoseTracker项目解析

Superfluid_ HQ hacked analysis

普通人下场全球贸易,新一轮结构性机会浮出水面

Daily practice - February 13, 2022

Some features of ECMAScript

Electrical data | IEEE118 (including wind and solar energy)

Leetcode study - day 35

VMware Tools installation error: unable to automatically install vsock driver

General operation method of spot Silver
随机推荐
Dynamic programming -- linear DP
Construction plan of Zhuhai food physical and chemical testing laboratory
Four dimensional matrix, flip (including mirror image), rotation, world coordinates and local coordinates
Basic process and testing idea of interface automation
Gartner released the prediction of eight major network security trends from 2022 to 2023. Zero trust is the starting point and regulations cover a wider range
Obstacle detection
测试/开发程序员的成长路线,全局思考问题的问题......
Cannot resolve symbol error
MobileNet系列(5):使用pytorch搭建MobileNetV3并基于迁移学习训练
毕设-基于SSM高校学生社团管理系统
Differences between standard library functions and operators
Cf:c. the third problem
Leetcode1961. Check whether the string is an array prefix
Development trend of Ali Taobao fine sorting model
直播系统代码,自定义软键盘样式:字母、数字、标点三种切换
1791. Find the central node of the star diagram / 1790 Can two strings be equal by performing string exchange only once
在产业互联网时代,将会凭借大的产业范畴,实现足够多的发展
Kotlin core programming - algebraic data types and pattern matching (3)
About error 2003 (HY000): can't connect to MySQL server on 'localhost' (10061)
Who knows how to modify the data type accuracy of the columns in the database table of Damon