MapStruct 一文读懂
Posted 在奋斗的大道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MapStruct 一文读懂相关的知识,希望对你有一定的参考价值。
目录
4、MapStruct 集合映射、Map映射、枚举映射和Stream 流映射
1、MapStruct 简介
MapStruct是基于JSR269规范的一个Java注解处理器,用于为Java Bean生成类型安全且高性能的映射。它基于编译阶段生成get/set代码,此实现过程中没有反射,不会造成额外的性能损失。
1.1 MapStruct Maven引入
在pom.xml文件添加MapStruct 相关依赖
<!--mapStruct依赖 高性能对象映射-->
<!--mapstruct核心-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.0.Beta1</version>
</dependency>
<!--mapstruct编译-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.0.Beta1</version>
</dependency>
2、MapStruct 基础操作
2.1 MapStruct 基本映射
创建MapStruct 映射步骤总结:
- 添加MapStruct jar包依赖
- 新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
- 添加自定义转换方法
示例:创建Person 和PersonDto 类定义,通过MapStruct 实现Person 类实例对象转换PersonDto l类实例对象。
package com.zzg.mapstruct.entity;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class Person
String describe;
private String id;
private String name;
private int age;
private BigDecimal source;
private double height;
private Date createTime;
package com.zzg.mapstruct.entity;
import lombok.Data;
@Data
public class PersonDTO
String describe;
private Long id;
private String personName;
private String age;
private String source;
private String height;
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
PersonDTO conver(Person person);
测试:
package com.zzg.mapstruct.test;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import com.zzg.mapstruct.mapper.PersonMapper;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class OneTest
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Person person = Person.builder().age(31).createTime(format.parse("1991-12-20")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.conver(person);
System.out.println(personDTO);
执行截图:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0)
优化:Person 类实例对象 转换PersonDto 类实例对象发现 Person.name 属性无法与PersonDto.personName 属性无法实现一一对应,可以通过@Mappering 注解标签实现不同属性名称转换。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
PersonDTO converMapping(Person person);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Person person = Person.builder().age(31).createTime(format.parse("1991-12-20")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.converMapping(person);
System.out.println(personDTO);
执行效果:
PersonDTO(describe=Java 开发, id=1, personName=在奋斗的大道上, age=31, source=10000, height=180.0)
MapStruct 转换总结:
-
当一个属性与其目标实体对应的名称相同时,它将被隐式映射。
-
当属性在目标实体中具有不同的名称时,可以通过@Mapping注释指定其名称。
温馨提示:
如果映射的对象field name不一样,通过 @Mapping 指定。
如果忽略映射字段加@Mapping#ignore() = true
2.2 MapStruct 指定默认值
功能要求:Person 类实例对象 转换PersonDto 类实例对象时,将describe属性值设置为:"默认值"。
在@Mapping注解标签中必须添加target属性,source属性,默认值使用defaultValue属性设置。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
PersonDTO converMapping(Person person);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Person person = Person.builder().age(31).createTime(format.parse("1991-12-20")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.converMapping(person);
System.out.println(personDTO);
执行效果:
PersonDTO(describe=Java 开发, id=1, personName=在奋斗的大道上, age=31, source=10000, height=180.0)
通过Main 方法测试发现PersonDto 类对象属性describe默认值未生效。将Person.buildr 建造模式移除describe属性值设置。
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Person person = Person.builder().age(31).createTime(format.parse("1991-12-20")).id("1")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.converMapping(person);
System.out.println(personDTO);
执行效果:
PersonDTO(describe=默认值, id=1, personName=在奋斗的大道上, age=31, source=10000, height=180.0)
2.3 MapStruct 表达式
功能要求:在PersonDto 类中添加时间属性currentDay,并且要求赋值系统当前时间
在@Mapping注解标签中必须添加target属性 和expression属性。
package com.zzg.mapstruct.entity;
import lombok.Data;
import java.util.Date;
@Data
public class PersonDTO
String describe;
private Long id;
private String personName;
private String age;
private String source;
private String height;
private Date currentDay;
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
PersonDTO converMapping(Person person);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Person person = Person.builder().age(31).createTime(format.parse("1991-12-20")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.conver(person);
System.out.println(personDTO);
执行结果:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0, currentDay=Wed Oct 19 17:20:23 CST 2022)
温馨提示:
1、expression()属性不能与source()、defaultValue()、defaultExpression()、qualifiedBy()、qualifiedByName()或constant()一起使用。
2、默认表达式@Mapping#defaultExpression()是默认值和表达式的组合。仅当source属性为null时才使用它们
2.4 MapStruct 时间格式
功能要求:指定PersonDto 类属性currentDay的时间格式为'yyyy-MM-dd'
在@Mapping注解标签中必须添加target属性、source属性 和dateFormat属性。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
PersonDTO converMapping(Person person);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.converMapping(person);
System.out.println(personDTO);
执行效果:
PersonDTO(describe=Java 开发, id=1, personName=在奋斗的大道上, age=31, source=10000, height=180.0, currentDay=Tue Jan 01 00:00:00 CST 1991)
2.5 MapStruct 数字格式
功能要求:指定PersonDto 类属性age的数字格式为'#0.00'
在@Mapping注解标签中必须添加target属性、source属性 和numberFormat属性。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.converMapping(person);
System.out.println(personDTO);
执行效果:
PersonDTO(describe=Java 开发, id=1, personName=在奋斗的大道上, age=31.00, source=10000, height=180.0, currentDay=Tue Jan 01 00:00:00 CST 1991)
3、MapStruct 组合映射
3.1 多参数源映射
功能要求:新增一个类对象(BasicEntity),要求将BasicEntity中的createTime 属性赋值给PersonDto 类中的currentDay属性。
package com.zzg.mapstruct.entity;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
@Data
@Builder
public class BasicEntity
private Date createTime;
private String createBy;
private Date updateTime;
private String updateBy;
private int _ROW;
PersonMapper 接口新增多参数源映射接口定义。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.BasicEntity;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
BasicEntity basicEntity = BasicEntity.builder().createTime(new Date()).createBy("周志刚").updateTime(new Date()).updateBy("周晨曦")._ROW(1).build();
PersonDTO personDTO = PersonMapper.INSTANCT.combinationConver(person, basicEntity);
System.out.println(personDTO);
执行效果:
PersonDTO(describe=Java 开发, id=1, personName=在奋斗的大道上, age=31, source=10000, height=180.0, currentDay=Wed Oct 19 23:29:59 CST 2022)
3.2 使用其他参数值
功能要求:PersonDTO l类中的id 属性值要求从方法中传入,不接受转换类Person 中的id 属性
PersonMapper 接口新增其他参数值映射接口定义。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.BasicEntity;
import com.zzg.mapstruct.entity.Person;
import com.zzg.mapstruct.entity.PersonDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
/**
* 其他参数值映射
* @param person
* @param id
* @return
*/
@Mapping(source = "person.name", target="personName")
@Mapping(target = "id", source = "id")
PersonDTO mapTo(Person person, String id);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).build();
PersonDTO personDTO = PersonMapper.INSTANCT.mapTo(person, "10");
System.out.println(personDTO);
效果截图:
PersonDTO(describe=Java 开发, id=10, personName=在奋斗的大道上, age=31, source=10000, height=180.0, currentDay=null)
温馨提示:在进行其他参数值映射转换时,主要source 对象与tager 对象的Mapping 映射需要添加实例对象名称 .属性名称。
3.3 嵌套映射
功能要求:为 Person 类新增一个类属性Company 公司属性,为PersonDTO类新增一个类型属性CompanyDTO公司属性。
package com.zzg.mapstruct.entity;
import lombok.Data;
import java.util.Date;
@Data
public class Company
public String name;
public String address;
public Integer numberOfPeople;
public Date createDate;
public String createBy;
package com.zzg.mapstruct.entity;
import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Builder
public class Person
String describe;
private String id;
private String name;
private int age;
private BigDecimal source;
private double height;
private Date createTime;
// 添加Company 类属性
private Company company;
package com.zzg.mapstruct.entity;
import lombok.Data;
import java.util.Date;
@Data
public class CompanyDTO
public String name;
public String address;
public Integer numbers ;
public Date currentDate;
public String leader;
package com.zzg.mapstruct.entity;
import lombok.Data;
import java.util.Date;
@Data
public class PersonDTO
String describe;
private Long id;
private String personName;
private String age;
private String source;
private String height;
private Date currentDay;
// 添加CompanyDTO 类属性
private CompanyDTO dto;
PersonMapper 接口新增嵌套属性接口转换定义
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
/**
* 方法值映射
* @param person
* @param id
* @return
*/
@Mapping(source = "person.name", target="personName")
@Mapping(target = "id", source = "id")
PersonDTO mapTo(Person person, String id);
/**
* 嵌套类属性转换
* @param person
* @return
*/
@Mapping(source="person.company", target = "dto")
PersonDTO coverNestedProperties(Person person);
CompanyDTO converDto(Company company);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Company company = new Company();
company.setAddress("龙岗大道10012");
company.setName("成宇科技");
company.setCreateBy("周晨宇");
company.setCreateDate(new Date());
company.setNumberOfPeople(1000);
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).company(company).build();
PersonDTO personDTO = PersonMapper.INSTANCT.coverNestedProperties(person);
System.out.println(personDTO);
执行结果:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0, currentDay=null, dto=CompanyDTO(name=成宇科技, address=龙岗大道10012, numbers=null, currentDate=null, leader=null))
嵌套属性问题:在测试上述功能代码发现,Person类中的Company类属性转换为PersonDTO类中的CompanyDTO 类属性时,发生有属性无法一一对应导致属性值为空 ,解决此问题的办法时,在@Mapper接口 中添加一个自定义 方法,主要解决Company 转CompanyDTO,无法对应的字段使用@Mapping 注解标签实现对应转换。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
/**
* 方法值映射
* @param person
* @param id
* @return
*/
@Mapping(source = "person.name", target="personName")
@Mapping(target = "id", source = "id")
PersonDTO mapTo(Person person, String id);
/**
* 嵌套类属性转换
* @param person
* @return
*/
@Mapping(source="person.company", target = "dto")
PersonDTO coverNestedProperties(Person person);
@Mapping(source = "createBy", target = "leader")
@Mapping(source = "createDate", target = "currentDate")
@Mapping(source = "numberOfPeople", target = "numbers")
CompanyDTO converDto(Company company);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Company company = new Company();
company.setAddress("龙岗大道10012");
company.setName("成宇科技");
company.setCreateBy("周晨宇");
company.setCreateDate(new Date());
company.setNumberOfPeople(1000);
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).company(company).build();
PersonDTO personDTO = PersonMapper.INSTANCT.coverNestedProperties(person);
System.out.println(personDTO);
效果截图:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0, currentDay=null, dto=CompanyDTO(name=成宇科技, address=龙岗大道10012, numbers=1000, currentDate=Thu Oct 20 19:45:17 CST 2022, leader=周晨宇))
拓展:嵌套属性为集合属性对象时,MapStruct 如何完成转换?
功能要求:为 Person 类新增一个集合属性List<House> 房屋属性,为PersonDTO类新增一个Lis<HouseDTO>房屋属性。
package com.zzg.mapstruct.entity;
import lombok.Data;
@Data
public class House
private String address;
private Integer price;
package com.zzg.mapstruct.entity;
import lombok.Data;
@Data
public class HouseDTO
private Integer house_pay;
private String address;
Person 和PersonDTO 分别添加相关集合属性:
// 添加集合属性
private List<House> houses;
// 添加集合属性
private List<HouseDTO> houseDTOs;
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Company company = new Company();
company.setAddress("龙岗大道10012");
company.setName("成宇科技");
company.setCreateBy("周晨宇");
company.setCreateDate(new Date());
company.setNumberOfPeople(1000);
List<House> houses= new ArrayList<>();
House one = new House();
one.setPrice(1000000);
one.setAddress("湖南长沙");
House two = new House();
two.setPrice(2600000);
two.setAddress("广东深圳");
houses.add(one);
houses.add(two);
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).company(company).houses(houses).build();
PersonDTO personDTO = PersonMapper.INSTANCT.coverNestedColl(person);
System.out.println(personDTO);
测试结果:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0, currentDay=null, dto=CompanyDTO(name=成宇科技, address=龙岗大道10012, numbers=1000, currentDate=Thu Oct 20 20:00:48 CST 2022, leader=周晨宇), houseDTOs=null)
测试问题:
我们发现Person类中List<House> 属性没有正确转换为PersonDTO 类中的List<HouseDTO>属性。
解决办法:在PersonMapper接口中新增集合属性转换方法coverColl。并在coverNestedColl方法上添加集合属性映射转换配置。
@Mapping(source = "person.houses", target ="houseDTOs")
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
/**
* 方法值映射
* @param person
* @param id
* @return
*/
@Mapping(source = "person.name", target="personName")
@Mapping(target = "id", source = "id")
PersonDTO mapTo(Person person, String id);
/**
* 嵌套类属性转换
* @param person
* @return
*/
@Mapping(source="person.company", target = "dto")
PersonDTO coverNestedProperties(Person person);
@Mapping(source = "createBy", target = "leader")
@Mapping(source = "createDate", target = "currentDate")
@Mapping(source = "numberOfPeople", target = "numbers")
CompanyDTO converDto(Company company);
@Mapping(source="person.company", target = "dto")
@Mapping(source = "person.houses", target ="houseDTOs")
PersonDTO coverNestedColl(Person person);
List<HouseDTO> coverColl(List<House> houses);
测试结果:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Company company = new Company();
company.setAddress("龙岗大道10012");
company.setName("成宇科技");
company.setCreateBy("周晨宇");
company.setCreateDate(new Date());
company.setNumberOfPeople(1000);
List<House> houses= new ArrayList<>();
House one = new House();
one.setPrice(1000000);
one.setAddress("湖南长沙");
House two = new House();
two.setPrice(2600000);
two.setAddress("广东深圳");
houses.add(one);
houses.add(two);
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).company(company).houses(houses).build();
PersonDTO personDTO = PersonMapper.INSTANCT.coverNestedColl(person);
System.out.println(personDTO);
测试结果:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0, currentDay=null, dto=CompanyDTO(name=成宇科技, address=龙岗大道10012, numbers=1000, currentDate=Fri Oct 21 09:33:17 CST 2022, leader=周晨宇), houseDTOs=[HouseDTO(house_pay=null, address=湖南长沙), HouseDTO(house_pay=null, address=广东深圳)])
3.4 逆映射
大家都发现了之前的案列,我们都是使用PO 对象转DTO对象,同时希望支持DTO对象转PO对象,MapStruct也支持PO 和DTO双向映射,主要通过@InheritInverseConfiguration注解标签实现。
@InheritInverseConfiguration
表示方法应继承相应反向方法的反向配置
温馨提示:建议指定name属性,对应 逆映射方法名称。
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.*;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
/**
* 方法值映射
* @param person
* @param id
* @return
*/
@Mapping(source = "person.name", target="personName")
@Mapping(target = "id", source = "id")
PersonDTO mapTo(Person person, String id);
/**
* 嵌套类属性转换
* @param person
* @return
*/
@Mapping(source="person.company", target = "dto")
PersonDTO coverNestedProperties(Person person);
@Mapping(source = "createBy", target = "leader")
@Mapping(source = "createDate", target = "currentDate")
@Mapping(source = "numberOfPeople", target = "numbers")
CompanyDTO converDto(Company company);
@Mapping(source="person.company", target = "dto")
@Mapping(source = "person.houses", target ="houseDTOs")
PersonDTO coverNestedColl(Person person);
List<HouseDTO> coverColl(List<House> houses);
/**
* 逆映射转换
* @param personDTO
* @return
*/
@InheritInverseConfiguration(name = "coverNestedColl")
Person coverNestedColl(PersonDTO personDTO);
测试代码:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
CompanyDTO company = new CompanyDTO();
company.setAddress("龙岗大道10012");
company.setName("成宇科技");
company.setLeader("周晨宇");
company.setCurrentDate(new Date());
company.setNumbers(1000);
List<HouseDTO> houses= new ArrayList<>();
HouseDTO one = new HouseDTO();
one.setHouse_pay(1000000);
one.setAddress("湖南长沙");
HouseDTO two = new HouseDTO();
two.setHouse_pay(2600000);
two.setAddress("广东深圳");
houses.add(one);
houses.add(two);
PersonDTO person = new PersonDTO();
person.setAge("31");
person.setCurrentDay(format.parse("1991"));
person.setId(1l);
person.setDescribe("Java 开发");
person.setHeight("180");
person.setPersonName("在奋斗的大道上");
person.setSource("10000");
person.setDto(company);
person.setHouseDTOs(houses);
Person personDTO = PersonMapper.INSTANCT.coverNestedColl(person);
System.out.println(personDTO);
测试结果:
Person(describe=Java 开发, id=1, name=null, age=31, source=10000, height=180.0, createTime=null, company=Company(name=成宇科技, address=龙岗大道10012, numberOfPeople=null, createDate=null, createBy=null), houses=[House(address=湖南长沙, price=null), House(address=广东深圳, price=null)])
3.4 继承映射
问题抛出:MapStruct 提供了很多方法级注解标签:Mapping,@BeanMapping,@IterableMapping 等等。有时候我们希望某些转换方法继承指定转换方法的MapStruct 注解标签配置。以节省@Mapper 接口到处都是相同的注解标签。
我们可以通过@InheritConfiguration注解标签,实现我们希望的功能。
通过声明
@InheritConfiguration
该方法,MapStruct可以搜索继承候选,以应用继承自该方法的注释。
白话讲解:
如果所有类型的A(源类型和结果类型)都可以分配给B的相应类型,则一个方法A可以从另一种方法B继承配置。如果可以使用多个方法作为继承的源,则必须在注释中指定方法名称:@InheritConfiguration( name = “coverNestedColl” )。
示例:在@Mapper 接口中添加配置继承方法
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.entity.*;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* mapstruct 工具类定义步骤:
* 1、添加MapStruct jar包依赖
* 2、新增接口或抽象类,并且使用org.mapstruct.Mapper注解标签修饰。
* 3、添加自定义转换方法
*/
@Mapper
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "currentDay", expression = "java(new java.util.Date())")
PersonDTO conver(Person person);
@Mapping(source = "name", target="personName")
@Mapping(source = "describe", target = "describe", defaultValue = "默认值")
@Mapping(source = "createTime", target = "currentDay", dateFormat = "yyyy-MM-dd")
@Mapping(source = "age", target = "age", numberFormat = "#0.00")
PersonDTO converMapping(Person person);
/**
* 多参数源映射转换
* @param person
* @param basicEntity
* @return
*/
@Mapping(source = "basicEntity.createTime", target = "currentDay")
@Mapping(source = "person.name", target="personName")
PersonDTO combinationConver(Person person, BasicEntity basicEntity);
/**
* 方法值映射
* @param person
* @param id
* @return
*/
@Mapping(source = "person.name", target="personName")
@Mapping(target = "id", source = "id")
PersonDTO mapTo(Person person, String id);
/**
* 嵌套类属性转换
* @param person
* @return
*/
@Mapping(source="person.company", target = "dto")
PersonDTO coverNestedProperties(Person person);
@Mapping(source = "createBy", target = "leader")
@Mapping(source = "createDate", target = "currentDate")
@Mapping(source = "numberOfPeople", target = "numbers")
CompanyDTO converDto(Company company);
@Mapping(source="person.company", target = "dto")
@Mapping(source = "person.houses", target ="houseDTOs")
PersonDTO coverNestedColl(Person person);
List<HouseDTO> coverColl(List<House> houses);
/**
* 逆映射转换
* @param personDTO
* @return
*/
@InheritInverseConfiguration(name = "coverNestedColl")
Person coverNestedColl(PersonDTO personDTO);
/**
* 配置继承
* @param person
* @param personDTO
*/
@InheritConfiguration(name="coverNestedColl")
void coverExtend(Person person, @MappingTarget PersonDTO personDTO);
测试:
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Company company = new Company();
company.setAddress("龙岗大道10012");
company.setName("成宇科技");
company.setCreateBy("周晨宇");
company.setCreateDate(new Date());
company.setNumberOfPeople(1000);
List<House> houses= new ArrayList<>();
House one = new House();
one.setPrice(1000000);
one.setAddress("湖南长沙");
House two = new House();
two.setPrice(2600000);
two.setAddress("广东深圳");
houses.add(one);
houses.add(two);
Person person = Person.builder().age(31).createTime(format.parse("1991")).id("1").describe("Java 开发")
.height(180L).name("在奋斗的大道上").source(new BigDecimal(10000)).company(company).houses(houses).build();
PersonDTO personDTO = new PersonDTO();
PersonMapper.INSTANCT.coverExtend(person, personDTO);
System.out.println(personDTO);
测试结果:
PersonDTO(describe=Java 开发, id=1, personName=null, age=31, source=10000, height=180.0, currentDay=null, dto=CompanyDTO(name=成宇科技, address=龙岗大道10012, numbers=1000, currentDate=Fri Oct 21 10:20:37 CST 2022, leader=周晨宇), houseDTOs=[HouseDTO(house_pay=null, address=湖南长沙), HouseDTO(house_pay=null, address=广东深圳)])
3.5 共享映射
开发实例:我们经常在数据库中定义 创建时间date_create、修改时间date_update 这样的字段,通常情况下几乎每个表都存在这样的字段,数据库里面的类型是java.sql.Timestamp类型,而我们一般都转为String类型便于显示。如果不用mapStruct的共享配置,那相当于在每个表对应的转化类里面配置 Timestamp到String的映射。但是如果有共享配置,我们只要配置一遍,然后在其他地方引入,达到共享的目的。
mapStruct的共享映射通过注解 @MapperConfig定义,然后在@Mapper的属性config中引入。@MapperConfig注释具有与@Mapper注释相同的属性。任何未通过@Mapper指定的属性都将从共享配置中继承。在@Mapper中指定的属性优先于通过引用的配置类指定的属性。
示例:共享映射
package com.zzg.mapstruct.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseDTO
public Date sysCreateDate;
public String sysCreateId;
package com.zzg.mapstruct.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BasePO
public String sysCreateDate;
public String sysCreateId;
package com.zzg.mapstruct.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User extends BasePO
private String name;
private String phone;
private Date birthday;
package com.zzg.mapstruct.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO extends BaseDTO
private String realname;
private String telephone;
private Date birthday;
通用@MapperConfig 定义和@Mapper定义。
package com.zzg.mapstruct.config;
import com.zzg.mapstruct.entity.BaseDTO;
import com.zzg.mapstruct.entity.BasePO;
import com.zzg.mapstruct.util.DateFormtUtil;
import org.mapstruct.MapperConfig;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
@MapperConfig(unmappedTargetPolicy = ReportingPolicy.ERROR, uses = DateFormtUtil.class)
public interface CommonConfig
@Mapping(source = "sysCreateDate", target = "sysCreateDate")
BaseDTO converBase(BasePO basePO);
package com.zzg.mapstruct.util;
import org.mapstruct.Named;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormtUtil
public Date asDate(String date)
try
return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
.parse( date ) : null;
catch ( ParseException e )
throw new RuntimeException( e );
package com.zzg.mapstruct.mapper;
import com.zzg.mapstruct.config.CommonConfig;
import com.zzg.mapstruct.entity.User;
import com.zzg.mapstruct.entity.UserDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper(config = CommonConfig.class)
public interface UserMapper
UserMapper INSTANCT = Mappers.getMapper(UserMapper.class);
@Mapping(source = "name", target="realname")
@Mapping(source = "phone", target="telephone")
UserDTO converMapping(User user);
测试代码:
package com.zzg.mapstruct.test;
import com.zzg.mapstruct.entity.User;
import com.zzg.mapstruct.entity.UserDTO;
import com.zzg.mapstruct.mapper.UserMapper;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class TwoTest
public static void main(String[] args) throws ParseException
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
User user = new User();
user.setSysCreateDate("2022-10-21");
user.setSysCreateId("1L");
user.setName("周晨曦");
user.setBirthday(format.parse("2019-05-30"));
user.setPhone("119");
UserDTO userDTO = UserMapper.INSTANCT.converMapping(user);
System.out.println(userDTO);
System.out.println(userDTO.getSysCreateDate());
System.out.println(userDTO.getSysCreateId());
测试结果:
UserDTO(realname=周晨曦, telephone=119, birthday=Thu May 30 00:00:00 CST 2019)
Fri Oct 21 00:00:00 CST 2022
1L
3.6 自定义方法
3.6.1 自定义类型转换方法
public class DateMapper
public String asString(Date date)
return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
.format( date ) : null;
public Date asDate(String date)
try
return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
.parse( date ) : null;
catch ( ParseException e )
throw new RuntimeException( e );
@Mapper(uses=DateMapper.class)
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
PersonDTO conver(Person person);
温馨提示: @Mapper#uses
可以使用多个类
3.6.2 使用@Qualifier
@Qualifier
标记的自定义注解标记的方法,必须有输入, 否则编译时会抛出异常。
public class DateFormtUtil
@DateFormat
public static String dateToString(Date date)
return date == null ? "": new SimpleDateFormat("yyyy-MM-dd").format(date);
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface DateFormat
@Mapper(uses =DateFormtUtil.class)
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "createTime",source = "createTime",qualifiedBy = DateFormat.class)
PersonDTO conver(Person person);
3.6.3 使用@namd
public class DateFormtUtil
@Named("dateToString")
public static String dateToString(Date date)
return date == null ? "": new SimpleDateFormat("yyyy-MM-dd").format(date);
@Mapper(uses =DateFormtUtil.class)
public interface PersonMapper
PersonMapper INSTANCT = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "createTime",source = "createTime",qualifiedByName = "dateToString")
PersonDTO conver(Person person);
4、MapStruct 集合映射、Map映射、枚举映射和Stream 流映射
4.1 集合映射
以上是关于MapStruct 一文读懂的主要内容,如果未能解决你的问题,请参考以下文章