深入理解Java對象復(fù)制
一、圖示

二、MapStruct
pom文件
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
<!-- dozer使用時需要配置xml 文件,不推薦使用性能和 BeanUtils 差不多,使用過程可以參考 https://www.jianshu.com/p/bf8f0e8aee23-->
<!-- https://mvnrepository.com/artifact/net.sf.dozer/dozer -->
<!--<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>-->
下載插件
插件的作用是為了在本地測試的時候,生成 接口的 impl 文件(生成的文件存在與target包里面)
如果是生產(chǎn)環(huán)境的話,和Lombok操作一樣,需要在pom文件添加 mapStruct 插件依賴
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showWarnings>true</showWarnings>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

代碼
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Created by yangLongFei on 2021/5/11 10:44
* Version: $
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName
public class Student {
private Integer id;
private String name;
private String age;
private String phone;
private String address;
}
import lombok.Data;
import java.io.Serializable;
/**
* Created by yangLongFei on 2021/5/11 10:51
* Version: $
*/
@Data
public class StudentDTO implements Serializable {
private static final long serialVersionUID = 735190899850778343L;
private Integer id;
private String name;
private String age;
private String phone;
private String address;
}
import lombok.Data;
import java.io.Serializable;
/**
* Created by yangLongFei on 2021/5/11 16:59
* Version: $
*/
@Data
public class StudentVO implements Serializable {
private static final long serialVersionUID = 2059190505074790405L;
private Integer pk;
private String userName;
private String userAge;
private String userPhone;
private String userAddress;
}
接口
import com.sys.yang.dto.StudentDTO;
import com.sys.yang.entity.Student;
import com.sys.yang.vo.StudentVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface ConverterStudent {
ConverterStudent INSTANCE = Mappers.getMapper(ConverterStudent.class);
@Mappings({
@Mapping(source = "name", target = "name"),
@Mapping(source = "age", target = "age")
})
StudentDTO entityToDTO(Student student);
@Mappings({
@Mapping(source = "id", target = "pk"),
@Mapping(source = "name", target = "userName"),
@Mapping(source = "age", target = "userAge"),
@Mapping(source = "phone", target = "userPhone"),
@Mapping(source = "address", target = "userAddress")
})
StudentVO dtoToVo(StudentDTO studentDTO);
}
測試類
import com.sys.yang.dto.StudentDTO;
import com.sys.yang.entity.Student;
import com.sys.yang.vo.StudentVO;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import java.lang.reflect.Method;
/**
* 對象轉(zhuǎn)換,映射
* 方式1:效率最高 get set 方法
* 方式2:Common包 BeanUtils.copyProperties 反射的方式進行
* 方式3:mapstruct 推薦使用,操作不復(fù)雜,效率和 get set 方式相差不大
*
* <p>
* Created by yangLongFei on 2021/5/11 10:43
* Version: $
*/
public class AToB {
/**
* set get 的時候使用
* 生成 對象的set方法
*/
public static void main(String[] args) {
Class<StudentDTO> clazz = StudentDTO.class;
Method[] fields = clazz.getDeclaredMethods();
for (Method field: fields) {
String name = field.getName();
if(!name.startsWith("is") && !name.startsWith("get")){
System.out.println("entity." + name + "()");
}
}
}
/**
* 測試方法
*/
@Test
public void test1() {
Student student = new Student(1,"zhagnsan","18","110112113114","diqiu");
System.out.println(student.toString());
StudentDTO studentDTO1 = new StudentDTO();
BeanUtils.copyProperties(student,studentDTO1);
System.out.println("BeanUtils: "+ studentDTO1.toString());
StudentDTO studentDTO2 = ConverterStudent.INSTANCE.entityToDTO(student);
System.out.println("mapstruct: entityToDTO " + studentDTO2.toString());
StudentVO studentVO = ConverterStudent.INSTANCE.dtoToVo(studentDTO2);
System.out.println("mapStruct: dtoToVo "+ studentVO);
}
}
生成的接口文件

三、framework cglib
要轉(zhuǎn)換的對象的,字段名稱 要和 原對象的字段名稱一致,否則賦值會失敗,可以手動 convert 方法,但是,實現(xiàn)后所有的轉(zhuǎn)換內(nèi)容都會走 convert 方法
代碼
import lombok.Data;
import java.io.Serializable;
/**
* Created by yangLongFei on 2021/5/11 16:59
* Version: $
*/
@Data
public class StudentVO implements Serializable {
private static final long serialVersionUID = 2059190505074790405L;
private Integer pk;
private String userName;
private String userAge;
private String userPhone;
private String userAddress;
// framework cglib 使用到的內(nèi)容
private String id;
private String name;
private Integer age;
private String phone;
private String address;
}
convert 實現(xiàn)類
import org.springframework.cglib.core.Converter;
/**
* Created by yangLongFei on 2021/5/11 19:53
* Version: $
*/
public class ConvertStudentDtoToVo implements Converter {
/**
* ⭐️⭐️⭐️⭐️⭐️ 要轉(zhuǎn)換的屬性名稱,相同的情況下,才會走該方法
* @param o 原對象屬性值,value
* @param aClass 目標對象屬性 類型,class java.lang.String
* @param o1 目標對象屬性set方法,setAddress
* @return
*/
@Override
public Object convert(Object o, Class aClass, Object o1) {
if (o.getClass().equals(aClass)) {
return o;
} else {
if (o instanceof Integer) {
return String.valueOf(o);
}
if (String.valueOf(o1).contains("Age")) {
return Integer.valueOf(o.toString());
}
return o;
}
}
}
測試方法
@Test
public void test2() {
Student student = new Student(1,"zhagnsan","18","110112113114","diqiu");
// false 表示不使用 轉(zhuǎn)換器,
BeanCopier entityToDto = BeanCopier.create(Student.class, StudentDTO.class, false);
StudentDTO studentDTO3 = new StudentDTO();
// null 表示,不指定轉(zhuǎn)換器,要使用轉(zhuǎn)換器的化,需要實現(xiàn) Converter 接口
// 屬性名稱之間不能指定映射關(guān)系,當屬性名稱不同的時候賦值操作會失敗
entityToDto.copy(student, studentDTO3, null);
System.out.println("cglib :entityToDTO " + studentDTO3.toString());
BeanCopier dtoTOVo = BeanCopier.create(StudentDTO.class, StudentVO.class, false);
StudentVO studentVO1 = new StudentVO();
dtoTOVo.copy(studentDTO3, studentVO1, null);
System.out.println("cglib: dtoToVo " + studentVO1.toString());
// 一旦使用Converter,BeanCopier只使用Converter定義的規(guī)則去拷貝屬性,所以在convert方法中要考慮所有的屬性
BeanCopier dtoTOVo2 = BeanCopier.create(StudentDTO.class, StudentVO.class, true);
StudentVO studentVO2 = new StudentVO();
dtoTOVo2.copy(studentDTO3, studentVO2, new ConvertStudentDtoToVo());
System.out.println("cglib : convert "+studentVO2.toString());
}
四、問題
beanUtils 不會進行 屬性 類型的轉(zhuǎn)換,如果字段名稱相同,類型不同,不會對該字段進行賦值操作,( 測試方法中使用的 是 org.springframework.beans.BeanUtils )
cglib 在不定義Converter 的情況下也會出現(xiàn) 類型轉(zhuǎn)換錯誤的異常,可以手動自定義轉(zhuǎn)換器 convert ,一旦使用Converter,BeanCopier只使用Converter定義的規(guī)則去拷貝屬性,所以在convert方法中要考慮所有的屬性。
springframwork 有實現(xiàn) cglib 的BeanCopier 不需要再引用 org.easymock 依賴
到此這篇關(guān)于深入理解Java對象復(fù)制的文章就介紹到這了,更多相關(guān)Java對象復(fù)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java 枚舉類定義靜態(tài)valueOf(java.lang.String)方法的問題及解決
這篇文章主要介紹了java 枚舉類定義靜態(tài)valueOf(java.lang.String)方法的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
springboot內(nèi)置tomcat之NIO處理流程一覽
這篇文章主要介紹了springboot內(nèi)置tomcat之NIO處理流程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
沒有編輯器的環(huán)境下是如何創(chuàng)建Servlet(Tomcat+Java)項目的?
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著在沒有編輯器的環(huán)境下如何創(chuàng)建Servlet(Tomcat+Java)項目展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下2021-06-06
基于eclipse-temurin鏡像部署spring boot應(yīng)用的實現(xiàn)示例
本文提供了基于eclipse-temurin鏡像部署Spring Boot應(yīng)用的詳細實現(xiàn)示例,通過使用Docker鏡像,可以輕松地創(chuàng)建和管理Spring Boot應(yīng)用程序的容器化環(huán)境,感興趣的可以了解一下2023-08-08
java CompletableFuture實現(xiàn)異步編排詳解
這篇文章主要為大家介紹了java CompletableFuture實現(xiàn)異步編排詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
Java線程編程中isAlive()和join()的使用詳解
這篇文章主要介紹了Java線程編程中isAlive()和join()的使用詳解,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09

