mapstruct 之 实体转换

MapStruct配置

简介:
1.在多模块多层级的开发中,每一层都有自己的数据模型,DO,DTO,VO等.
2.对象与对象之间进行转换,一般通过get,set方法.或者是BeanUtils进行转换,但是对象之间名称不同或者类型不同时,BeanUtils则不会进行处理,需要我们自己进行处理.
3.MapStruct是一个属性映射工具,基于注解进行开发,可以支持名称不同,类型不同等处理.

MapStruct配置

maven引入依赖:

	
<properties>
		<mapstruct.version>1.3.0.Final</mapstruct.version>
	</properties>
	
<!-- 实体映射工具类相关 -->
			<dependency>
				<groupId>org.mapstruct</groupId>
				<artifactId>mapstruct-jdk8</artifactId>
				<version>${mapstruct.version}</version>
			</dependency>

			<dependency>
				<groupId>org.mapstruct</groupId>
				<artifactId>mapstruct-processor</artifactId>
				<version>${mapstruct.version}</version>
			</dependency>


简单使用

简单使用
1.先定义一个接口:

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface PersonConvert {

    PersonConvert instance = Mappers.getMapper(PersonConvert.class);
    /**
     * DTO转DO
     * @return
     */
    PersonDO personDtoToPersonDO(PersonDTO dto);
}

注意这里的Mapper注解导入的包是 org.mapstruct.Mapper

2.定义两个实体:

public class PersonDO {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
public class PersonDTO {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public PersonDTO(){}
    public PersonDTO(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

进行测试:

public class Test {
    public static void main(String[] args) {
        PersonDTO personDTO = new PersonDTO("mapStruct",18);
        PersonDO personDO = PersonConvert.instance.personDtoToPersonDO(personDTO);
        System.out.println(personDO.getName()+":"+personDO.getAge());
    }
}

测试结果:
在这里插入图片描述
我们通过class可以查看mapStruct的是如何进行转换的.
在这里插入图片描述
从图中得知,是通过实现我们的接口,然后调用get,set方法进行转换.


字段名称不一样进行转换

字段名称不一样进行转换.
这个时候需要我们添加一些额外的注解:
将DO的名字变更一下

public class PersonDO {

    private String personName;

    private Integer age;

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

接口也改一下:

@Mapper
public interface PersonConvert {

    PersonConvert instance = Mappers.getMapper(PersonConvert.class);
    /**
     * DTO转DO
     * @return
     */
    @Mappings({
        @Mapping(source = "name", target = "personName")
    })
    PersonDO personDtoToPersonDO(PersonDTO dto);
}

通过注解将名字映射一下.
测试结果:
在这里插入图片描述


字段名称类型不一样进行转换以及注意点

字段名称不一样,类型不一样进行转换
DTO

public class PersonDTO {

    private String name;

    private Integer age;

    private Integer gender;

    public PersonDTO(String name, Integer age, Integer gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public PersonDTO(){}
    public PersonDTO(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

DO

public class PersonDO {

    private String personName;

    private Integer age;

    private Boolean personGender;



    public Boolean getPersonGender() {
        return personGender;
    }

    public void setPersonGender(Boolean personGender) {
        this.personGender = personGender;
    }


    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

接口也要相应的改一下:

@Mapper
public interface PersonConvert {

    PersonConvert instance = Mappers.getMapper(PersonConvert.class);
    /**
     * DTO转DO
     * @return
     */
    @Mappings({
        @Mapping(source = "name", target = "personName"),
        @Mapping(source = "gender", target = "personGender",qualifiedByName = "integerToBoolean")
    })
    PersonDO personDtoToPersonDO(PersonDTO dto);

    @Named("integerToBoolean")
    default Boolean integerToBoolean(Integer value){
        if (value == 1) {
            return false;
        }
        return true;
    }
}

qualifiedByName 注解和Named注解配合使用,代表这个字段的处理用指定的哪个方法. 这样可以帮我们解决类型不一致的问题.

测试:

public class Test {
    public static void main(String[] args) {
        PersonDTO personDTO = new PersonDTO("mapStruct",18,1);
        PersonDO personDO = PersonConvert.instance.personDtoToPersonDO(personDTO);
        System.out.println(personDO.getPersonName()+":"+personDO.getAge()+":"+personDO.getPersonGender());
    }
}

在这里插入图片描述
查看class类是不是处理的时候调用了我们的方法.
在这里插入图片描述
可以看到class实现类调用的是我们自定义的方法.

对于一些通用的类型转换,我们可以自定义类:
也可以写成这样:
增加一个类:

public class TypeStrategy {

    @Named("integerToBoolean")
    public Boolean integerToBoolean(Integer value){
        if (value == 1) {
            return false;
        }
        return true;
    }
}

接口处:

@Mapper(uses=TypeStrategy.class)
public interface PersonConvert {

    PersonConvert instance = Mappers.getMapper(PersonConvert.class);
    /**
     * DTO转DO
     * @return
     */
    @Mappings({
        @Mapping(source = "name", target = "personName"),
        @Mapping(source = "gender", target = "personGender",qualifiedByName = "integerToBoolean")
    })
    PersonDO personDtoToPersonDO(PersonDTO dto);
 }

这两种方式都是一样的效果.就是一个是调用接口默认的方法,一个是调用
@Mapper(uses=TypeStrategy.class)类里的方法.
在这里插入图片描述


注意点:
在我们使用多个实体转换多个实体的时候,
例如:

@Mapper(uses=TypeStrategy.class)
public interface PersonConvert {

    PersonConvert instance = Mappers.getMapper(PersonConvert.class);
    @Mappings({
        @Mapping(source = "name", target = "personName"),
        @Mapping(source = "gender", target = "personGender",qualifiedByName = "integerToBoolean")
    })
    List<PersonDO> personDtoListToPersonDOList(List<PersonDTO> dtoList);

像这样的是不对的:

在这里插入图片描述
可以看到运行的时候都会报错,说找不到该属性.这是工作中踩的坑.

而是应该将注解在单个实体中映射.

@Mapper(uses=TypeStrategy.class)
public interface PersonConvert {

    PersonConvert instance = Mappers.getMapper(PersonConvert.class);
    List<PersonDO> personDtoListToPersonDOList(List<PersonDTO> dtoList);
    /**
     * DTO转DO
     * @return
     */
    @Mappings({
        @Mapping(source = "name", target = "personName"),
        @Mapping(source = "gender", target = "personGender",qualifiedByName = "integerToBoolean")
    })
    PersonDO personDtoToPersonDO(PersonDTO dto);
    
}

测试类:

public class Test {
    public static void main(String[] args) {
        List<PersonDTO> listDTO = new LinkedList<>();
        PersonDTO personDTO2 = new PersonDTO("mapStruct2",19,0);
        PersonDTO personDTO = new PersonDTO("mapStruct",18,1);
        listDTO.add(personDTO);
        listDTO.add(personDTO2);
        List<PersonDO> personDOList = PersonConvert.instance.personDtoListToPersonDOList(listDTO);
        personDOList.forEach(personDO->
            System.out.println(personDO.getPersonName()+":"+personDO.getAge()
                +":"+personDO.getPersonGender()));
    }
}

结果:
在这里插入图片描述
可以查看class中生成的代码:
在这里插入图片描述
也是通过循环的方式去调用的单个实体的转换.

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值