当前位置:网站首页>Mapstructure detoxifies object mapping

Mapstructure detoxifies object mapping

2020-11-09 10:49:00 JaJian

Preface

MVC Mode is the standard development mode of current mainstream projects , In this mode, the hierarchical structure of the framework is clear , It is mainly divided into Controller,Service,Dao. In a hierarchical structure , There will be differences in data transmission requirements between layers , We can't use an object to run through 3 layer , This does not conform to the development specification and is not flexible enough .

We often encounter the inconsistency of field format requirements between levels , For example, a field in a database is datetime Date format , The stored value of this timestamp in the database is 2020-11-06 23:59:59.999999, But when it is passed to the front end, the interface is required to return yyyy-MM-dd The format of , Or some data in the database is a comma concatenation String type , But the front end needs to be cut List Type, etc. .

So we propose a hierarchical object model , That's what we see VO,DTO,DO,PO wait . This way of distinguishing the hierarchical object model makes clear the object passing between our levels , But the transformation and value copy between object models is really troublesome , Copy and copy , Back and forth , The process is repetitive and tedious , Writing such mapping code is a tedious and error prone task .

The simplest and crude way to copy is to keep new Objects and then between objects setter and getter, This way can deal with less field attributes , If there are many attribute fields, then the large segment of set,get The code is not elegant . So we need to use the object copy tool , At present, there are many in the market, such as BeanCopy,Dozer wait , But I don't feel that good enough , Today I recommend an entity mapping tool that is MapStruct.

Introduce

MapStruct Its official website is https://mapstruct.org/MapStruct, It's a fast and safe bean Mapping code generator , Only simple annotation is needed to realize the property transformation between objects , Is a Apache LICENSE 2.0 Licensed open source products ,Github The source code address is https://github.com/mapstruct.

Through the official website of three consecutive questions (What,Why,How) We can get a general idea of MapStruct The role of , Its advantages and how it is realized .

From the above three questions, we can get the following information :

  • Based on convention over configuration approach
    MapStruct Greatly simplified Java bean Implementation of mapping between types , It works with simple annotations . The generated mapping code uses normal method calls instead of reflection , So fast , Type safe and easy to understand .

  • Build at compile time Bean mapping
    Compared with other mapping frameworks ,MapStruct Build at compile time Bean mapping , This ensures high performance , And developers can get quick feedback and thorough error checking .

  • An annotation processor
    MapStruct It's an annotation processor , Inserted Java compiler , Can be used for command line build (Maven,Gradle etc. ), It can also be used for your preferred IDE in (IDEA,Eclipse etc. ).

Code writing

MapStruct need Java 1.8 Or later . about Maven-based Project , stay pom Add the following dependencies to the file

<!--  Specify the version -->
<properties>
    <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
</properties>
<!--  Add dependency  -->
<dependencies>
   <dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct</artifactId>
	<version>${org.mapstruct.version}</version>
   </dependency>
   <dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct-processor</artifactId>
	<version>${org.mapstruct.version}</version>
   </dependency>
</dependencies>

After the basic dependencies are introduced, you can write code , Simply define a mapping class , In order to Mybatis Medium mapper Interface distinction , We can call it xxObjectConverter.

For example, the mapping class name of the car object is CarObjectConverter, We have two object models DO and DTO, Their internal attribute fields are as follows :

The persistent object model of database CarDo

public class Car {
    @ApiModelProperty(value = " Primary key id")
    private Long id;
	
    @ApiModelProperty(value = " Manufacturer ")
    private String manufacturers;
	
    @ApiModelProperty(value = " Distribution channel ")
    private String saleChannel;

    @ApiModelProperty(value = " Date of manufacture ")
    private Date productionDate;
    ...
}

The object model of transmission between levels CarDto

public class CarDto {
    @ApiModelProperty(value = " Primary key id")
    private Long id;
	
    @ApiModelProperty(value = " Manufacturer ")
    private String maker;
	
    @ApiModelProperty(value = " Distribution channel ")
    private List<Integer> saleChannel;

    @ApiModelProperty(value = " Date of manufacture ")
    private Date productionDate;
    ...
}

Then write specific MapStruct Object mapper

@Mapper
public interface CarObjectConverter{

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    CarDto carToCarDto(Car car);

}

For the same field name, there is no need to specify additional mapping rules , However, the attributes with different field names need to indicate the mapping rules of the fields , Above we persistent layer DO The field name of the manufacturer of is manufacturers And the transmission between layers DTO In the model maker, We need to go through the mapping method @Mapping The annotation points out the mapping rules , My personal habit is to like to target Write it at the front ,source Written in the back , This is consistent with the position of the mapped object , When there are many difference fields, it is convenient to compare and not easy to confuse .

In the development process, we often encounter some date format conversion , As I said at the beginning of the article , In this case, we can also specify the mapping rules of the date

@Mapper
public interface CarObjectConverter{

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    @Mapping(target = "productionDate", dateFormat = "yyyy-MM-dd", source = "productionDate")
    CarDto carToCarDto(Car car);

}

These are simple field mappings , But sometimes the field types between our two object models are inconsistent , The sales channel field of the above car saleChannel, This is the string comma concatenation value in the database 1,2,3, And what we need to deliver is List Of Integer type , How does this complex mapping work ?

There is also a way , Let's write a string separated by commas and then converted to List The tool method of , as follows

public class CollectionUtils {

    public static List<Integer> list2String(String str) {
        if (StringUtils.isNoneBlank(str)) {
            return Arrays.asList(str.split(",")).stream().map(s -> Integer.valueOf(s.trim())).collect(Collectors.toList());
        }
        return null;
    }
}

And then mapping Mapping You can use the expression in

@Mapper
public interface CarObjectConverter {

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    @Mapping(target = "productionDate", dateFormat = "yyyy-MM-dd", source = "productionDate")
    @Mapping(target = "saleChannel", expression = "java(com.jiajian.demo.utils.CollectionUtils.list2String(car.getSaleChannel()))")
    CarDto carToCarDto(Car car);

}

This completes the mapping of all fields , We can call the object model transformation in the following way

CarDto carDto = CarObjectConverter.INSTANCE.carToCarDto(car);

This is between monomer objects Copy A lot of times we need List Transformation between object models , Just write another method carToCarDtos that will do

@Mapper
public interface CarObjectConverter{

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    @Mapping(target = "productionDate", dateFormat = "yyyy-MM-dd", source = "productionDate")
    @Mapping(target ="saleChannel", expression = "java(com.jiajian.demo.utils.CollectionUtils.list2String(car.getSaleChannel()))")
    CarDto carToCarDto(Car car);

    List<CarDto> carToCarDtos(List<Car> carList);

}

Find out

Would you wonder how this is done , We just create an interface, and then add an annotation to the interface method and specify the mapping rules of the fields in the annotation to realize the copy between object attributes , How does this work ?

We pass through here MapStruct An interface is created , To achieve specific functions, the interface must be implemented .

MapStruct An implementation class will be created for us when our code is compiled , And this implementation class through the field of setter, getter Method to implement the field assignment , So as to realize the mapping of objects .

Here's a little bit of attention : If you modify any mapping object , Remember to execute first mvn clean Start the project again , Otherwise, it will report an error when debugging .

ending

MapStrut The functions of the system are far less than those described above , I just picked out a few common grammar examples to explain , If you are interested, you can refer to the official reference document for more information ,Reference Guide.

meet MapStruct After that, I began to abandon the original ones in the project BeanCopyUtils Tools for , Relatively speaking MapStruct It's really simpler and easier to use, and it's very customizable .

You can see from the compiled file that MapStruct It's through setter,getter To copy property values , Then isn't this the simplest, safest and most efficient way ? It's just MapStruct Better to help us achieve , Avoid redundant duplicate code in the project , The greatest truths are the simplest .

版权声明
本文为[JaJian]所创,转载请带上原文链接,感谢