老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实体字段特别多的时候。有的人会说,我直接使用get/set方法。没错,get/set方法的确可以解决,而且也是性能较高的处理方法,但是大家有没有想过,要是转换的实体字段比较多,那么get/set方法的代码量是非常恐怖的;有人会说,用自带的BeanUtils工具类,但在属性拷贝的过程中,会遇到类型转换异常,或是影响性能等等问题。所以,我把自己项目中使用的这款转换神器分享出来。BeanUtils属性复制
之前对各种属性映射工具的性能进行了简单的对比,结果如下:
先贴下官网地址吧:https://mapstruct.org/
1.8
UTF-8
UTF-8
3.5.3.1
1.18.26
8.0.30
1.2.4
3.0.15.RELEASE
3.0.12.RELEASE
1.5.3.Final
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-data-jpa
com.baomidou
mybatis-plus-boot-starter
${mybatisPlus.version}
org.projectlombok
lombok
${lombok.version}
mysql
mysql-connector-java
${mysql.version}
com.alibaba
druid-spring-boot-starter
${alibaba.druid.version}
org.thymeleaf
thymeleaf
${thymeleaf.version}
org.thymeleaf
thymeleaf-spring4
${spring4.version}
org.springframework.boot
spring-boot-devtools
true
org.mapstruct
mapstruct
${mapstruct.version}
org.springframework.boot
spring-boot-maven-plugin
true
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
${java.version}
org.projectlombok
lombok
${lombok.version}
org.mapstruct
mapstruct-processor
${mapstruct.version}
PS:lombok和mapstruct的版本兼容问题(可以直接使用上面pom里的版本)
1、maven插件要使用3.6.0版本以上;
2、lombok使用1.16.16版本以上;
3、另外编译的lombok和mapstruct的插件不要忘了加上。否则会出现下面的错误:No property named "aaa" exists in source parameter(s). Did you mean "null"?
⑴.源实体1:
package com.***;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* 学生
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Student {
/*** ID*/
private Long userId;
/*** 姓名*/
private String name;
/*** 年龄*/
private Integer age;
/*** 手机号*/
private String phone;
/*** 性别(1男 2女)*/
private Integer sex;
/*** 生日*/
private String birthday;
/*** 创建时间*/
private Date createTime;
}
⑵.源实体2:
package com.***;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 课程
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Course {
/*** 课程ID*/
private Long courseId;
/*** 课程名称*/
private String courseName;
/*** 序号*/
private Integer sortNo;
}
⑶.目标实体1:
package com.***;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* 学生Vo
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentVo {
/***用户ID */
private Long userId;
/*** 姓名*/
private String name;
/*** 年龄*/
private Integer age;
/*** 手机号*/
private String phone;
/*** 性别(1男 2女)*/
private Integer gender;
/*** 生日*/
private String birthday;
/*** 创建时间*/
private Date createTime;
}
⑷.目标实体2:
package com.***;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 学生课程Vo
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentCourseVo {
/*** 学生姓名*/
private String name;
/*** 年龄*/
private Integer age;
/*** 性别(1男 2女)*/
private String gender;
/*** 生日*/
private String birthday;
/*** 课程名称*/
private String course;
}
⑸.转换Mapper接口:(编译完成后会自动生成相应的实现类)
package com.***;
import com.test.java.domain.entity.Course;
import com.test.java.domain.entity.Student;
import com.test.java.domain.vo.StudentCourseVo;
import com.test.java.domain.vo.StudentVo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 转换mapper
*/
@Mapper
public interface StudentWrapper {
StudentWrapper INSTANCE = Mappers.getMapper(StudentWrapper.class);
// 转换一:实体转实体
@Mapping(target = "userId", ignore = true)
@Mapping(source = "sex", target = "gender")
@Mapping(target = "createTime", expression = "java(new java.util.Date())")
@Mapping(source = "name", target = "name", defaultValue = "张三")
StudentVo convertVo(Student student);
// 转换二:list转list
List convertList(List list);
// 转换三:多对象转换一个对象
@Mapping(source = "student.sex", target = "gender")
@Mapping(source = "course.courseName", target = "course")
StudentCourseVo convertTo(Student student, Course course);
}
现在就可以直接使用mapper接口进行属性转换了,以下举例有三种转换用法:
1、转换一:对象转对象
2、转换二:集合转集合
3、转换三:多个对象转单一对象
public static void main(String[] args) {
// 转换一
Student student = Student.builder().userId(100L).age(18).phone("13012345678").sex(1).birthday("01-01").build();
StudentVo convertVo = StudentWrapper.INSTANCE.convertVo(student);
System.out.println("转换一、实体转实体:" + convertVo);
// 转换二
Student student1 = Student.builder().userId(1L).name("张三").age(18).phone("13012345678").sex(1).birthday("01-01").createTime(new Date()).build();
Student student2 = Student.builder().userId(2L).name("李四").age(20).phone("15026668652").sex(2).birthday("05-01").createTime(new Date()).build();
List list = new ArrayList<>();
list.add(student1);
list.add(student2);
List convertList = StudentWrapper.INSTANCE.convertList(list);
System.out.println("转换二、list转list:" + convertList);
// 转换三
Student student3 = Student.builder().name("小明").age(18).phone("13512365568").sex(1).birthday("05-06").createTime(new Date()).build();
Course course = Course.builder().courseName("《Java从入门到放弃》").sortNo(1).build();
StudentCourseVo convertTo = StudentWrapper.INSTANCE.convertTo(student3, course);
System.out.println("转换三、多对象转换一个对象:" + convertTo);
}
转换结果:
mapper转换接口中,还可以进行字段映射,改变字段类型,指定格式化、赋予默认值、过滤不需要转换的字段、自定义转换等方式,包括一些日期的默认处理,只需在@Mapping注解中添加相应参数即可,如下:
@Mapping(source = "sex", target = "gender")
StudentVo convertVo(Student student);
source:代表源字段;
target:代表目标字段;
@Mapping(source = "createTime",target = "createTime",dateFormat = "yyyy-MM-dd HH:mm:ss")
StudentVo convertVo(Student student);
@Mapping(source = "name", target = "name", defaultValue = "张三")
StudentVo convertVo(Student student);
defaultValue:转换时,赋予默认值;
@Mapping(target = "userId", ignore = true)
StudentVo convertVo(Student student);
ignore:默认为false,不过滤;
@Mapping(target = "createTime", expression = "java(new java.util.Date())")
StudentVo convertVo(Student student);
expression:自定义转换规则,当前案例是createTime字段获取当前系统时间
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。