ModelMapper 一文读懂

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

1、ModelMapper简介

1.1 引入ModelMapper 的依赖 

1.2 进行Mapping映射

1.3 ModelMapper 工作原理 

2、ModelMapper 基础操作 

2.1 ModelMapper 基本映射

2.2  ModelMapper 集合转换

 2.3  ModelMapper 指定默认值

 2.4  ModelMapper 属性值转换

 2.5  ModelMapper 属性值跳过

 2.6 ModelMapper  条件映射

2.7 ModelMapper  转换

2.8 ModelMapper 提供者


1、ModelMapper简介

ModelMapper是一个旨在简化对象映射框架它根据约定处理对象之间的映射方式为处理特定对象提供一个简单的、安全的、可重构安全API。

1.1 引入ModelMapper 的依赖 

在pom.xml文件添加modelMapper相关依赖

<dependency>
         <groupId>org.modelmapper</groupId>
         <artifactId>modelmapper</artifactId>
         <version>2.4.2</version>
</dependency>

1.2 进行Mapping映射

使用ModelMapper来映射对象主要分为以下两大类

  • Source model: 源数据对象
  • Destination model:模板数据对象

1.3 ModelMapper 工作原理 

        在ModelMapper 调用map() 方法时先分分析源对象和目标对象类型根据匹配策略和其他配置确定那些属性需要进行隐式匹配然后根据这些匹配映射数据。

        即使源对象和目标对象的属性不同ModelMapper 也会尽最大努力根据配置的匹配策略将源对象和目标对象的属性进行匹配。

        在实际项目开发过程中进行对象类型转换经常出现如下操作

  • Controller层接受到客户端的DTO 对象通过ModelMapper 框架将DTO对象转换为Service层可操作执行的BO对象。
  • Service层调用Dao 层方法时通过ModelMapper框架将BO对象转换为Dao 层可操作执行的PO对象。如果调用Dao 层有结果对象返回又需要ModelMapper 框架将PO对象转换为BO对象进行返回。
  • Controller层调用Service 层有对象返回需要通过ModelMapper框架对象将BO对象转换为VO对象返回给客户端。

2、ModelMapper 基础操作 

2.1 ModelMapper 基本映射

创建ModelMapper映射步骤总结

1、添加ModelMapper 依赖Jar 包。

2、实例化ModelMapper类调用map 方法传入源对象和目标对象。

实战创建Order和OrderDTO 类定义通过ModelMapper实现Order类实例对象转换OrderDTO 类实例对象。

package com.zzg.modelmapper.po.source;

import lombok.Data;

@Data
public class Order {
    private Address address;
    private Customer customer;
}


package com.zzg.modelmapper.po.source;

import lombok.Data;

@Data
public class Address {
    private String street;
    private String city;
}


package com.zzg.modelmapper.po.source;

import lombok.Data;

@Data
public class Customer {
    private Name name;
}


package com.zzg.modelmapper.po.source;

import lombok.Data;

@Data
public class Name {
    private String firstName;
    private String lastName;
}
package com.zzg.modelmapper.po.target;

import lombok.Data;

@Data
public class OrderDTO {
    private String customerFirstName;
    private String customerLastName;
    private String addressStreet;
    private String addressCity;
}

测试

package com.zzg.modelmapper.po.test;

import com.alibaba.fastjson.JSON;
import com.zzg.modelmapper.po.source.Address;
import com.zzg.modelmapper.po.source.Customer;
import com.zzg.modelmapper.po.source.Name;
import com.zzg.modelmapper.po.source.Order;
import com.zzg.modelmapper.po.target.OrderDTO;
import org.modelmapper.ModelMapper;

public class OneTest {
    public static void main(String[] args) {
        ModelMapper modelMapper = new ModelMapper();
        Order order = new Order();
        Customer customer = new Customer();
        Name name = new Name();
        name.setLastName("周");
        name.setFirstName("程宇");
        customer.setName(name);
        Address address = new Address();
        address.setCity("深圳");
        address.setStreet("龙岗区横岗街道");
        order.setCustomer(customer);
        order.setAddress(address);
        OrderDTO orderDTO = modelMapper.map(order, OrderDTO.class);
        String jsonString = JSON.toJSONString(orderDTO);
        System.out.println("jsonString = " + jsonString);

    }
}

执行效果截图

2.2  ModelMapper 集合转换

功能要求将List<Order> 转换为List<OrderDTO>

功能实现通过modelMapper.map(源对象Class, new TypeToken<List<目标读写Class>>() {}.getType());

测试:

     Order order = new Order();
        Customer customer = new Customer();
        Name name = new Name();
        name.setLastName("周");
        name.setFirstName("程宇");
        customer.setName(name);
        Address address = new Address();
        address.setCity("深圳");
        address.setStreet("龙岗区横岗街道");
        order.setCustomer(customer);
        order.setAddress(address);

        Order order2 = new Order();
        Customer customer2 = new Customer();
        Name name2 = new Name();
        name2.setLastName("周");
        name2.setFirstName("晨曦");
        customer2.setName(name2);
        Address address2 = new Address();
        address2.setCity("深圳");
        address2.setStreet("盐田区梅沙街道");
        order2.setCustomer(customer2);
        order2.setAddress(address2);

        List<Order> containers =  new ArrayList<>();
        containers.add(order);
        containers.add(order2);

        ModelMapper modelMapper = new ModelMapper();
        List<OrderDTO> orderDTOs = modelMapper.map(containers, new TypeToken<List<OrderDTO>>() {}.getType());
        String jsonString = JSON.toJSONString(orderDTOs);
        System.out.println("jsonString = " + jsonString);
    }

执行效果截图

 2.3  ModelMapper 指定默认值

功能要求Order类实例对象 转换OrderDTO 类实例对象时将street属性值设置为:龙岗区横岗街道"。

功能实现

  public static void main(String[] args) {
        ModelMapper modelMapper = new ModelMapper();
        Order order = new Order();
        Customer customer = new Customer();
        Name name = new Name();
        name.setLastName("周");
        name.setFirstName("程宇");
        customer.setName(name);
        Address address = new Address();
        address.setCity("深圳");
        address.setStreet("盐田区梅沙街道");
        order.setCustomer(customer);
        order.setAddress(address);

        modelMapper.createTypeMap(Order.class, OrderDTO.class)
                .addMappings(mapper-> mapper.using((Converter<String, String>) context ->{
                   return "龙岗区横岗街道" ;
                }).map(it-> it.getAddress().getStreet(),OrderDTO::setAddressStreet));

        OrderDTO orderDTO = modelMapper.map(order, OrderDTO.class);
        String jsonString = JSON.toJSONString(orderDTO);
        System.out.println("jsonString = " + jsonString);
    }

执行效果截图

 2.4  ModelMapper 属性值转换

功能要求OrderDTO类对象新增cityTest 和streetTest 属性对应属性值为Order类实例对象Address 属性对象中的city 和street属性。

package com.zzg.modelmapper.po.target;

import lombok.Data;

@Data
public class OrderDTO {
    private String customerFirstName;
    private String customerLastName;
    private String addressStreet;
    private String addressCity;
    /**
     * 新增属性
     */
    private String cityTest;
    private String streetTest;
}

测试

public static void main(String[] args) {
        ModelMapper modelMapper = new ModelMapper();
        Order order = new Order();
        Customer customer = new Customer();
        Name name = new Name();
        name.setLastName("周");
        name.setFirstName("程宇");
        customer.setName(name);
        Address address = new Address();
        address.setCity("深圳");
        address.setStreet("盐田区梅沙街道");
        order.setCustomer(customer);
        order.setAddress(address);

        OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
                .addMappings(mapper-> {
                            // 自定义属性转换
                            mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                            mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                        }).map(order);

        String jsonString = JSON.toJSONString(orderDTO);
        System.out.println("jsonString = " + jsonString);
    }

执行效果截图

 拓展功能需求OrderDTO 类对象新增枚举对象属性OrderSource orderSource, 对应属性值为Order类实例对象新增字符串属性String orderSource

package com.zzg.modelmapper.po.target;

import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public enum OrderSource {
    Mobile("1", "移动端"),
    Web("2", "网页端"),
    Other("3", "其他");
    private String type;
    private String message;

    OrderSource(){

    }

    OrderSource(String type, String message) {
        this.type = type;
        this.message = message;
    }

    /**
     * 枚举转Map
     */
    private static Map<String, OrderSource> map = Stream.of(OrderSource.values()).collect(Collectors.toMap(OrderSource::getType, Function.identity(), (v1, v2) -> v1));

    public static OrderSource getInstance(String type){
        return map.get(type);
    }
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }


    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
package com.zzg.modelmapper.po.target;

import lombok.Data;

@Data
public class OrderDTO {
    private String customerFirstName;
    private String customerLastName;
    private String addressStreet;
    private String addressCity;
    /**
     * 新增属性
     */
    private String cityTest;
    private String streetTest;
    private OrderSource orderSource;
}
package com.zzg.modelmapper.po.source;

import lombok.Data;

@Data
public class Order {
    private Address address;
    private Customer customer;
    /**
     * 新增订单来源属性
     */
    private String orderSource;
}

测试

 public static void main(String[] args) {
            ModelMapper modelMapper = new ModelMapper();
            Order order = new Order();
            Customer customer = new Customer();
            Name name = new Name();
            name.setLastName("周");
            name.setFirstName("程宇");
            customer.setName(name);
            Address address = new Address();
            address.setCity("深圳");
            address.setStreet("盐田区梅沙街道");
            order.setCustomer(customer);
            order.setAddress(address);
            order.setOrderSource("1");

            OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
                    .addMappings(mapper-> {
                        // 自定义属性转换
                        mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                        mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                        // 字符串转枚举
                        mapper.using((Converter<String, OrderSource>) context ->{
                                return OrderSource.getInstance(context.getSource()) ;
                        }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);
                    }).map(order);

            String jsonString = JSON.toJSONString(orderDTO);
            System.out.println("jsonString = " + jsonString);
        }

执行效果截图

 2.5  ModelMapper 属性值跳过

ModelMapper 隐式创建从源类型到目标类型中每个属性的映射但有时可能需要跳过某些目标属性的映射。

功能要求跳过OrderDTO类实例对象的addressStreet 和addressCity 属性值映射。

测试:

public static void main(String[] args) {
    ModelMapper modelMapper = new ModelMapper();
    Order order = new Order();
    Customer customer = new Customer();
    Name name = new Name();
    name.setLastName("周");
    name.setFirstName("程宇");
    customer.setName(name);
    Address address = new Address();
    address.setCity("深圳");
    address.setStreet("盐田区梅沙街道");
    order.setCustomer(customer);
    order.setAddress(address);
    order.setOrderSource("1");

    OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
            .addMappings(mapper-> {
                //  跳过属性
                mapper.skip(OrderDTO::setAddressStreet);
                mapper.skip(OrderDTO::setAddressCity);
                // 自定义属性转换
                mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                // 字符串转枚举
                mapper.using((Converter<String, OrderSource>) context ->{
                    return OrderSource.getInstance(context.getSource()) ;
                }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);
            }).map(order);

    String jsonString = JSON.toJSONString(orderDTO);
    System.out.println("jsonString = " + jsonString);
}

执行效果截图

 2.6 ModelMapper  条件映射

ModelMapper 提供Condition条件接口判断是否执行源属性到模板属性映射。

功能要求在Order类中添加订单金额字段:amount, 在OrderDTO 类中添加订单金额字段:amount和订单优先级字段priority如果金额大于1000, priority 设置为最高基本=3其他设置为普通基本=2。

 public static void main(String[] args) {
            ModelMapper modelMapper = new ModelMapper();
            Order order = new Order();
            Customer customer = new Customer();
            Name name = new Name();
            name.setLastName("周");
            name.setFirstName("程宇");
            customer.setName(name);
            Address address = new Address();
            address.setCity("深圳");
            address.setStreet("盐田区梅沙街道");
            order.setCustomer(customer);
            order.setAddress(address);
            order.setOrderSource("1");
            order.setAmount(100000);

            OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
                    .addMappings(mapper-> {
                        //  添加判断条件 + 添加自定义转换条件
                        mapper.when((Condition<Integer, String>) context -> context.getSource() > 0).using((Converter<Integer, String>) context ->{
                                return context.getSource() >=1000 ? "3":"2" ;
                        }).map(it-> it.getAmount(),OrderDTO::setPriority);
                        // 自定义属性转换
                        mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                        mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                        // 字符串转枚举
                        mapper.using((Converter<String, OrderSource>) context ->{
                            return OrderSource.getInstance(context.getSource()) ;
                        }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);
                    }).map(order);

            String jsonString = JSON.toJSONString(orderDTO);
            System.out.println("jsonString = " + jsonString);
        }

订单金额大于10000执行效果截图

订单金额小于10000执行效果截图

 拓展功能如果没有设置订单金额将priority 设置为异常订单=1。

测试

  public static void main(String[] args) {
            ModelMapper modelMapper = new ModelMapper();
            Order order = new Order();
            Customer customer = new Customer();
            Name name = new Name();
            name.setLastName("周");
            name.setFirstName("程宇");
            customer.setName(name);
            Address address = new Address();
            address.setCity("深圳");
            address.setStreet("盐田区梅沙街道");
            order.setCustomer(customer);
            order.setAddress(address);
            order.setOrderSource("1");

            OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
                    .addMappings(mapper-> {
                        //  添加判断条件 + 添加自定义转换条件
                        mapper.when((Condition<Integer, String>) context -> {
                            if(context.getSource() != null && context.getSource()> 0){
                                return true;
                            }
                            return false;
                        }).using((Converter<Integer, String>) context ->{
                                return context.getSource() >=1000 ? "3":"2" ;
                        }).map(it-> it.getAmount(),OrderDTO::setPriority);
                        // 自定义属性转换
                        mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                        mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                        // 字符串转枚举
                        mapper.using((Converter<String, OrderSource>) context ->{
                            return OrderSource.getInstance(context.getSource()) ;
                        }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);
                    }).map(order);

            String jsonString = JSON.toJSONString(orderDTO);
            System.out.println("jsonString = " + jsonString);
        }

 订单金额无执行效果截图

结果由于没有设置订单金额导致OrderDTO 类对象中的 priority 属性字段没有对应 映射这与我们提出的功能要求不符需要添加以下业务逻辑处理

如果订单金额为空 或者为0需要将OrderDTO 类对象中的 priority 属性字段映射为1(异常订单类型)

   public static void main(String[] args) {
            ModelMapper modelMapper = new ModelMapper();
            Order order = new Order();
            Customer customer = new Customer();
            Name name = new Name();
            name.setLastName("周");
            name.setFirstName("程宇");
            customer.setName(name);
            Address address = new Address();
            address.setCity("深圳");
            address.setStreet("盐田区梅沙街道");
            order.setCustomer(customer);
            order.setAddress(address);
            order.setOrderSource("1");

            OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
                    .addMappings(mapper-> {
                        //  添加判断条件 + 添加自定义转换条件
                        mapper.when((Condition<Integer, String>) context -> {
                            if(context.getSource() != null && context.getSource()> 0){
                                return true;
                            }
                            return false;
                        }).using((Converter<Integer, String>) context ->{
                                return context.getSource() >=1000 ? "3":"2" ;
                        }).map(it-> it.getAmount(),OrderDTO::setPriority);
                        // 添加判空添加 + 添加默认值
                        mapper.when((Condition<Integer, ?>) condition ->{
                            if(condition.getSource() == null ||  condition.getSource() == 0){
                                return true;
                            }
                            return false;
                        }).using((Converter<Integer, String>) converter->{
                            return "1";
                        }).map(it-> it.getAmount(),OrderDTO::setPriority);

                        // 自定义属性转换
                        mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                        mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                        // 字符串转枚举
                        mapper.using((Converter<String, OrderSource>) context ->{
                            return OrderSource.getInstance(context.getSource()) ;
                        }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);
                    }).map(order);

            String jsonString = JSON.toJSONString(orderDTO);
            System.out.println("jsonString = " + jsonString);
        }
}

订单金额无执行效果截图

2.7 ModelMapper  转换

转换器允许在将源映射到目标属性时进行自定义转换。ModelMapper 提供Converter转换接口实现源映射到目标属性时自定义转换。

示例代码片段

                        // 字符串转枚举
                        mapper.using((Converter<String, OrderSource>) context ->{
                            return OrderSource.getInstance(context.getSource()) ;
                        }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);

2.8 ModelMapper 提供者

ModelMapper 提供Provide接口返回源属性到模板属性映射值。

功能要求Order 类属性amount 为null, 设置OrderDTO 类属性amount  = 0

测试:

 public static void main(String[] args) {
            ModelMapper modelMapper = new ModelMapper();
            Order order = new Order();
            Customer customer = new Customer();
            Name name = new Name();
            name.setLastName("周");
            name.setFirstName("程宇");
            customer.setName(name);
            Address address = new Address();
            address.setCity("深圳");
            address.setStreet("盐田区梅沙街道");
            order.setCustomer(customer);
            order.setAddress(address);
            order.setOrderSource("1");

            OrderDTO orderDTO =modelMapper.typeMap(Order.class, OrderDTO.class)
                    .addMappings(mapper-> {
                        //  添加判断条件 + 添加自定义转换条件
                        mapper.when((Condition<Integer, String>) context -> {
                            if(context.getSource() != null && context.getSource()> 0){
                                return true;
                            }
                            return false;
                        }).using((Converter<Integer, String>) context ->{
                                return context.getSource() >=1000 ? "3":"2" ;
                        }).map(it-> it.getAmount(),OrderDTO::setPriority);
                        // 添加判空添加 + 添加默认值
                        mapper.when((Condition<Integer, ?>) condition ->{
                            if(condition.getSource() == null ||  condition.getSource() == 0){
                                return true;
                            }
                            return false;
                        }).using((Converter<Integer, String>) converter->{
                            return "1";
                        }).map(it-> it.getAmount(),OrderDTO::setPriority);
                        // 通过Provider 设置默认值
                        mapper.with((Provider<Integer>) provider ->{
                            return 0;
                        }).map(it-> it.getAmount(),OrderDTO::setAmount);

                        // 自定义属性转换
                        mapper.map(src -> src.getAddress().getStreet(), OrderDTO::setStreetTest);
                        mapper.map(src -> src.getAddress().getCity(), OrderDTO::setCityTest);
                        // 字符串转枚举
                        mapper.using((Converter<String, OrderSource>) context ->{
                            return OrderSource.getInstance(context.getSource()) ;
                        }).map(src -> src.getOrderSource(), OrderDTO::setOrderSource);
                    }).map(order);

            String jsonString = JSON.toJSONString(orderDTO);
            System.out.println("jsonString = " + jsonString);
        }

效果展示:

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6