Skip to content

ruoyi-vue-plus POJO转换

技术需求

在日常开发中通常有三种实体(模型),DO/BO/VO;

DO(Domain object):领域对象,一般对应于数据库实体,通常也PO、ENTITY

BO(business object):业务对象,一般包含相关字段效验或者业务逻辑效验等。

VO(view object):显示层对象,一般传递给前端使用

如果直接把数据库查询到的DO实体输出到前端,可能会有些包含一些冗余字段或者隐私字段。等于直接把数据库表结构暴露了。所以需要通过工具将DO转换成VO。

实现方法

1、可以用org.springframework.beans.BeanUtils.copyProperties(src,dest)方法

java
CategoryVo categoryVo = new CategoryVo();
BeanUtils.copyProperties(category,categoryVo);
System.out.println(categoryVo);

2、使用mapstruct 实体类映射框架,mapstruct 可以在VO定义的时候就制定映射类及字段关系。

3、MapstructPlus:Mapstruct 的增强工具,在 Mapstruct 的基础上,实现了自动生成 Mapper 接口的功能,并强化了部分功能,使 Java 类型转换更加便捷、优雅。ruoyi-vue-plus采用该框架。

java
//假设有两个类 UserDto 和 User,分别表示数据层对象和业务层对象

@Data
UserDto
public class UserDto {
    private String username;
    private int age;
    private boolean young;
}

@AutoMapper(target = UserDto.class)
@Data
User
public class User {
    private String username;
    private int age;
    private boolean young;
}
- 注意:使用@AutoMapper Mapstruct Plus 除了会生成 User -> UserDto 的转换接口,默认还会生成 UserDto -> User 的转换接口,而且只需要一方标注就可以了
    
// 转换
@SpringBootTest
class MapstructApplicationTests {

    @Autowired
    private Converter converter;

    @Test
    public void test01(){
        User user = new User();
        user.setUsername("jack");
        user.setAge(23);
        user.setYoung(false);
        UserDto userDto = converter.convert(user, UserDto.class);
        System.out.println(userDto);    // UserDto{username='jack', age=23, young=false}
        User newUser = converter.convert(userDto, User.class);
        System.out.println(newUser);    // User{username='jack', age=23, young=false}
    }
}
//---------------------
//UserDto(username=jack, age=23, young=false)
//User(username=jack, age=23, young=false)

框架封装

ruoyi-plus-vue 把DO与VO的转换封装在BaseMapperPlus中

以SysUserMapper为例,SysUserMapper继承了BaseMapperPlus,BaseMapperPlus继承了BaseMapper。实现了POJO转换等通用逻辑的封装

继承关系:

java
public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo>
public interface BaseMapperPlus<T, V> extends BaseMapper<T>

以ID查询为例:

java
/**
 * 根据 ID 查询
 */
default <C> C selectVoById(Serializable id, Class<C> voClass) {
    T obj = this.selectById(id);
    if (ObjectUtil.isNull(obj)) {
        return null;
    }
    return MapstructUtils.convert(obj, voClass);
}

MapstructUtils类

java
/**
 * Mapstruct 工具类
 * <p>参考文档:<a href="https://mapstruct.plus/introduction/quick-start.html">mapstruct-plus</a></p>
 *
 *
 * @author Michelle.Chung
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MapstructUtils {

    private final static Converter CONVERTER = SpringUtils.getBean(Converter.class);

    /**
     * 将 T 类型对象,转换为 desc 类型的对象并返回
     *
     * @param source 数据来源实体
     * @param desc   描述对象 转换后的对象
     * @return desc
     */
    public static <T, V> V convert(T source, Class<V> desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        return CONVERTER.convert(source, desc);
    }

    /**
     * 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象
     *
     * @param source 数据来源实体
     * @param desc   转换后的对象
     * @return desc
     */
    public static <T, V> V convert(T source, V desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        return CONVERTER.convert(source, desc);
    }

    /**
     * 将 T 类型的集合,转换为 desc 类型的集合并返回
     *
     * @param sourceList 数据来源实体列表
     * @param desc       描述对象 转换后的对象
     * @return desc
     */
    public static <T, V> List<V> convert(List<T> sourceList, Class<V> desc) {
        if (ObjectUtil.isNull(sourceList)) {
            return null;
        }
        if (CollUtil.isEmpty(sourceList)) {
            return CollUtil.newArrayList();
        }
        return CONVERTER.convert(sourceList, desc);
    }

    /**
     * 将 Map 转换为 beanClass 类型的集合并返回
     *
     * @param map       数据来源
     * @param beanClass bean类
     * @return bean对象
     */
    public static <T> T convert(Map<String, Object> map, Class<T> beanClass) {
        if (MapUtil.isEmpty(map)) {
            return null;
        }
        if (ObjectUtil.isNull(beanClass)) {
            return null;
        }
        return CONVERTER.convert(map, beanClass);
    }

}