java springboot中,PO、BO、VO等转换工具

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限制边界,未完全测试,有可能有问题。望大佬指教!!!

### JavaVOBO、DTO、PO转换方法 在Java开发中,为了保持不同层次间的解耦合以及数据的安全性和一致性,通常会使用不同的对象模型来表示同一逻辑实体的不同视图。这些对象包括VO(View Object)、BO(Business Object)、DTO(Data Transfer Object)和PO(Persistent Object)。下面将介绍如何在这几种对象之间进行转换。 #### 使用 MapStruct 实现自动映射 MapStruct 是一种用于简化类间属性复制工作的框架,可以减少手动编写繁琐的转换代码。通过定义接口并标注特定注解即可实现高效的双向映射功能[^1]。 ```java @Mapper(componentModel = "spring") public interface EntityDtoMapper { UserBo userPoToUserBo(UserPo po); UserDto userBoToUserDto(UserBo bo); } ``` 此段代码展示了从`UserPo`(持久化对象)到`UserBo`(业务对象),再到`UserDto`(传输对象)的过程。借助于MapStruct自动生成具体的实现类完成实际的对象转换工作。 对于VO(视图对象), 如果前端请求或响应需要特殊格式的数据,则可以在控制器层进一步处理: ```java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public ResponseEntity<UserVo> getUser(@PathVariable Long id){ UserDto dto = userService.getUserById(id); // 假设这里有一个dtoToVo的方法来进行最终转换 return new ResponseEntity<>(dtoToVo(dto), HttpStatus.OK); } } private static UserVo dtoToVo(UserDto dto){ UserVo vo = new UserVo(); BeanUtils.copyProperties(dto,vo); // 可能还需要额外设置一些只读字段或者其他不适合放在DTO中的信息 return vo; } ``` 上述例子说明了当接收到HTTP GET请求时,先调用服务获取DTO实例,之后将其转化为适合前端使用的VO实例返回给客户端[^2]。 另外值得注意的是,在某些情况下可以直接利用DTO作为VO传递给前端而不需要单独创建VO类,尤其是在两者结构非常相似的情况下这样做能够有效降低系统的复杂度[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值