MapStruct
1 What is a MapStruct?
MapStruct is a code generator used for mapping between Java beans, such as Entity to DTO.
2 Why MapStruct?
plan | advantages | disadvantages |
---|---|---|
Handwritten code | 1. High flexibility 2. Facilitate subsequent reconstruction |
1. Repetitive work 2. Handwritten code tends to leave out fields |
Beanutils.copyproperties is implemented using reflection | 1. Easy to use 2. Apache package efficiency is relatively low, while Spring package efficiency is acceptable |
1. Insufficient support for complex scenarios. The control copy granularity is too coarse 2. Difficult to reconstruct |
MapStruct | 1. High flexibility support simple, complex, nested, custom extension and other means 2. Compilation time generation, no efficiency problem |
3. Inconvenient for subsequent reconstruction |
3 Combined with SpringBoot
3.1 Importing Maven dependencies and plug-ins
<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.3.12. RELEASE</version>
<relativePath/> <! -- lookup parent from repository -->
</parent>
<groupId>cn.muzaijian.mall</groupId>
<artifactId>mapstruct</artifactId>
<version>1.0-RELEASE</version>
<name>mapstruct</name>
<description>Map Struct project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<mapstruct.version>1.4.1. The Final</mapstruct.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<! -- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<! -- SpringBoot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<! MapStruct domain mapping tool -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<! -- Spring Boot plugin that can package an application as an executable Jar -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<! MapStruct MapStruct plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<! -- MapStruct annotation handler -->
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<! -- Lombok annotation processor -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<! -- MapStruct and Lombok annotation binding handler -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Copy the code
- The latter two annotation handlers can be removed if lombok is not in use
3.2 write the entity
3.2.1 PmsBrand
package cn.muzaijian.mall.mapstruct.mbg.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/** * <p> **@author muzaijian
* @sinceThe 2021-07-12 * /
@Data
@EqualsAndHashCode(callSuper = false)
public class PmsBrand implements Serializable {
private Long id;
/** * name */
private String name;
/**
* 首字母
*/
private String firstLetter;
/** ** sort */
private Integer sort;
/** * if it is a manufacturer brand: 0-> No; 1 - > * /
private Integer factoryStatus;
/** * Whether to display: 0-> do not display; 1 - > display * /
private Integer showStatus;
/** ** quantity */
private Integer productCount;
/** ** number of comments */
private Integer productCommentCount;
/** * brand logo */
private String logo;
/** ** /
private String bigPic;
/** ** brand story */
private String brandStory;
}
Copy the code
3.2.2 PmsBrandItemDTO
package cn.muzaijian.mall.mapstruct.domain.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
ItemDTO * </p> **@author muzaijian
* @date2021/2/26 * /
@Data
@EqualsAndHashCode(callSuper = false)
public class PmsBrandItemDTO implements Serializable {
private String name;
private String firstLetter;
private Integer sort;
private Integer factoryStatus;
private Integer showStatus;
private String logo;
private String bigPicture;
private String brandStory;
}
Copy the code
- You can see that PmsBrandItemDTO has fewer ID instance variables than PmsBrand and has changed bigPic to bigPicture
3.3 Programming MapStruct conversion interface
3.3.1 PmsBrandConvertDemoOne
package cn.muzaijian.mall.mapstruct.convert;
import cn.muzaijian.mall.mapstruct.domain.dto.PmsBrandItemDTO;
import cn.muzaijian.mall.mapstruct.mbg.entity.PmsBrand;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
/** * <p> **@author muzaijian
* @date2021/7/12 * /
@Mapper(componentModel = "spring")
public interface PmsBrandConvertDemoOne {
/** * ItemDTO convert entity **@paramBrandItemDTO brandItemDTO *@returnEntity */
@Mapping(source = "bigPicture", target = "bigPic")
PmsBrand convert(PmsBrandItemDTO brandItemDTO);
}
Copy the code
- Use it in conjunction with Spring
- If domain instance variables are different, use the @mapping annotation to specify the instance variable Mapping name
3.3.2 rainfall distribution on 10-12 PmsBrandConvertDemoTwo
package cn.muzaijian.mall.mapstruct.convert;
import cn.muzaijian.mall.mapstruct.domain.dto.PmsBrandItemDTO;
import cn.muzaijian.mall.mapstruct.mbg.entity.PmsBrand;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/** * <p> **@author muzaijian
* @date2021/7/13 * /
@Mapper
public interface PmsBrandConvertDemoTwo {
PmsBrandConvertDemoTwo INSTANCE = Mappers.getMapper(PmsBrandConvertDemoTwo.class);
/** * ItemDTO convert entity **@paramBrandItemDTO brandItemDTO *@returnEntity */
@Mapping(source = "bigPicture", target = "bigPic")
PmsBrand convert(PmsBrandItemDTO brandItemDTO);
}
Copy the code
3.4 Viewing the Compiled Implementation Class
3.4.1 track PmsBrandConvertDemoOneImpl
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package cn.muzaijian.mall.mapstruct.convert;
import cn.muzaijian.mall.mapstruct.domain.dto.PmsBrandItemDTO;
import cn.muzaijian.mall.mapstruct.mbg.entity.PmsBrand;
import org.springframework.stereotype.Component;
@Component
public class PmsBrandConvertDemoOneImpl implements PmsBrandConvertDemoOne {
public PmsBrandConvertDemoOneImpl(a) {}public PmsBrand convert(PmsBrandItemDTO brandItemDTO) {
if (brandItemDTO == null) {
return null;
} else {
PmsBrand pmsBrand = new PmsBrand();
pmsBrand.setBigPic(brandItemDTO.getBigPicture());
pmsBrand.setName(brandItemDTO.getName());
pmsBrand.setFirstLetter(brandItemDTO.getFirstLetter());
pmsBrand.setSort(brandItemDTO.getSort());
pmsBrand.setFactoryStatus(brandItemDTO.getFactoryStatus());
pmsBrand.setShowStatus(brandItemDTO.getShowStatus());
pmsBrand.setLogo(brandItemDTO.getLogo());
pmsBrand.setBrandStory(brandItemDTO.getBrandStory());
returnpmsBrand; }}}Copy the code
3.4.2 PmsBrandConvertDemoTwoImpl
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package cn.muzaijian.mall.mapstruct.convert;
import cn.muzaijian.mall.mapstruct.domain.dto.PmsBrandItemDTO;
import cn.muzaijian.mall.mapstruct.mbg.entity.PmsBrand;
public class PmsBrandConvertDemoTwoImpl implements PmsBrandConvertDemoTwo {
public PmsBrandConvertDemoTwoImpl(a) {}public PmsBrand convert(PmsBrandItemDTO brandItemDTO) {
if (brandItemDTO == null) {
return null;
} else {
PmsBrand pmsBrand = new PmsBrand();
pmsBrand.setBigPic(brandItemDTO.getBigPicture());
pmsBrand.setName(brandItemDTO.getName());
pmsBrand.setFirstLetter(brandItemDTO.getFirstLetter());
pmsBrand.setSort(brandItemDTO.getSort());
pmsBrand.setFactoryStatus(brandItemDTO.getFactoryStatus());
pmsBrand.setShowStatus(brandItemDTO.getShowStatus());
pmsBrand.setLogo(brandItemDTO.getLogo());
pmsBrand.setBrandStory(brandItemDTO.getBrandStory());
returnpmsBrand; }}}Copy the code
- The difference is only visible PmsBrandConvertDemoOneImpl one more @ Component annotation, can directly use dependency injection method call
3.5 test
package cn.muzaijian.mall.mapstruct;
import cn.muzaijian.mall.mapstruct.convert.PmsBrandConvertDemoOne;
import cn.muzaijian.mall.mapstruct.convert.PmsBrandConvertDemoTwo;
import cn.muzaijian.mall.mapstruct.domain.dto.PmsBrandItemDTO;
import cn.muzaijian.mall.mapstruct.mbg.entity.PmsBrand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MapstructApplicationTests {
@Autowired
private PmsBrandConvertDemoOne brandConvertDemoOne;
@Test
void testMapStructDemoOne(a) {
PmsBrandItemDTO brandItemDTO = new PmsBrandItemDTO();
brandItemDTO.setBigPicture("picture");
brandItemDTO.setBrandStory("Aliyun Story");
brandItemDTO.setLogo("Ali Cloud Logo");
PmsBrand brand = brandConvertDemoOne.convert(brandItemDTO);
System.out.println(brand);
}
@Test
void testMapStructDemoTwo(a) {
PmsBrandItemDTO brandItemDTO = new PmsBrandItemDTO();
brandItemDTO.setBigPicture("picture");
brandItemDTO.setBrandStory(Tencent Cloud Story);
brandItemDTO.setLogo("Tencent Cloud Logo"); PmsBrand brand = PmsBrandConvertDemoTwo.INSTANCE.convert(brandItemDTO); System.out.println(brand); }}Copy the code
- DemoOne is called as an injection, and DemoTwo is called as a member variable INSTANCE generated in the interface
4 Project source code address
Github.com/a616766585/…