1.mapstruct introduction
In projects, the mutual conversion of DO, BO, DTO, VO and other objects is often used, which requires an efficient and universal conversion tool. After all, the get/set method of each field will be very troublesome. MapStruct is such an attribute mapping tool. You only need to define a Mapper interface, and MapStruct will automatically implement this mapping interface, avoiding complicated and cumbersome mapping implementations.
2.Code project
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mapstruct</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.40</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
application.yaml
server:
port: 8088
DemoApplication.java
package com.et.mapstruct;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
entity
package com.et.mapstruct.entity;
import lombok.Data;
@Data
public class Car {
private String make;
private int numberOfSeats;
private CarType carType;
}
package com.et.mapstruct.entity;
import lombok.Data;
@Data
public class CarDTO {
private String make;
private int seatCount;
private String type;
}
package com.et.mapstruct.entity;
import lombok.Data;
@Data
public class CarType {
private String type;
}
mapper
package com.et.mapstruct.mapper;
import com.et.mapstruct.entity.Car;
import com.et.mapstruct.entity.CarDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
@Mapper(componentModel = "spring",imports = {LocalDateTime.class, Date.class, ZoneId.class})//交给spring管理
public interface CarMapping {
CarMapping CAR_MAPPING = Mappers.getMapper(CarMapping.class);
@Mapping(target = "type", source = "carType.type")
@Mapping(target = "seatCount", source = "numberOfSeats")
CarDTO carToCarDTO(Car car);
}
Just a few lines of code above are enough! It’s very simple! Explain the steps: First declare a mapping interface marked with @org.mapstruct.Mapper (not to be confused with the mybatis annotation), indicating that this is an entity type conversion interface. Here we declare a CAR_MAPPING to facilitate our call. Is CarDTO toCarDTO(Car car) familiar? It abstracts our conversion method like mybatis. The @org.mapstruct.Mapping annotation is used to declare the mapping of member attributes. This annotation has two important properties:
- source represents the source of the conversion. This is Car.
target
represents the target of the conversion。This isCarDTO
。
This is based on the parameter name of the member variable. If there is nesting, for example, there is a member variable carType of CarType type in Car, and its type attribute maps the type string in CarDTO, we use type.type to get the attribute value. If there are multiple layers, so on. MapStruct ultimately calls setter and getter methods instead of reflection. This is one of the reasons why its performance is relatively good. It is easier to understand that numberOfSeats maps to seatCount. Did we forget an attribute make? Because their positions and names are exactly the same, they can be omitted. Moreover, the packaging class is automatically unboxed and sealed, and is thread-safe. MapStruct not only has these functions, but also has other complex functions
Code repository
3.Test
package com.et.mapstruct;
import com.alibaba.fastjson2.JSONObject;
import com.et.mapstruct.entity.Car;
import com.et.mapstruct.entity.CarDTO;
import com.et.mapstruct.entity.CarType;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author simon
* @date 2023/12/12 16:56
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CarMappingTest {
private Car car;
private CarDTO carDTO;
@Autowired
private com.et.mapstruct.mapper.CarMapping CarMapping;
@Before
public void setUp() throws Exception {
car = new Car();
car.setMake("make");
CarType type = new CarType();
type.setType("type");
car.setCarType(type);
car.setNumberOfSeats(1);
}
@Test
public void testcarToCarDTO() {
carDTO = CarMapping.carToCarDTO(car);
System.out.println(JSONObject.toJSONString(carDTO));
}
}
output
{"make":"make","seatCount":1,"type":"type"}