文章目录
- 前言
- 正文
- 一、项目代码
- 1.1 maven依赖
- 1.2 核心配置文件
- 1.3 时间工具类
- 1.4 实体类
- 1.5 转换对象的调用
- 二、MapperFacade API
前言
众所周知,在Java项目中经常会有用到各种对象属性复制的情况,以及从一个对象转换为另一个对象。
之前我们可能会使用以下工具:
BeanUtils.copyProperties(A, B);
MapStruct
对象映射
今天我们来一起看看另一种功能同样强大,性能也很高的工具!就是Orika MapperFacade
。
正文
在SpringBoot项目中,我们使用Orika MapperFacade时也是非常方便的。以下会用代码举例。
一、项目代码
项目环境是java1.8,使用了Springboot的2.x版本。
1.1 maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<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><groupId>org.feng</groupId><artifactId>mapper-facade-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>mapper-facade-demo</name><description>mapper-facade-demo</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.6</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.gitlab.haynes</groupId><artifactId>orika-spring-boot-starter</artifactId><version>1.26.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>org.feng.MapperFacadeDemoApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
1.2 核心配置文件
因为在转换java8的时间类(诸如LocalDateTime等)时,会有格式问题,所以增加了类转换器。
package org.feng.config;import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.converter.BidirectionalConverter;
import ma.glasnost.orika.converter.ConverterFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.Type;
import org.feng.util.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.time.LocalDateTime;/*** mapperFacade配置** @author feng*/
@Configuration
public class MapperFacadeConfig {@Beanpublic MapperFactory mapperFactory() {DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder()// 忽略映射空字段.mapNulls(false).build();ConverterFactory converterFactory = mapperFactory.getConverterFactory();// 注册时间转换器converterFactory.registerConverter(new LocalDateTimeStrConverter());return mapperFactory;}@Beanpublic MapperFacade mapperFacade(@Autowired MapperFactory mapperFactory) {return mapperFactory.getMapperFacade();}private static class LocalDateTimeStrConverter extends BidirectionalConverter<LocalDateTime, String> {@Overridepublic String convertTo(LocalDateTime localDateTime, Type<String> type, MappingContext mappingContext) {return TimeUtil.parse(localDateTime);}@Overridepublic LocalDateTime convertFrom(String str, Type<LocalDateTime> type, MappingContext mappingContext) {return TimeUtil.format(str);}}
}
1.3 时间工具类
package org.feng.util;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;/*** 时间工具类** @version v1.0* @author: fengjinsong* @date: 2024年01月18日 22时40分*/
public class TimeUtil {private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");public static String parse(LocalDateTime localDateTime) {if (localDateTime == null) {return "";}return DATE_TIME_FORMATTER.format(localDateTime);}public static LocalDateTime format(String dateTime) {if (dateTime == null) {return null;}return LocalDateTime.parse(dateTime, DATE_TIME_FORMATTER);}
}
1.4 实体类
为了简化文章篇幅,这里将用到的实体类放在了一起。
@Data
public class Order {private Long id;private String code;private String type;private String desc;private LocalDateTime createDateTime;
}@Data
public class User {private Long id;private String userName;private String email;private LocalDateTime birthday;private LocalDate registerDay;private List<Order> orders;
}@Data
public class OrderVO {private Long id;private String code;private String type;private String desc;private String createDateTime;
}@Data
public class UserVO {private Long id;private String name;private String email;private String birthday;private LocalDate registerDay;private List<OrderVO> orders;
}
1.5 转换对象的调用
为了方便,直接在启动类中进行操作。在springboot项目启动后,会执行对应的转换代码。
package org.feng;import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.BoundMapperFacade;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import org.feng.entity.Order;
import org.feng.entity.User;
import org.feng.vo.UserVO;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;@Slf4j
@SpringBootApplication
public class MapperFacadeDemoApplication implements CommandLineRunner {@Resourceprivate MapperFactory mapperFactory;public static void main(String[] args) {SpringApplication.run(MapperFacadeDemoApplication.class, args);}@Overridepublic void run(String... args) throws Exception {// 存在不同字段名映射,需要增加映射规则;字段名完全相同时,可以直接获取mapperFacade实例进行转换mapperFactory.classMap(User.class, UserVO.class).field("userName", "name").byDefault().register();BoundMapperFacade<User, UserVO> mapperFacade = mapperFactory.getMapperFacade(User.class, UserVO.class);User user = new User();user.setUserName("玑而");user.setId(2L);user.setBirthday(LocalDateTime.now());user.setRegisterDay(LocalDate.of(2023,12,21));List<Order> orders = new ArrayList<>();Order order = new Order();order.setCreateDateTime(LocalDateTime.now());order.setId(21L);order.setCode("323d2");orders.add(order);user.setOrders(orders);UserVO userVO = mapperFacade.map(user);log.info(userVO.toString());}
}
控制台输出:
UserVO(id=2, name=玑而, email=null, birthday=2024-01-31 11:47:50, registerDay=2023-12-21, orders=[OrderVO(id=21, code=323d2, type=null, desc=null, createDateTime=2024-01-31 11:47:50)])
二、MapperFacade API
- map(…) 普通对象转换
- mapAsArray(…) 数组转换为数组
- mapAsCollection(…) 集合转换为集合
- mapAsList(…) 转换list
- mapAsSet(…) 转换set
- mapAsMap(…) 转换map
- newObject(…) 创建一个新对象
另外需要注意一下,MapperFacade本身是使用递归的方式去做的。
也就是说如果你要转换的对象内嵌套了其他对象,也是可以复制的。