深入理解Java對(duì)象復(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使用時(shí)需要配置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>-->
下載插件
插件的作用是為了在本地測(cè)試的時(shí)候,生成 接口的 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);
}
測(cè)試類
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;
/**
* 對(duì)象轉(zhuǎn)換,映射
* 方式1:效率最高 get set 方法
* 方式2:Common包 BeanUtils.copyProperties 反射的方式進(jìn)行
* 方式3:mapstruct 推薦使用,操作不復(fù)雜,效率和 get set 方式相差不大
*
* <p>
* Created by yangLongFei on 2021/5/11 10:43
* Version: $
*/
public class AToB {
/**
* set get 的時(shí)候使用
* 生成 對(duì)象的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 + "()");
}
}
}
/**
* 測(cè)試方法
*/
@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)換的對(duì)象的,字段名稱 要和 原對(duì)象的字段名稱一致,否則賦值會(huì)失敗,可以手動(dòng) convert 方法,但是,實(shí)現(xiàn)后所有的轉(zhuǎn)換內(nèi)容都會(huì)走 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 實(shí)現(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)換的屬性名稱,相同的情況下,才會(huì)走該方法
* @param o 原對(duì)象屬性值,value
* @param aClass 目標(biāo)對(duì)象屬性 類型,class java.lang.String
* @param o1 目標(biāo)對(duì)象屬性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;
}
}
}
測(cè)試方法
@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)換器的化,需要實(shí)現(xiàn) Converter 接口
// 屬性名稱之間不能指定映射關(guān)系,當(dāng)屬性名稱不同的時(shí)候賦值操作會(huì)失敗
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 不會(huì)進(jìn)行 屬性 類型的轉(zhuǎn)換,如果字段名稱相同,類型不同,不會(huì)對(duì)該字段進(jìn)行賦值操作,( 測(cè)試方法中使用的 是 org.springframework.beans.BeanUtils )
cglib 在不定義Converter 的情況下也會(huì)出現(xiàn) 類型轉(zhuǎn)換錯(cuò)誤的異常,可以手動(dòng)自定義轉(zhuǎn)換器 convert ,一旦使用Converter,BeanCopier只使用Converter定義的規(guī)則去拷貝屬性,所以在convert方法中要考慮所有的屬性。
springframwork 有實(shí)現(xiàn) cglib 的BeanCopier 不需要再引用 org.easymock 依賴
到此這篇關(guān)于深入理解Java對(duì)象復(fù)制的文章就介紹到這了,更多相關(guān)Java對(duì)象復(fù)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot Logback日志多文件輸出方式(按日期和大小分割)
這篇文章主要介紹了Springboot Logback日志多文件輸出方式(按日期和大小分割),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Java?數(shù)據(jù)交換?Json?和?異步請(qǐng)求?Ajax詳解
Json(JavaScript Object Notation)是一種輕量級(jí)的數(shù)據(jù)交換格式,采用鍵值對(duì)的形式來表示數(shù)據(jù),它廣泛應(yīng)用于Web開發(fā)中,特別適合于前后端數(shù)據(jù)傳輸和存儲(chǔ),這篇文章主要介紹了Java數(shù)據(jù)交換Json和異步請(qǐng)求Ajax,需要的朋友可以參考下2023-09-09
SpringBoot基于redis自定義注解實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn)
本文主要介紹了SpringBoot基于redis自定義注解實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Jenkins+Maven+SVN自動(dòng)化部署java項(xiàng)目
這篇文章主要介紹了Jenkins+Maven+SVN自動(dòng)化部署java項(xiàng)目,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Myeclipse工程發(fā)布時(shí)端口占用問題的解決方法
這篇文章主要介紹了Myeclipse工程發(fā)布時(shí)端口占用問題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
基于Java實(shí)現(xiàn)QQ登錄注冊(cè)功能的示例代碼
這篇文章主要和大家分享如何利用Java語言實(shí)現(xiàn)QQ登錄、注冊(cè)等功能。本文主要應(yīng)用的技術(shù)有:GUI、JDBC、多線程等,需要的可以參考一下2022-05-05
如何利用postman完成JSON串的發(fā)送功能(springboot)
這篇文章主要介紹了如何利用postman完成JSON串的發(fā)送功能(springboot),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07

