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
  1. Use it in conjunction with Spring
  2. 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/…