Orika用在Do和Dto之前转换,即持久化层对应的实体对象与数据传输对象之间的映射。使用Orika可以自定义CustomMapper,实现二者转换。
Orika相同功能的还有Apache的BeanUtils,Spring的BeanUtils,Dozer等。
Orika使用
接下来通过一个小demo来记录下如何使用。
新建一个springboot的web项目。
maven导入依赖包
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.4.6</version>
</dependency>
Do和Dto
定义两个bean,用来转换。
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class A {
private String nameA;
private Integer ageA;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class B {
private String nameB;
private Integer ageB;
}
写CustomMapper
写转换方法,extens CustomMapper。
import com.bean.A;
import com.bean.B;
import ma.glasnost.orika.CustomMapper;
import ma.glasnost.orika.MappingContext;
import org.springframework.stereotype.Component;
@Component
public class AToB extends CustomMapper<A, B> {
@Override
public void mapAtoB(A a, B b, MappingContext context) {
b.setNameB(a.getNameA());
b.setAgeB(a.getAgeA());
}
}
controller层
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class TestController {
@Resource
private MapperFacade mapper;
@RequestMapping("/hello")
public String getTest(@RequestBody A a){
mapper.map(a,B.class);
System.out.println(a);
System.out.println(mapper.map(a,B.class));
return "hello";
}
}
配置文件
此时启动springboot时,controller层的mapper会为空,无法注入,应该加入自己写的Orika配置类才能让自动导入MapperFacade类。
此处也同时自定义了MapperFactoryBean 类。
package com.config;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OrikaConfig {
@Bean
@ConditionalOnMissingBean(MapperFactoryBean.class)
public MapperFactoryBean loadFactory() {
return new MapperFactoryBean();
}
@Bean
@ConditionalOnMissingBean(MapperFacade.class)
public MapperFacade loadMapperFacade(MapperFactory factory) {
return factory.getMapperFacade();
}
}
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.Mapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.Nullable;
public class MapperFactoryBean implements FactoryBean<MapperFactory>, ApplicationContextAware {
ApplicationContext applicationContext;
@Nullable
@Override
public MapperFactory getObject() throws Exception {
DefaultMapperFactory build = new DefaultMapperFactory.Builder().build();
for (CustomConverter converter : applicationContext.getBeansOfType(CustomConverter.class).values()) {
build.getConverterFactory().registerConverter(converter);
}
for (Mapper<?, ?> mapper : applicationContext.getBeansOfType(Mapper.class).values()) {
build.registerMapper(mapper);
}
for (ClassMapBuilder<?, ?> mapper : applicationContext.getBeansOfType(ClassMapBuilder.class).values()) {
build.registerClassMap(mapper);
}
return build;
}
@Nullable
@Override
public Class<?> getObjectType() {
return MapperFactory.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
启动类加注解导入配置类
import com.config.OrikaConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import({OrikaConfig.class})
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
注意:如果springboot启动后输入url报错404,很可能是目录层级不对,目录结构不符合要求。Controller包必须和AppApplication.java同级,因为@SpringBootApplication默认会去扫描同级目录或者子集目录下的所有类。
demo的目录结构如下:
结果
启动工程,postman发送post请求至本地,可以看到打印的结果,b已经正确赋值。
自定义的MapperFactoryBean把写的CustomMapper注册进去。
MapperFacade的map方法,其实现类MapperFacadeImpl,里面使用MappingStategy查找stategy,最后找到UserCustomMapperStategy,调用其map方法,最终调用我们自定义的CustomMapper中的mapA2B方法。