別再用 BeanUtils 了,這款 PO VO DTO 轉換神器不香麼?
阿新 • • 發佈:2021-12-13
點選“終碼一生”,關注,置頂公眾號
每日技術乾貨,第一時間送達!
1、前言
老鐵們是不是經常為寫一些實體轉換的原始程式碼感到頭疼,尤其是實體欄位特別多的時候。介紹一個開源專案 mapstruct ,可以輕鬆優雅的進行轉換,簡化你的程式碼。
當然有的人喜歡寫get set,或者用BeanUtils 進行復制,程式碼只是工具,本文只是提供一種思路。
先貼下官網地址吧:https://mapstruct.org/
廢話不多說,上程式碼:
pom.xml 配置:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <org.mapstruct.version>1.4.1.Final</org.mapstruct.version> <org.projectlombok.version>1.18.12</org.projectlombok.version> </properties> <dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> </dependency> <!-- lombok dependencies should not end up on classpath --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${org.projectlombok.version}</version> <scope>provided</scope> </dependency> <!-- idea 2018.1.1 之前的版本需要新增下面的配置,後期的版本就不需要了,可以註釋掉, 我自己用的2019.3 --> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> <scope>provided</scope> </dependency> </dependencies>
關於lombok和mapstruct的版本相容問題多說幾句,maven外掛要使用3.6.0版本以上、lombok使用1.16.16版本以上,另外編譯的lombok mapstruct的外掛不要忘了加上。否則會出現下面的錯誤:No property named "aaa" exists in source parameter(s). Did you mean "null"?
這種異常就是lombok編譯異常導致缺少get setter方法造成的。還有就是缺少建構函式也會拋異常。
另外,關注公號“終碼一生”,回覆關鍵詞“資料”,獲取視訊教程和最新的面試資料!
@Data @Builder @AllArgsConstructor @NoArgsConstructor publicclassStudent { privateStringname; privateint age; privateGenderEnum gender; privateDouble height; privateDatebirthday; } publicenumGenderEnum { Male("1","男"), Female("0","女"); privateStringcode; privateStringname; publicStringgetCode() { returnthis.code; } publicStringgetName() { returnthis.name; } GenderEnum(Stringcode,Stringname) { this.code = code; this.name = name; } } @Data @Builder @AllArgsConstructor @NoArgsConstructor publicclassStudentVO { privateStringname; privateint age; privateStringgender; privateDouble height; privateStringbirthday; } @Mapper publicinterfaceStudentMapper { StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class); @Mapping(source ="gender.name", target ="gender") @Mapping(source ="birthday", target ="birthday", dateFormat ="yyyy-MM-dd HH:mm:ss") StudentVO student2StudentVO(Student student); }
實體類是開發過程少不了的,就算是用工具生成肯定也是要有的,需要手寫的部分就是這個Mapper的介面,編譯完成後會自動生成相應的實現類。
然後就可以直接用mapper進行實體的轉換了
publicclassTest{ publicstaticvoidmain(String[] args){ Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(newDate()).build(); System.out.println(student); //這行程式碼便是實際要用的程式碼 StudentVO studentVO = StudentMapper.INSTANCE.student2StudentVO(student); System.out.println(studentVO); } }
mapper可以進行欄位對映,改變欄位型別,指定格式化的方式,包括一些日期的預設處理。
可以手動指定格式化的方法:
@Mapper
publicinterfaceStudentMapper{
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mapping(source ="gender", target ="gender")
@Mapping(source ="birthday", target ="birthday", dateFormat ="yyyy-MM-dd HH:mm:ss")
StudentVOstudent2StudentVO(Student student);
defaultStringgetGenderName(GenderEnum gender){
returngender.getName();
}
}
上面只是最簡單的實體對映處理,下面介紹一些高階用法:
2、List 轉換
屬性對映基於上面的mapping配置
@Mapper
publicinterfaceStudentMapper{
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mapping(source ="gender.name", target ="gender")
@Mapping(source ="birthday", target ="birthday", dateFormat ="yyyy-MM-dd HH:mm:ss")
StudentVO student2StudentVO(Student student);
List<StudentVO> students2StudentVOs(List<Student> studentList);
}
publicstaticvoid main(String[] args) {
Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(newDate()).build();
List<Student>list=newArrayList<>();
list.add(student);
List<StudentVO> result = StudentMapper.INSTANCE.students2StudentVOs(list);
System.out.println(result);
}
3、多物件轉換到一個物件
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
publicclassStudent{
privateString name;
privateintage;
privateGenderEnum gender;
privateDouble height;
privateDate birthday;
}
@Data
@AllArgsConstructor
@Builder
@NoArgsConstructor
publicclassCourse{
privateString courseName;
privateintsortNo;
privatelongid;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
publicclassStudentVO{
privateString name;
privateintage;
privateString gender;
privateDouble height;
privateString birthday;
privateString course;
}
@Mapper
publicinterfaceStudentMapper{
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mapping(source ="student.gender.name", target ="gender")
@Mapping(source ="student.birthday", target ="birthday", dateFormat ="yyyy-MM-dd HH:mm:ss")
@Mapping(source ="course.courseName", target ="course")
StudentVOstudentAndCourse2StudentVO(Student student, Course course);
}
publicclassTest{
publicstaticvoidmain(String[] args){
Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(newDate()).build();
Course course = Course.builder().id(1L).courseName("語文").build();
StudentVO studentVO = StudentMapper.INSTANCE.studentAndCourse2StudentVO(student, course);
System.out.println(studentVO);
}
}
3、預設值
@Mapper
publicinterfaceStudentMapper{
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mapping(source ="student.gender.name", target ="gender")
@Mapping(source ="student.birthday", target ="birthday", dateFormat ="yyyy-MM-dd HH:mm:ss")
@Mapping(source ="course.courseName", target ="course")
@Mapping(target ="name", source ="student.name", defaultValue ="張三")
StudentVOstudentAndCourse2StudentVO(Student student, Course course);
}
PS:防止找不到本篇文章,可以收藏點贊,方便翻閱查詢哦。