老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实体字段特别多的时候。有的人会说,我直接使用get/set方法。没错,get/set方法的确可以解决,而且也是性能较高的处理方法,但是大家有没有想过,要是转换的实体字段比较多,那么get/set方法的代码量是非常恐怖的;有人会说,用自带的BeanUtils工具类,但在属性拷贝的过程中,会遇到类型转换异常,或是影响性能等等问题。所以,我把自己项目中使用的这款转换神器分享出来。BeanUtils属性复制

之前对各种属性映射工具的性能进行了简单的对比,结果如下:

先贴下官网地址吧:https://mapstruct.org/

一、pom 配置

1.8UTF-8UTF-83.5.3.11.18.268.0.301.2.43.0.15.RELEASE3.0.12.RELEASE1.5.3.Finalorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testorg.springframework.bootspring-boot-starter-thymeleaforg.springframework.bootspring-boot-starter-data-jpacom.baomidoumybatis-plus-boot-starter${mybatisPlus.version}org.projectlomboklombok${lombok.version}mysqlmysql-connector-java${mysql.version}com.alibabadruid-spring-boot-starter${alibaba.druid.version}org.thymeleafthymeleaf${thymeleaf.version}org.thymeleafthymeleaf-spring4${spring4.version}org.springframework.bootspring-boot-devtoolstrueorg.mapstructmapstruct${mapstruct.version}<!----><!-- org.mapstruct--><!-- mapstruct-processor--><!-- ${org.mapstruct.version}--><!-- provided--><!---->org.springframework.bootspring-boot-maven-plugintrueorg.apache.maven.pluginsmaven-compiler-plugin3.8.1${java.version}${java.version}org.projectlomboklombok${lombok.version}org.mapstructmapstruct-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”” />package com.***;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.util.Date;/** * 学生 */@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic 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@NoArgsConstructorpublic 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@NoArgsConstructorpublic 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@NoArgsConstructorpublic 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 */@Mapperpublic 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转listList 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字段获取当前系统时间

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。