java后端代码中,经常会涉及到各种属性基本相同对象的转换过程,常见的如PO、BO、VO等。通常,后端开发规范中,会要求PO对象只能应用在DAO层,BO对象应用在service层,VO对象应用在web层;
为了方便代码的管理以及增加代码的可读性,我们需要一个统一的Convert工具类;为了应对不同业务对象,以及Convert工具类的方法统一,我们定义一个泛型接口;
1.泛型接口,用于不同的业务对象转换
/**
* @Author win
* @Description
* @Date 2023/7/10 13:44
*/
public interface Converter<P,B,V> {
B voToBo(V v) throws Exception;
default List<B> voListToBoList(List<V> voList) throws Exception{
List<B> boList = new ArrayList<>();
if (!CollectionUtils.isEmpty(voList)) {
for (V v : voList) {
boList.add(voToBo(v));
}
}
return boList;
}
V boToVo(B b) throws Exception;
default List<V> boListToVoList(List<B> boList) throws Exception{
List<V> voList = new ArrayList<>();
if (!CollectionUtils.isEmpty(boList)) {
for (B b : boList) {
voList.add(boToVo(b));
}
}
return voList;
}
P boToPo(B b) throws Exception;
default List<P> boListToPoList(List<B> boList) throws Exception{
List<P> poList = new ArrayList<>();
if (!CollectionUtils.isEmpty(boList)) {
for (B b : boList) {
poList.add(boToPo(b));
}
}
return poList;
}
B poToBo(P p) throws Exception;
default List<B> poListToBoList(List<P> poList) throws Exception{
List<B> boList = new ArrayList<>();
if (!CollectionUtils.isEmpty(poList)) {
for (P p : poList) {
boList.add(poToBo(p));
}
}
return boList;
}
}
A:Converter接口中,使用了三个泛型类,P、B、V,分别代表PO、BO、VO的类;
B:XXXConverter工具类实现Converter接口,重写接口中的voToBo等方法;
C:利用java8中,接口中使用default 关键字修饰方法,把默认的集合转换方法先定义好,XXXConverter不需要重写这一部分代码,可以直接调用。
2.定义UserConverter工具类,实现Converter接口
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @Author win
* @Description
* @Date 2023/7/10 13:55
*/
@Component("userConverer")
public class UserConverter implements Converter<UserPO, UserBO, UserVO>{
@Override
public UserBO voToBo(UserVO vo) throws Exception {
UserBO bo = new UserBO ();
if (vo != null) {
bo.setUserName(vo.getUserName());
...
//其他属性的赋值
//或者直接使用spring bean中的 BeanUtils.copyProperties(vo , bo);
}
return bo;
}
@Override
public UserVO boToVo(UserBO bo) throws Exception {
UserVO vo = new UserVO ();
if (bo != null) {
//属性的赋值
}
return vo;
}
@Override
public UserPO boToPo(UserBO bo) throws Exception {
UserPO po = new UserPO();
if (bo != null) {
//属性的赋值
}
return po;
}
@Override
public UserBO poToBo(UserPO po) throws Exception {
UserBO bo = new UserBO ();
if (po != null) {
//属性的赋值
}
return bo;
}
}
以上,就能UserConverter 就能将PO、BO、VO互相转换;在类上,使用@Component注解,将UserConverter 对象放到springBean容器中管理;
3.方法调用
在view层或者是service层就能通过 @Autowired或者 @Resource自动注入XXXConverter 为属性。
下面以Controller层为例:
@RestController
@RequestMapping(value = "/v1/user", produces = "application/json;charset=UTF-8")
public class UserController {
@Resource
private UserConverter userConverter;
@Resource
private UserService userservice;
@RequestMapping(value = "/add_user", method = RequestMethod.POST)
public Result addUser(@RequestBody UserVO userVO) {
Result result = new Result();
//vo转换成bo
UserBO bo = userConverter.voToBo(userVO);
//调用业务层
userservice.add(bo);
return result;
}
}
当我们的服务中,存在很多的Converter实体类时,在同一个Controller或者Service中,需要注入多个类似于UserConverter 的属性时,会让代码看起来比较的臃肿。
4.ConverterFactory泛型工厂,实现ApplicationContextAware接口
当某一个Controller或者Service需要多个Converter 时,用Factory的来管理这些Converter 对象,只要调用Factory中的某个方法,就可以获得某个指定的Converter 工具类;
使用泛型边界设置,限制Factory只允许获取Converter实体类对象;
/**
* 说明: 将spring bean对象转换成静态变量;当前类只作用于Converter接口的子类
*
* @Author: win
* @Description:
* @Date 2023/4/21 15:43
*/
@Component
public class ConverterFactory<T extends Converter> implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 方法说明: 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
*
* @param applicationContext
* @return void
* @date 2023/5/31 18:16
* @author win
*/
public void setApplicationContext(ApplicationContext applicationContext) {
ConverterFactory.applicationContext = applicationContext;
}
/**
* 方法说明: 取得存储在静态变量中的ApplicationContext.
*
* @param
* @return org.springframework.context.ApplicationContext
* @date 2023/5/31 18:15
* @author win
*/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/**
* 方法说明: 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
*
* @param name 可以通过枚举,定义beanName;在UserConverter中的@Component("userConverer"),userConverer即是bean的名字;但是这个名字有可能会重复,
* @return T
* @date 2023/5/31 18:14
* @author win
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
/**
* 方法说明: 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型;如果有多个Bean符合Class, 取出第一个.
*
* @param clazz
* @return T
* @date 2023/5/31 18:15
* @author win
*/
@SuppressWarnings("unchecked")
public static <T extends Converter> T getBean(Class<T> clazz) {
checkApplicationContext();
@SuppressWarnings("rawtypes")
Map beanMaps = applicationContext.getBeansOfType(clazz);
if (beanMaps != null && !beanMaps.isEmpty()) {
return (T) beanMaps.values().iterator().next();
} else {
return null;
}
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicationContext未注入");
}
}
}
此时,修改UserController中的调用方法
@RestController
@RequestMapping(value = "/v1/user", produces = "application/json;charset=UTF-8")
public class UserController {
@Resource
private UserService userservice;
@RequestMapping(value = "/add_user", method = RequestMethod.POST)
public Result addUser(@RequestBody UserVO userVO) {
Result result = new Result();
//vo转换成bo
UserBO bo = ConverterFactory.getBean(UserConverter.class).voToBo(userVO)
//调用业务层
userservice.add(bo);
return result;
}
}
至此,在代码中都可以使用 ConverterFactory.getBean(XXXConverter.class)调用XXXConverter中的所有方法,也包括Converter接口中的voListToBoList(voList)等集合转换方法。
注:ConverterFactory中限制用T extends Converter限制边界,未完全测试,有可能有问题。望大佬指教!!!