Java 实体映射工具 MapStruct器

背景

java分布式系统经常需要做do(数据库访问对象)对象跟dto(业务传输对象)。一般do对象只涉及系统内部跟数据库的交互,如果跟其他系统通过rpc交互,需要定义dto对象。
但是do对象跟dto对象有很多字段的名称和类型都是相同的,但是需要程序来做转换。
目前常用的方式并发量高的时候,都会有点性能问题。

常用方式

有很多博文专门写过,主要就是一些BeanUtils,常用的如下:

  1. spring包中的 BeanUtil
  2. cglib包中的 Beancopier
  3. Apache BeanUtils
  4. FastJson的转换
    上面的几种方式比较常见,下面看下fastJson的方式。
/**
     * 对象映射
     * 按照指定的目标class创建一个目标对象,然后将源对象中同名称的属性映射到新的目标对象并返回
     *
     * @param sourceObject 源对象
     * @param targetClass  目标class
     * @param <E>          泛型
     * @return 目标对象
     */
    public static <E> E mapObject(Object sourceObject, Class<E> targetClass) {
        String jsonString = JSONObject.toJSONString(sourceObject);
        return JSONObject.parseObject(jsonString, targetClass);
    }

具体的性能对比,可以参考别人的文章。链接

这几种方式有的通过反射,有的通过字节码生成,如果并发量比较高的情况下,会有些性能问题。

MapStruct框架

mapStruct是基于java注解处理器的实现方式,使用方只需要声明接口,框架在**编译期**负责实现。基于对象属性的get/set方法来做属性映射,所以性能是最高的。这意味着这些值是通过简单的getter / setter调用而不是反射或类似方法从源复制到目标的。
对于名称和类型兼容的属性,mapStruct会自动映射,很方便。对于不能直接映射的类型,可以通过配置的方式做定制化的映射。

1. 引入方式

基于maven的java项目,只需要引入jar包和打包插件即可。
如果跟lombok搭配的话,需要按照指定的方式配置,否则可能会出现异常。

...
<properties>
    <org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

2. 使用方式

2.1 声明接口

声明接口,通过@Mapper注解。@Mapper注释使MapStruct代码生成器在构建时创建CarMapper接口的实现。

@Mapper
public interface CarMapper {

    @Mapping(source = "make", target = "manufacturer")
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);

    @Mapping(source = "name", target = "fullName")
    PersonDto personToPersonDto(Person person);
}

框架自动生成的代码

// GENERATED CODE
public class CarMapperImpl implements CarMapper {

    @Override
    public CarDto carToCarDto(Car car) {
        if ( car == null ) {
            return null;
        }

        CarDto carDto = new CarDto();

        if ( car.getFeatures() != null ) {
            carDto.setFeatures( new ArrayList<String>( car.getFeatures() ) );
        }
        carDto.setManufacturer( car.getMake() );
        carDto.setSeatCount( car.getNumberOfSeats() );
        carDto.setDriver( personToPersonDto( car.getDriver() ) );
        carDto.setPrice( String.valueOf( car.getPrice() ) );
        if ( car.getCategory() != null ) {
            carDto.setCategory( car.getCategory().toString() );
        }
        carDto.setEngine( engineToEngineDto( car.getEngine() ) );

        return carDto;
    }

    @Override
    public PersonDto personToPersonDto(Person person) {
        //...
    }

    private EngineDto engineToEngineDto(Engine engine) {
        if ( engine == null ) {
            return null;
        }

        EngineDto engineDto = new EngineDto();

        engineDto.setHorsePower(engine.getHorsePower());
        engineDto.setFuel(engine.getFuel());

        return engineDto;
    }
}

2.2 类型转换

一、 对于相同类型的属性,mapstrct会自动映射。对于不同类型的属性,mapStruct会做简单的类型转换。

  1. java基本类型,int <–> Integer , bool <–> Boolean等。
  2. java数字类型: int 、Long 、 Byte
  3. java基本类型和String的转换
  4. 枚举类型 and String.
  5. java.util.Date/XMLGregorianCalendar and String。可通过
    配置日期表达式,来做日期和字符串的转换。@Mapping(source = “manufacturingDate”, dateFormat = “dd.MM.yyyy”)
  6. 以及很多的日期格式和类型转换。

二、对象类型的映射,需要映射的对象属性不是java基本属性,是业务系统定义的对象。 这时可以自定义转换方法(比如自动生成代码中的personToPersonDto),如果找不到自定义的转换方法,mapStruct会自动生成映射方法(比如自动生成代码中的engineToEngineDto)。

三、集合类型的属性Collection or Map。
集合类型如果具有相同的元素类型:通过创建包含源属性中元素的目标集合类型的新实例,将复制具有相同元素类型的集合类型的属性。实现类中的carDto.setFeatures( new ArrayList( car.getFeatures() ) );
对于具有不同元素类型的集合类型的属性,每个元素将被单独映射并添加到目标集合中。

四、自定义映射。通过@Mapping注解可以配置自定义映射。

2.3 获取转换器

  1. 工厂模式
@Mapper
public interface CarMapper {

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

    CarDto carToCarDto(Car car);
}
  1. spring 模式
    声明Mapper时加上componentModel属性。
@Mapper(componentModel = "cdi")
public interface CarMapper {

    CarDto carToCarDto(Car car);
}

通过spring的@Autowired可以获取到实现类了。

@Autowired
private CarMapper mapper;

官方链接

官方文档写的很清晰,有疑问可以看文档。链接

发布了117 篇原创文章 · 获赞 219 · 访问量 55万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览