How to use MapStruct

This article introduces

MapStruct can map certain types of objects to another type, such as converting multiple DO (business entity objects) objects into DTO (data transfer objects).
In addition to MapStruct, we have also used set/get, BeanUtils before, and of course there are other methods. We will discuss their pros and cons below. Let's first introduce the basic use of MapStruct.

Basic use

Student and StudentDTO conversion

  1. Convert the student object into a studentdto object
  2. Convert the student collection to the studentdto collection

model model
student

@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="Student对象", description="")
public class Student extends Model<Student> {
    
    

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "id")
      @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "学号")
    private String stuId;

    @ApiModelProperty(value = "名字")
    private String name;

    @ApiModelProperty(value = "性别 0 男,1 女")
    private Integer sex;

    @ApiModelProperty(value = "手机号")
    private String phone;

    @ApiModelProperty(value = "个人简介")
    private String info;

    @ApiModelProperty(value = "头像,picture表id")
    private Long picture;

    @ApiModelProperty(value = "班级")
    private String className;

    @ApiModelProperty(value = "专业")
    private String major;

    @ApiModelProperty(value = "所在小组")
    private Long gId;

}

studentdto object

@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "学生DTO对象", description = "返回某一个学生最基本的信息")
public class StudentDTO {
    
    


    @ApiModelProperty(value = "id")
    private Long id;

    @ApiModelProperty(value = "名字")
    private String name;

    @ApiModelProperty(value = "性别 0 男,1 女")
    private Integer sex;

    @ApiModelProperty(value = "班级")
    private String className;

    @ApiModelProperty(value = "学号")
    private Long stuId;

    @ApiModelProperty(value = "手机号")
    private String phone;
}

manual

1. Introduce dependencies

        <!--Java 实体映射工具 —— mapStruct依赖-->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${
    
    mapstruct.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${
    
    mapstruct.version}</version>
        </dependency>

2. Writing the object conversion interface
is usually at the server layer.
Insert picture description here

package com.marchsoft.group.manager.system.service.mapstruct;
/**
 * @Mapper 定义这是一个MapStruct对象属性转换接口,在这个类里面规定转换规则
 *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制。  注解详解看下方。
 */
@Mapper
public interface StudentMapStruct {
    
    


    /**
     * 获取该类自动生成的实现类的实例
     * 接口中的属性都是 public static final 的 方法都是public abstract的
     */
    StudentMapStruct INSTANCES = Mappers.getMapper(StudentMapStruct.class);

   //转换对象
    StudentDTO toStudentDTO(Student student);
    //转换集合
    List<StudentDTO> toListStudentDTO(List<Student> student);
}

3. First use

 		 //设置每页的容量为5,这里是一个分页查询。
        Integer pageCount=2;
        Page<Student> page = new Page<>(pageCurrent,pageCount);
        Page<Student> studentPage = studentMapper.selectPage(page, null);
		//获取数据库查询的对象
        List<Student> students = studentPage.getRecords();
        //转换成DTO集合
        List<StudentDTO> studentsDTO = StudentMapStruct.INSTANCES.toListStudentDTO(students);
        System.out.println(students);
        System.out.println(studentsDTO);

4. Results

StudentDTO(id=1, name=张三, sex=0, className=4561, stuId=2004, phone=19907865257)

[StudentDTO(id=3, name=花花, sex=1, className=546, stuId=2045614106, phone=1990245212), StudentDTO(id=4, name=花花, sex=1, className=动科181, stuId=2078788107, phone=199885454512)]

Source code analysis

After creating the StudentMapStruct interface and running it, the system will generate its implementation class for us by default. The bottom layer is to use the most basic set/get
Insert picture description here

Advanced use

Some processor option configurations provided by MapStruct

MapStruct provides us with @Mapper annotations and some property configurations.

Such as: two commonly used componentMode l and unmappedTargetPolicy

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface StudentMapStruct {
    
    
}

1.componentModel = "XX" four attribute values

  • default: By default, mapstruct does not use any component types, and the automatically generated instance objects can be obtained through Mappers.getMapper(Class).
  • cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
  • Spring (used frequently): An @Component annotation will be automatically added to the generated implementation class, which can be injected through Spring's @Autowired method
  • jsr330: @javax.inject.Named and @Singleton annotations will be added to the generated implementation class, which can be obtained through the @Inject annotation.

2. unmappedTargetPolicy=ReportingPolicy.XX three attribute values

In not using the default policy report the case of a source attribute value to fill the target mapping method to be applied
Insert picture description here

-IGNORE will be ignored
-WARN causes a warning when building
-ERROR mapping code generation failed

Other options configuration
Insert picture description here

Use Spring dependencies

We use componentModel="spring", we don’t need to create an instance of StudentMapStrct, it can be used directly through @Autowired

接口中:

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface StudentMapStruct {
    
    
    StudentDTO toStudentDTO(Student student);
    List<StudentDTO> toListStudentDTO(List<Student> student);
   }

注入:
    @Autowired  
    StudentMapStruct studentMapStruct;

直接使用:
     StudentDTO studentDTO = studentMapStruct.toStudentDTO(student);
     List<StudentDTO> studentsDTO =studentMapStruct.toListStudentDTO(students);

Inconsistent attribute names

  • When the attributes are inconsistent, we can use @Mapping
@Mapping(source = "name", target = "stuName")

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface StudentMapStruct {
    
    
	@Mapping(source = "name", target = "stuName")
    StudentDTO toStudentDTO(Student student);
    @Mapping(source = "name", target = "stuName")
    List<StudentDTO> toListStudentDTO(List<Student> student);
   }

Inconsistent attribute types

When the types are inconsistent, mapstruct will help us to do automatic conversion, but the automatic conversion type is limited

Types that can be automatically converted

  1. Basic types and their packaging
  2. Between the basic type of packaging type and the String type
  3. Between String type and enumeration type
  4. Custom constant

Entity model

@Data
public class UserTest {
    
    
   private String gender;
   private  Integer age;
}


@Data
public class UserTestDTO {
    
    
   private  boolean sex;
   private String age;
}

The type conversion class
should be added to the bean container, because later when we need to use it, it will be called automatically

@Component
public class BooleanStrFormat {
    
    
   public String toStr(Boolean gender) {
    
    
       if (gender) {
    
    
           return "男";
       } else {
    
    
           return "女";
       }
   }
   public Boolean toBoolean(String str) {
    
    
       if (str.equals("Y")) {
    
    
           return true;
       } else {
    
    
           return false;
       }
   }
}

Mapping interface
Use uses={BooleanStrFormat.class}) to introduce the conversion class, which will be called automatically

@Component
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE,uses={
    
    BooleanStrFormat.class})
public interface UserStruct {
    
    
    @Mappings({
    
    
            @Mapping(source = "gender",target = "sex"),
    })
    UserTestDTO toUserTestDTO(UserTest userTest);
}


Test class

    @Autowired
    UserStruct userStruct;
    @Test
    public void mapStructTest(){
    
    
        UserTest userTest = new UserTest();
        userTest.setGender("Y");
        userTest.setAge(18);
        UserTestDTO userTestDTO = userStruct.toUserTestDTO(userTest);
        System.out.println(userTestDTO);
    }

result:

UserTestDTO(sex=true, age=18)

Multiple sources map a target

Sometimes, we may encounter assigning the values ​​of two different objects to the same object. At this time, we need to use the @Mapping annotation.

@Mapper(componentModel = "spring")
public interface GoodInfoMapper {
    
    
    @Mappings({
    
    
            @Mapping(source = "type.name",target = "typeName"),
            @Mapping(source = "good.id",target = "goodId"),
            @Mapping(source = "good.title",target = "goodName"),
            @Mapping(source = "good.price",target = "goodPrice")
    })
    GoodInfoDTO fromGoodInfoDTO(GoodInfo good, GoodType type);
}

Date conversion/fixed value

  固定值:constant
    @Mapping(source = "name", constant = "hollis")
  日期转换:dateForma
    @Mapping(source = "person.begin",target="birth" dateFormat="yyyy-MM-dd HH:mm:ss")

Package use

We can encapsulate a struct class to satisfy the basic use of mapping for all objects

detailed steps:

1. Create a public processing class BaseMapper

public interface BaseMapper<D, E> {
    
    

    /**
     * DTO转Entity
     * @param dto /
     * @return /
     */
    E toEntity(D dto);

    /**
     * Entity转DTO
     * @param entity /
     * @return /
     */
    D toDto(E entity);

    /**
     * DTO集合转Entity集合
     * @param dtoList /
     * @return /
     */
    List <E> toEntity(List<D> dtoList);

    /**
     * Entity集合转DTO集合
     * @param entityList /
     * @return /
     */
    List <D> toDto(List<E> entityList);
}

2. Create a struct for each entity object, inherit BaseMapper

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface StudentMapStruct extends BaseMapper<StudentDTO,Student> {
    
    
}

3. Use

        StudentDTO studentDTO = studentMapStruct.toDto(student);
        
        List<StudentDTO> studentsDTO =studentMapStruct.toDto(students);

4. Results

StudentDTO(id=1, name=张三, sex=0, className=4561, stuId=2004, phone=19907865257)

[StudentDTO(id=3, name=花花, sex=1, className=546, stuId=2045614106, phone=1990245212), StudentDTO(id=4, name=花花, sex=1, className=动科181, stuId=2078788107, phone=199885454512)]

Performance comparison

Insert picture description here

Annotation introduction

Insert picture description here

Reference blog:

At the time of writing this article, I was in the preliminary learning stage, and I am grateful to these articles for helping me learn.

  1. MapStruct super simple study notes
  2. Throw away those BeanUtils tools, MapStruct is so fragrant! ! !
  3. Why does Alibaba prohibit the use of Apache Beanutils for property
    copying?
  4. Getting started with MapStruct

Guess you like

Origin blog.csdn.net/zhang19903848257/article/details/113739973