一、Orika背景介紹
Orika是java Bean映射框架,可以實現從一個對象遞歸拷貝數據至另一個對象。在開發多層應用程序中非常有用。在這些層之間交換數據時,通常為了適應不同API需要轉換一個實例至另一個實例。
有很多方法可以實現:硬代碼拷貝或Dozer實現bean映射等。總之,需要簡化不同層對象之間映射過程。
Orika使用字節碼生成器創建開銷最小的快速映射,比其他基於反射方式實現(如,Dozer)更快。之前使用Bean Copy 性能非常慢,發現在這個領域業界還是有很多新秀的。 Orika 應該就算一個比較好的吧。
二、優勢
1. 性能
大概是Dozer的8-10 倍, 這個上面的已經做了描述
2. 內存消耗
大概是Dozer內存消耗的一半多點。 為什么做到這點的還沒想清楚, 估計是因為運行期不需要維護復雜的Mapping 關系。 不需要大量的Mapping 關系查找以及需要的對這些查找優化所消耗的空間。
3. 簡單
Orika的代碼短小精悍, 而且可讀性非常強, Dozer如果要加減一個功能, 不才完全沒有信心, Orika 我還是可以偶爾在Orika里面打幾個醬油的。
三、基礎使用
- Maven項目依賴包:POM文件直接依賴進去即可。
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.4.6</version>
</dependency>
- 創建兩個Bean對象,用於復制使用。
UserVo對象
@Data //Set GET方法 @Accessors(chain = true) public class UserVo { private String id; private String name; }
User對象
@Data @Accessors(chain = true) public class User { private String id; private String name; }
- 使用場景(如果對象中屬性太多,普通邏輯處理代碼太多)
- A對象復制到B對象(對象復制)
//業務場景,將A對象復制B對象中 //1.普通邏輯處理 User A = new User().setId("123").setName("1231"); UserVo B = new UserVo().setId(A.getId()).setName(A.getName()); System.out.println("普通方式將A對象復制B對象中:"+B); //使用orika復制工具將A復制到B對象中 MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); UserVo map = mapperFactory.getMapperFacade().map(A, UserVo.class); System.out.println("orika復制對象:"+map);
- 由上得出控制台輸出如下:
普通方式將A對象復制B對象中:UserVo(id=123, name=1231) orika復制對象:UserVo(id=123, name=1231)
2.A集合復制到B集合(集合復制)
//1.普通邏輯處 //A對象 List<User> A = Arrays.asList(new User().setId("123").setName("張三")); //B對象 List<UserVo> B = new ArrayList<>(); //將A集合數據復制到B集合中 A.forEach(x->{ B.add( new UserVo().setId(x.getId()).setName(x.getName())); }); System.out.println("將A集合中數據set到B集合中數據打印"); //使用orika復制工具將A集合復制到B集合中 MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); List<UserVo> userVo = mapperFactory.getMapperFacade().mapAsList mapperFactory.getMapperFacade().mapAsList(A, UserVo.class); System.out.println("orika直接復制對象集合打印結果:"+userVo);
- 由上得出控制台輸出如下:
`將A集合中數據set到B集合中數據打印:[UserVo(id=123, name=張三)]`
`orika直接復制對象集合打印結果:[UserVo(id=123, name=張三)]`
- 到此為止您已經算入門了,以上是Orika的基礎使用,由此發現如果對象中屬性如果20個,那么用普通的邏輯處理需要20個set過去,如果用Orika兩行代碼搞定。話不多說關鍵步驟總結一波(關鍵必須牢記):
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.getMapperFacade().map(操作對象) mapperFactory.getMapperFacade().mapAsList(操作集合對象)
四、高級使用方法
- 創建兩個Bean對象,用於復制使用。
UserVo對象
@Data //Set GET方法 @Accessors(chain = true) public class UserVo { private String id; private String userName; private int ageOne; }
User對象
@Data @Accessors(chain = true) public class User { private String id; private String name; private int age; }
- 使用場景(對象A與對象B中屬性不一致時,如果對象中屬性太多,普通邏輯處理代碼太多)
1.A對象復制到B對象,對象中屬性不一樣時
//業務場景,將A對象復制B對象中,A對象中的字段與B對象中的字段不一致 //1.普通邏輯處理 User A = new User().setId("123").setName("張三").setAge(20); UserVo B = new UserVo().setId(A.getId()).setUserName(A.getName()).setAgeOne(A.getAge()); System.out.println("普通方式將A對象處理B對象中:"+B);. //使用orika復制工具將A復制到B對象中 MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(User.class, UserVo.class) .field("name", "userName") .field("age", "ageOne") .byDefault().register(); UserVo userVo = mapperFactory.getMapperFacade().map(A, UserVo.class); System.out.println("orika復制對象:"+userVo);
- 由上得出控制台輸出如下:
`普通方式將A對象處理B對象中:UserVo(id=123, userName=張三, ageOne=20)`
`orika復制對象:UserVo(id=123, userName=張三, ageOne=20)`
2.A集合對象復制到B集合對象,對象中屬性不一樣時
//1.普通邏輯處里A對象中與B對象字段不一致處理 //A對象 List<User> A = Arrays.asList(new User().setId("123").setName("張三").setAge(20)); //B對象 List<UserVo> B = new ArrayList<>(); //將A集合數據復制到B集合中 A.forEach(x->{ B.add(new UserVo().setId(x.getId()).setUserName(x.getName()).setAgeOne(x.getAge())); }); System.out.println("將A集合中數據set到B集合中數據打印"+B); //使用orika復制工具將A集合復制到B集合中 MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(User.class, UserVo.class) .field("name", "userName") .field("age", "ageOne") .byDefault().register(); List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(A, UserVo.class); System.out.println("orika復制對象:"+userVos);
- 由上得出控制台輸出如下:
`將A集合中數據set到B集合中數據打印[UserVo(id=123, userName=張三, ageOne=20)]`
`orika復制對象:[UserVo(id=123, userName=張三, ageOne=20)]`
- 話不多說關鍵步驟總結一波(關鍵必須牢記):
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(User.class, UserVo.class) .field("name", "userName") .field("age", "ageOne") .byDefault().register(); //集合復制--使用mapAsList List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(A, UserVo.class); //對象復制--使用map UserVo userVos = mapperFactory.getMapperFacade().map(A, UserVo.class);
五、總結工具類
/** * 映射工具類 */ public enum MapperUtils { INSTANCE; /** * 默認字段工廠 */ private static final MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build(); /** * 默認字段實例 */ private static final MapperFacade MAPPER_FACADE = MAPPER_FACTORY.getMapperFacade(); /** * 默認字段實例集合 */ private static Map<String, MapperFacade> CACHE_MAPPER_FACADE_MAP = new ConcurrentHashMap<>(); /** * 映射實體(默認字段) * * @param toClass 映射類對象 * @param data 數據(對象) * @return 映射類對象 */ public <E, T> E map(Class<E> toClass, T data) { return MAPPER_FACADE.map(data, toClass); } /** * 映射實體(自定義配置) * * @param toClass 映射類對象 * @param data 數據(對象) * @param configMap 自定義配置 * @return 映射類對象 */ public <E, T> E map(Class<E> toClass, T data, Map<String, String> configMap) { MapperFacade mapperFacade = this.getMapperFacade(toClass, data.getClass(), configMap); return mapperFacade.map(data, toClass); } /** * 映射集合(默認字段) * * @param toClass 映射類對象 * @param data 數據(集合) * @return 映射類對象 */ public <E, T> List<E> mapAsList(Class<E> toClass, Collection<T> data) { return MAPPER_FACADE.mapAsList(data, toClass); } /** * 映射集合(自定義配置) * * @param toClass 映射類 * @param data 數據(集合) * @param configMap 自定義配置 * @return 映射類對象 */ /* public <E, T> List<E> mapAsList(Class<E> toClass, Collection<T> data, Map<String, String> configMap) { T t = data.stream().findFirst().orElseThrow(() -> new ResourceNotExistException("映射集合,數據集合為空")); MapperFacade mapperFacade = this.getMapperFacade(toClass, t.getClass(), configMap); return mapperFacade.mapAsList(data, toClass); }*/ /** * 獲取自定義映射 * * @param toClass 映射類 * @param dataClass 數據映射類 * @param configMap 自定義配置 * @return 映射類對象 */ private <E, T> MapperFacade getMapperFacade(Class<E> toClass, Class<T> dataClass, Map<String, String> configMap) { String mapKey = dataClass.getCanonicalName() + "_" + toClass.getCanonicalName(); MapperFacade mapperFacade = CACHE_MAPPER_FACADE_MAP.get(mapKey); if (Objects.isNull(mapperFacade)) { MapperFactory factory = new DefaultMapperFactory.Builder().build(); ClassMapBuilder classMapBuilder = factory.classMap(dataClass, toClass); configMap.forEach(classMapBuilder::field); classMapBuilder.byDefault().register(); mapperFacade = factory.getMapperFacade(); CACHE_MAPPER_FACADE_MAP.put(mapKey, mapperFacade); } return mapperFacade; } }
1.orika底層實現原理:(后續加上)
2.如果有任何不懂的地方可以咨詢我,隨時歡迎互相幫助。
3.以上完整代碼加群(群文件):422167709
