# scaffold 项目之 POJO 对象转换和翻译
# 简介
POJO(Plain Old Java Object,普通老式 Java 对象)通常指的是简单的 Java 对象,它们通常用于封装数据,没有继承特殊的类或实现特殊的接口。尽管 POJO 对象在 Java 应用中非常常见,但在某些情况下,POJO 对象需要进行转换和翻译,原因如下:
- 数据模型匹配:
- 不同层级或组件之间可能使用不同的数据模型。例如,数据库层可能使用 Entity 对象,服务层可能使用 DTO(Data Transfer Object),而前端可能需要 VO(View Object)。POJO 对象转换确保这些不同模型之间的数据一致性和正确性。
- 数据安全和隐私:
- POJO 对象可能包含敏感信息,不适合直接暴露给客户端或其他系统。通过转换和翻译,可以过滤掉敏感字段,保护数据安全。
- 业务逻辑封装:
- POJO 对象转换可以在不同层之间传递数据时,封装业务逻辑,如数据验证、格式化和计算字段值。
- 性能优化:
- 通过转换,可以减少不必要的数据传输,只传递所需要的。
# 对象转换
对象转换是指 A 类型对象转成 B 类型对象,例如我有一个 UserDO
对象,需要转成 UserVO
类型或者 UserDTO
类型对象。
关于上述类型说明:
- DO:与数据库表结构紧密相关,用于数据库操作。
- VO:用于前端展示,根据用户界面的需求定制数据结构。
- DTO:用于系统间的数据传输,可以跨越不同的服务和系统。
市面上有很多对象类型转换工具, MapStruct、Dozer、BeanUtil、BeanCopier 等等,本项目使用 MapStruct 和 BeanUtil
# MapStruct
项目使用 MapStruct 来实现对象之间的转换,定义在规范在每个模块下有一个 convert
包, 用于所有 DO 的转换, 每个 DO 对应一个转换类,例如:
可以看到下面的代码在
com.tz.scaffold.module.system.convert
包下, 下面提供的方法就是把DO
转成VO
package com.tz.scaffold.module.system.convert.auth; | |
/** | |
* <p> Project: scaffold - AuthConvert </p> | |
* | |
* Auth Convert | |
* @author Tz | |
* @date 2024/01/09 23:45 | |
* @version 1.0.0 | |
* @since 1.0.0 | |
*/ | |
@Mapper | |
public interface AuthConvert { | |
AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); | |
AuthLoginRespVO convert(OAuth2AccessTokenDO bean); | |
// 自己定义的转换 | |
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { | |
return AuthPermissionInfoRespVO.builder() | |
.user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build()) | |
.roles(convertSet(roleList, RoleDO::getCode)) | |
// 权限标识信息 | |
.permissions(convertSet(menuList, MenuDO::getPermission)) | |
// 菜单树 | |
.menus(buildMenuTree(menuList)) | |
.build(); | |
} | |
//MapStruct 会自己帮我们实现转换的逻辑 | |
AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu); | |
} |
# 数据翻译
数据翻译,指的是将 A 类型对象的某个字段,“翻译” 成 B 类型对象的某个字段。例如说,我们有一个 UserVO 的 deptId
字段,读取对应 DeptDO 的 name
字段,最终设置到 UserVO 的 deptName
字段。
有两种处理方法:
- 在查询的时候联表查询
- 数据库多次单表查询,让后在 java 代码中进行数据拼接。
一般采用第二张方式,减少数据库压力,列如
public CommonResult<UserRespVO> getUser(@RequestParam("id") Long id) { | |
AdminUserDO user = userService.getUser(id); | |
// 获得部门数据 | |
DeptDO dept = deptService.getDept(user.getDeptId()); | |
return success(UserConvert.INSTANCE.convert(user).setDept(UserConvert.INSTANCE.convert(dept))); | |
} |
@Schema(description = "管理后台 - 用户分页时的信息 Response VO,相比用户基本信息来说,会多部门信息") | |
@Data | |
@NoArgsConstructor | |
@AllArgsConstructor | |
@EqualsAndHashCode(callSuper = true) | |
public class UserPageItemRespVO extends UserRespVO { | |
/** | |
* 所在部门 | |
*/ | |
private Dept dept; | |
@Schema(description = "部门") | |
@Data | |
public static class Dept { | |
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
private Long id; | |
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") | |
private String name; | |
} | |
} |
如果嫌这种方式麻烦可以采用
easy-trans
框架来实现数据翻译,只需要加注解使用,方便简单。
# 扩展
后续切换为使用 easy-trans