目录
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);
}
效果展示: