PO VO DTO

  • 1. MapStruct简介
  • 2.0 MapStruct入门
    • 2.0.1 简易demo
    • 2.1. 引入依赖
    • 2.2. 需要转换的对象
    • 2.3. 创建转换器
    • 2.4. 验证
    • 2.5. 自动生成的实现类
  • 3.0 MapStruct进阶
  • 4.0 扩展(网上项目参考)
  • 4.1 扩展 dozer使用
  • 5.0 本地测试DEMO加深理解
  • DEMO2:实用版本

在我们日常开发的程序中,为了各层之间解耦,一般会定义不同的对象用来在不同层之间传递数据,比如xxxDTO、xxxVO、xxxQO,当在不同层之间传输数据时,不可避免地经常需要将这些对象进行相互转换。

今天给大家介绍一个对象转换工具MapStruct,代码简洁安全、性能高,强烈推荐。

1. MapStruct简介

MapStruct是一个代码生成器,它基于约定优于配置,极大地简化了Java Bean类型之间映射的实现。特点如下:

1.基于注解
2.在编译期自动生成映射转换代码
3.类型安全、高性能、无依赖性、易于理解阅读

2.0 MapStruct入门

2.0.1 简易demo

Car.java

public class Car {private String make;private int numberOfSeats;private CarType type;//constructor, getters, setters etc.
}

CarDto .java

public class CarDto {private String make;private int seatCount;private String type;//constructor, getters, setters etc.
}
@Mapper (1:下面对此解释)
public interface CarMapper {CarMapper INSTANCE = Mappers.getMapper( CarMapper.class ); (3:下面对此解释)@Mapping(source = "numberOfSeats", target = "seatCount")CarDto carToCarDto(Car car); (2:下面对此解释)
}

注释@Mapper(1)将接口标记为映射接口,并允许 MapStruct 处理器在编译期间启动。

实际的映射方法2期望源对象作为参数并返回目标对象。它的名字可以自由选择。

对于源对象和目标对象中具有不同名称的属性,可以使用注释来配置名称。@Mapping

在需要和可能的情况下,将为源和目标中具有不同类型的属性执行类型转换,例如,属性将从枚举类型转换为字符串。type

当然,一个接口中可以有多个映射方法,所有这些方法的实现都将由MapStruct生成。

可以从类中检索接口实现的实例。按照惯例,接口声明一个成员MappersINSTANCE 3,为客户端提供对映射器实现的访问。

shouldMapCarToDto.java

@Test
public void shouldMapCarToDto() {//givenCar car = new Car( "Morris", 5, CarType.SEDAN );//whenCarDto carDto = CarMapper.INSTANCE.carToCarDto( car );//thenassertThat( carDto ).isNotNull();assertThat( carDto.getMake() ).isEqualTo( "Morris" );assertThat( carDto.getSeatCount() ).isEqualTo( 5 );assertThat( carDto.getType() ).isEqualTo( "SEDAN" );
}

如想了解更多请查看官网内容(https://mapstruct.org/)

2.1. 引入依赖

这里使用Gradle构建

dependencies {implementation 'org.mapstruct:mapstruct:1.4.2.Final'annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}

maven仓库地址;

// https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor
implementation group: 'org.mapstruct', name: 'mapstruct-processor', version: '1.4.2.Final'

maven地址:

<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.4.2.Final</version>
</dependency>

2.2. 需要转换的对象

创建两个示例对象(EG: 将Demo对象转换为DemoDto对象)
保证对象之间的值是相同的;

/*** 源对象*/
@Data
public class Demo {private Integer id;private String name;
}/*** 目标对象*/
@Data
public class DemoDto {private Integer id;private String name;
}

2.3. 创建转换器

只需要创建一个转换器接口类,并在类上添加 @Mapper 注解即可(官方示例推荐以 xxxMapper 格式命名转换器名称)

@Mapper
public interface DemoMapper {//使用Mappers工厂获取DemoMapper实现类DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//定义接口方法,参数为来源对象,返回值为目标对象DemoDto toDemoDto(Demo demo);
}

2.4. 验证

public static void main(String[] args) {Demo demo = new Demo();demo.setId(111);demo.setName("hello");DemoDto demoDto = DemoMapper.INSTANCE.toDemoDto(demo);System.out.println("目标对象demoDto为:" + demoDto);//输出结果:目标对象demoDto为:DemoDto(id=111, name=hello)
}

测试结果如下:

目标对象demoDto为:DemoDto(id=111, name=hello)

达到了我们的预期结果。

2.5. 自动生成的实现类

为什么声明一个接口就可以转换对象呢?
我们看一下MapStruct在编译期间自动生成的实现类:

@Generated(value = "org.mapstruct.ap.MappingProcessor",date = "2022-09-01T17:54:38+0800",comments = "version: 1.4.2.Final, compiler: IncrementalProcessingEnvironment from gradle-language-java-7.3.jar, environment: Java 1.8.0_231 (Oracle Corporation)"
)
public class DemoMapperImpl implements DemoMapper {@Overridepublic DemoDto toDemoDto(Demo demo) {if ( demo == null ) {return null;}DemoDto demoDto = new DemoDto();demoDto.setId( demo.getId() );demoDto.setName( demo.getName() );return demoDto;}
}

可以看到,MapStruct帮我们将繁杂的代码自动生成了,而且实现类中用的都是最基本的get、set方法,易于阅读理解,转换速度非常快。

3.0 MapStruct进阶

上面的例子只是小试牛刀,下面开始展示MapStruct的强大之处。

(限于篇幅,这里不展示自动生成的实现类和验证结果,大家可自行测试)

场景1:属性名称不同、(基本)类型不同

  • 属性名称不同: 在方法上加上 @Mapping 注解,用来映射属性
  • 属性基本类型不同: 基本类型和String等类型会自动转换

关键字:@Mapping注解

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String name;
}/*** 目标对象*/
@Data
public class DemoDto {private String id;private String fullname;
}/*** 转换器*/
@Mapper
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);@Mapping(target = "fullname", source = "name")DemoDto toDemoDto(Demo demo);
}

场景2:统一映射不同类型
下面例子中,time1、time2、time3都会被转换,具体说明看下面的注释:

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String name;/*** time1、time2名称相同,time3转为time33* 这里的time1、time2、time33都是Date类型*/private Date time1;private Date time2;private Date time3;
}/*** 目标对象*/
@Data
public class DemoDto {private String id;private String name;/*** 这里的time1、time2、time33都是String类型*/private String time1;private String time2;private String time33;
}/*** 转换器*/
@Mapper
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);@Mapping(target = "time33", source = "time3")DemoDto toDemoDto(Demo demo);//MapStruct会将所有匹配到的://源类型为Date、目标类型为String的属性,//按以下方法进行转换static String date2String(Date date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String strDate = simpleDateFormat.format(date);return strDate;}
}

场景3:固定值、忽略某个属性、时间转字符串格式
一个例子演示三种用法,具体说明看注释,很容易理解:

关键字:ignore、constant、dateFormat

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String name;private Date time;
}/*** 目标对象*/
@Data
public class DemoDto {private String id;private String name;private String time;
}/*** 转换器*/
@Mapper
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//id属性不赋值@Mapping(target = "id", ignore = true)//name属性固定赋值为“hello”@Mapping(target = "name", constant = "hello")//time属性转为yyyy-MM-dd HH:mm:ss格式的字符串@Mapping(target = "time", dateFormat = "yyyy-MM-dd HH:mm:ss")DemoDto toDemoDto(Demo demo);
}

场景4:为某个属性指定转换方法
场景2中,我们是按照某个转换方法,统一将一种类型转换为另外一种类型;而下面这个例子,是为某个属性指定方法:

关键字:@Named注解、qualifiedByName

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String name;
}/*** 目标对象*/
@Data
public class DemoDto {private String id;private String name;
}/*** 转换器*/
@Mapper
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//为name属性指定@Named为convertName的方法进行转换@Mapping(target = "name", qualifiedByName = "convertName")DemoDto toDemoDto(Demo demo);@Named("convertName")static String aaa(String name) {return "姓名为:" + name;}
}

场景5:多个参数合并为一个对象
如果参数为多个的话,@Mapping注解中的source就要指定是哪个参数了,用点分隔:

关键字:点(.)

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String name;
}/*** 目标对象*/
@Data
public class DemoDto {private String fullname;private String timestamp;
}/*** 转换器*/
@Mapper
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//fullname属性赋值demo对象的name属性(注意这里.的用法)//timestamp属性赋值为传入的time参数@Mapping(target = "fullname", source = "demo.name")@Mapping(target = "timestamp", source = "time")DemoDto toDemoDto(Demo demo, String time);
}

场景6:已有目标对象,将源对象属性覆盖到目标对象

覆盖目标对象属性时,一般null值不覆盖,所以需要在类上的@Mapper注解中添加属性:nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE 代表null值不进行赋值。

关键字:@MappingTarget注解、nullValuePropertyMappingStrategy

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String name;
}/*** 目标对象*/
@Data
public class DemoDto {private String id;private String name;
}/*** 转换器*/
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE,nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//将已有的目标对象当作一个参数传进来DemoDto toDemoDto(Demo demo, @MappingTarget DemoDto dto);
}

场景7:源对象两个属性合并为一个属性

这种情况可以使用@AfterMapping注解。

关键字:@AfterMapping注解、@MappingTarget注解

/*** 来源对象*/
@Data
public class Demo {private Integer id;private String firstName;private String lastName;
}/*** 目标对象*/
@Data
public class DemoDto {private String id;private String name;
}/*** 转换器*/
@Mapper
public interface DemoMapper {DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);DemoDto toDemoDto(Demo demo);//在转换完成后执行的方法,一般用到源对象两个属性合并为一个属性的场景//需要将源对象、目标对象(@MappingTarget)都作为参数传进来,@AfterMappingstatic void afterToDemoDto(Demo demo, @MappingTarget DemoDto demoDto) {String name = demo.getFirstName() + demo.getLastName();demoDto.setName(name);}
}

本文介绍了对象转换工具 MapStruct 库,以安全、简洁、优雅的方式来优化我们的转换代码。

从文中的示例场景中可以看出,MapStruct 提供了大量的功能和配置,使我们可以快捷的创建出各种或简单或复杂的映射器。而这些,也只是 MapStruct 库的冰山一角,还有很多强大的功能文中没有提到,感兴趣的朋友可以自行查看官方文档。

官网地址:https://mapstruct.org/

4.0 扩展(网上项目参考)

pom 配置:

<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><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${org.projectlombok.version}</version></path><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${org.mapstruct.version}</version></path></annotationProcessorPaths></configuration></plugin></plugins></build>

关于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
public class Student {private String name;private int age;private GenderEnum gender;private Double height;private Date birthday;}
public enum GenderEnum {Male("1", "男"),Female("0", "女");private String code;private String name;public String getCode() {return this.code;}public String getName() {return this.name;}GenderEnum(String code, String name) {this.code = code;this.name = name;}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentVO {private String name;private int age;private String gender;private Double height;private String birthday;
}
@Mapper
public interface StudentMapper {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的接口,编译完成后会自动生成相应的实现类(targer)

然后就可以直接用mapper进行实体的转换了

public class Test {public static void main(String[] args) {Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();System.out.println(student);//这行代码便是实际要用的代码StudentVO studentVO = StudentMapper.INSTANCE.student2StudentVO(student);System.out.println(studentVO);}}

mapper可以进行字段映射,改变字段类型,指定格式化的方式,包括一些日期的默认处理。

可以手动指定格式化的方法:

@Mapper
public interface StudentMapper {StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);@Mapping(source = "gender", target = "gender")@Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")StudentVO student2StudentVO(Student student);default String getGenderName(GenderEnum gender) {return gender.getName();}}

上面只是最简单的实体映射处理,下面介绍一些高级用法

  1. List 转换

属性映射基于上面的mapping配置

@Mapper
public interface StudentMapper {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);}
public static void main(String[] args) {Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();List<Student> list = new ArrayList<>();list.add(student);List<StudentVO> result = StudentMapper.INSTANCE.students2StudentVOs(list);System.out.println(result);
}


2.多对象转换到一个对象

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Student {private String name;private int age;private GenderEnum gender;private Double height;private Date birthday;}
@Data
@AllArgsConstructor
@Builder
@NoArgsConstructor
public class Course {private String courseName;private int sortNo;private long id;}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentVO {private String name;private int age;private String gender;private Double height;private String birthday;private String course;
}
@Mapper
public interface StudentMapper {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")StudentVO studentAndCourse2StudentVO(Student student, Course course);}
public class Test {public static void main(String[] args) {Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();Course course = Course.builder().id(1L).courseName("语文").build();StudentVO studentVO = StudentMapper.INSTANCE.studentAndCourse2StudentVO(student, course);System.out.println(studentVO);}}


3.默认值

@Mapper
public interface StudentMapper {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 = "张三")StudentVO studentAndCourse2StudentVO(Student student, Course course);}

4.1 扩展 dozer使用

<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>

然后分别创建一个UserVo和UserDto,并对他们做转换

首先让两个类的属性名称一样,如下

@Data
public class UserVo {private String name;
private int id;
}@Data
public class UserDto {private String name;
private int id;
}

接下来怎么转换呢,代码如下

Mapper dozerMapper = new DozerBeanMapper();

UserVo userVo = new UserVo();
userVo.setName("mg");
userVo.setId(10);
InUserDto userDto = dozerMapper.map(userVo,UserDto.class);
System.out.println(userDto.getName());

输出结果为

mg

UserVo转换为UserDto,这是属性完全相同的情况,不过通常属性名称都是不同的,那怎么办呢

修改UserVo 为

@Data
public class UserVo {private String sname;
private int sid;
}

@Mapping(“实体类对应名字”) 这样就可以解决对应的实体类个别不一样的问题;

修改UserDto为@Data
public class UserDto {@Mapping("sname")
private String name;
@Mapping("sid")
private int id;
}

在执行下刚写的转换函数,试试是否能成功转换了

5.0 本地测试DEMO加深理解

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.1</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example.DemoCrud</groupId><artifactId>democurd</artifactId><version>0.0.1-SNAPSHOT</version><name>democurd</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- mybatis整合Springboot --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><!--           maven 添加json--><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version></dependency><!--jquery-webjar--><dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.3.0</version></dependency><!--bootstrap-webjar--><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>4.0.0</version></dependency><!--配置文件注入时使用后会有提示--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.18</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.2</version></dependency><!--mapStruct依赖--><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-jdk8</artifactId><version>1.2.0.CR1</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.2.0.CR1</version><scope>provided</scope></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.3.1.Final</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectors</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins><!-- 添加资源 --><resources><resource><directory>src/main/resources</directory><!-- src/main/resources下的指定资源放行 --><includes><include>**/*.properties</include><include>**/*.yml</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build></project>

代码结构:

先创建2个实体类:

package com.example.democrud.democurd.DoVO;import lombok.Data;/*** 来源对象*/
@Data
public class DoUser {private String id;private String user;private String age;}
package com.example.democrud.democurd.DoVO;import lombok.Data;/*** 目标对象*/
@Data
public class VoUser {private String id;private String user;private String age;}

为了加深理解我们先手写一个映射关系;

@Mapper
public interface CarMap {CarMap INSTANCE = Mappers.getMapper( CarMap.class );DoUser toVoUser(VoUser demo);
}

实现类

package com.example.democrud.democurd.DoVO;public class CarMapImpl implements CarMap{@Overridepublic DoUser toVoUser(VoUser demo) {if ( demo == null ) {return null;}DoUser demoDto = new DoUser();demoDto.setId( demo.getId() );demoDto.setUser( demo.getUser() );demoDto.setAge(demo.getAge());return demoDto;}}

控制台:

public static void main(String[] args) {VoUser user = new VoUser();user.setUser("闫文超");user.setAge("12");user.setId("66");DoUser doUser=CarMap.INSTANCE.toVoUser(user);System.out.println("doUser==>"+doUser);}
}

这样2个实体类的关系就会达成映射关系

还有一个简单的方法;(componentModel = “spring”) 加入注解就可以自动实现他的方法了(和上面 的区别只添加这个即可)

package com.example.democrud.democurd.DoVO;import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;@Mapper(componentModel = "spring")
public interface CarMap {CarMap INSTANCE = Mappers.getMapper( CarMap.class );//    DoUser toVoUser(VoUser demo);DoUser toVoUsers(VoUser demo);
}

测试结果:

是不是很容易啊,这样既能分别定义的VO、PO、DTO,又能快速完成开发工作了;

DEMO2:实用版本

实体类和上面相识;



重点 BaseVo 工具类:

package com.example.democrud.democurd.DoVO;import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.DoubleConverter;
import org.apache.commons.beanutils.converters.FloatConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.commons.beanutils.converters.ShortConverter;/*** * VO基类* @author clwang* @version 2019年4月17日*/
public class BaseVO implements Serializable {/*** 意义,目的和功能,以及被用到的地方<br>*/private static final long serialVersionUID = 7474374467497907429L;/*** * PO转VO* @param po po对象* @param voClass VO的class对象* @param <T> 具体VO对象的泛型* @return  返回VO*/public static <T extends BaseVO> T toVO(Object po, Class<T> voClass) {if (null == po) {return null;}setDefaultValue();try {T vo = voClass.newInstance();BeanUtils.copyProperties(vo, po);return vo;} catch (InstantiationException e) {System.out.println(e);} catch (IllegalAccessException e) {System.out.println(e);} catch (InvocationTargetException e) {System.out.println(e);}return null;}/*** BeanUtils空值拷贝默认属性设置,空值任然为空,不赋值默认值*/private static void setDefaultValue() {ConvertUtils.register(new LongConverter(null), Long.class);ConvertUtils.register(new IntegerConverter(null), Integer.class);ConvertUtils.register(new ShortConverter(null), Short.class);ConvertUtils.register(new FloatConverter(null), Float.class);ConvertUtils.register(new DoubleConverter(null), Double.class);ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);}/*** * VO转PO* @param poClass po class对象* @param <T> 具体po对象的泛型* @return PO对象*/public <T> T toPO(Class<T> poClass) {setDefaultValue();try {T po = poClass.newInstance();BeanUtils.copyProperties(po, this);return po;} catch (InstantiationException e) {System.out.println(e);} catch (IllegalAccessException e) {System.out.println(e);} catch (InvocationTargetException e) {System.out.println(e);}return null;}}

我们看下如何调用:

 public static void main(String[] args) {VoUser user = new VoUser();user.setUser("闫文超");user.setAge("12");user.setId("66");VoUser user1 = new VoUser();user1.setUser("闫22");user1.setAge("33");user1.setId("77");test1(user);//   test2(user1);}public static void test1(VoUser vouser) {//用实体类继承该f方法后调用//前面是空数据需要导入数据的类 vouser是有数据的DoUser douser = vouser.toPO(DoUser.class);System.out.println("test1==>"+douser);}public static void test2(VoUser vouser) {DoUser doUser=DoUser.toVO(vouser,DoUser.class);System.out.println("test2==>"+doUser);}


补充:

 public static void test3(VoUser vouser) {DoUser doUser=new DoUser();//前面的为值 后面是需要赋值的实体类BeanUtil.copyProperties(vouser,doUser);System.out.println("test3==>"+doUser);}


想用那种大家随意喽;

PO VO DTO 转换神器替代BeanUtils 了相关推荐

  1. 别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:toutiao.com/i6891531055631696395 老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实 ...

  2. 一款 PO VO DTO 转换神器

    欢迎关注方志朋的博客,回复"666"获面试宝典 老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实体字段特别多的时候.介绍一个开源项目 mapstruct ,可以轻松优雅 ...

  3. 【工具神器】PO VO DTO 转换神器

    老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实体字段特别多的时候.介绍一个开源项目 mapstruct ,可以轻松优雅的进行转换,简化你的代码. 当然有的人喜欢写get set,或者用B ...

  4. VO的实际应用;后端接收前端传入的值;实体类转化VO;PO,VO,DTO,BO,DAO,POJO区别

    文章目录 各层转换流程 分层领域模型规约: 领域模型命名规约: 后端向前端传参 封装 前端向后台传参 封装 快速转换解决方案 参考 各层转换流程 分层领域模型规约: DO( Data Object): ...

  5. Java 中的PO VO DTO BO

    PO 持久对象,数据: BO 业务对象,封装对象.复杂对象 ,里面可能包含多个类: DTO 传输对象,前端调用时传输 : VO 表现对象,前端界面展示. 当你业务足够简单时,一个POJO 也完全当做P ...

  6. POJO,PO,VO,DTO

    1.POJO POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称. POJO (Plain Old ...

  7. Java开发中的几种对象的说明(PO,VO,DTO,BO,POJO,DAO,SAO等)

    一.PO :(persistant object ),持久对象 可以看成是与数据库中的表相映射的java对象,也就是说只有属性和setter和getter方法.使用Hibernate来生成PO是不错的 ...

  8. PO VO DTO BO区别及用法

    PO: persistant object持久对象 最形象的理解就是一个PO就是数据库中的一条记录. 好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象. BO: businessobjec ...

  9. JSP PO VO BO DTO POJO DAO解释

    PO :persistent object持久对象 1 .有时也被称为Data对象,对应数据库中的entity,可以简单认为一个PO对应数据库中的一条记录. 2 .在hibernate持久化框架中与i ...

最新文章

  1. 【今晚七点半】:龙芯多媒体技术生态 从平台优化实践说起
  2. io多路复用的原理和实现_IO多路复用的三种机制:select 、poll 、epoll
  3. 常用类一一枚举类一一定义和调用
  4. 编写了一个文件编码转换器。
  5. linux的可执行文件通常放在哪个目录中?写出该目录的路径.,实验2 Linux的基本操作与 使用vi编辑器 2010 (1)...
  6. java删除表操作,JDBC删除表实例
  7. php分页函数代码,PHP分页函数代码分享
  8. 树莓派3b接收USB串口数据并解析处理
  9. JAVA-初步认识-第四章-其他流程控制语句
  10. 我学习的自定义ASP.NET分页控件
  11. 《微积分的力量》读书摘记
  12. 【论文阅读笔记】Securing software by enforcing data-flow integrity
  13. 2 月份看了 17 本书,我只推荐这 8 本!
  14. OSChina 周日乱弹 ——程序员撩妹必杀。
  15. QGraphicsView使用详解
  16. 迷宫中离入口最近的出口问题
  17. Mac创建自签名的代码证书
  18. markdown写出项目目录结构
  19. A题 序号互换(进制转换)
  20. CSS3 rgb and rgba(透明色)的使用

热门文章

  1. 域泛化(Domain Generalization)相关知识学习
  2. js控制手机保持亮屏的库
  3. 物联网网关是什么?有什么作用?
  4. 《炬丰科技-半导体工艺》硅晶片清洗是半导体制造中的一个基础步骤
  5. 联邦计算在百度观星盘的实践
  6. 对于超图(hypergraph)的一些理解及部分概念
  7. Windows FAT32转换NTFS
  8. csgo的demo怎么录屏_CSGO如何观看DEMO 录像功能全解析
  9. 700万行数据,Excel也能轻松应对,你会吗?
  10. 将mcl中与系统相关的函数用c++标准库替代