高级示例:用户-角色-菜单(权限),三者之间分别都是多对多的关系,查询用户的时候,期望查询用户下所有的角色与权限。
1、构建实体对象
@Data
@Table(comment = "菜单信息")
public class Menu {
@ColumnComment("主键")
private String id;
@ColumnComment("菜单名")
private String name;
// 省略其他信息
.......
}
@Data
@Table(comment = "角色信息")
public class Role {
@ColumnComment("主键")
private String id;
@ColumnComment("角色名")
private String name;
// @BindEntityByMid是可以实现通过中间表关联数据,主要属性conditions,midEntity指定中间表实体(该实体必须有对应的MP的Mapper),
//
@BindEntityByMid(conditions = @MidCondition(
midEntity = RoleMenu.class, selfMidField = "roleId", joinMidField = "menuId"
), orderBy = @JoinOrderBy(field = "name"))
private List<Menu> menus;
// 省略其他信息
.......
}
@Data
@Table(comment = "用户信息")
public class User {
@ColumnComment("主键")
private String id;
@ColumnComment("用户名")
private String username;
@ColumnComment("密码")
private String password;
// 通过中间表关联所有相关的角色。
// 通过中间表的形式需要使用@Bind*ByMid
@BindEntityByMid(conditions = @MidCondition(
midEntity = UserRole.class, selfMidField = "userId", joinMidField = "roleId"
), orderBy = @JoinOrderBy(field = "name"))
private List<Role> roles;
// 省略其他信息
.......
}
@Data
@Table(comment = "角色-菜单关联关系")
public class RoleMenu {
@ColumnComment("主键")
private String id;
@ColumnComment("角色id")
private String roleId;
@ColumnComment("菜单id")
private String menuId;
}
@Data
@Table(comment = "用户-角色关联关系")
public class UserRole {
@ColumnComment("主键")
private String id;
@ColumnComment("用户id")
private String userId;
@ColumnComment("角色id")
private String roleId;
}
2、数据查询
/**
* 用户服务
*/
@Slf4j
@Service
public class UserService {
@Resource
private UserRepository userRepository;
/**
* 根据用户的名字模糊查询所有用户的详细信息
*/
@Transactional(readOnly = true)
public List<UserDetailWithRoleDto> searchUserByName(String name) {
// MP的lambda查询方式
List<User> userList = userRepository.lambdaQuery()
.eq(name != null, User::getUsername, name)
.list();
// 关键步骤,指定关联角色数据。如果你打开sql打印,会看到3条sql语句,第一条根据id去User表查询user信息,第二条根据userId去UserRule中间表查询所有的ruleId,第三条sql根据ruleId集合去Rule表查询全部的权限
Binder.bindOn(userList, User::getRoles);
// Deeper为一个深度遍历工具,可以深入到对象的多层属性内部,从而获取全局上该层级的所有对象同一属性
Binder.bindOn(Deeper.with(userList).inList(User::getRoles), Role::getMenus);
return UserMapping.MAPPER.toDto5(userList);
}
/**
* 根据用户的名字模糊查询所有用户的详细信息,等价于上一个查询方式
*/
@Transactional(readOnly = true)
public List<UserDetailWithRoleDto> searchUserByName2(String name) {
// 本框架拓展的lambda查询器lambdaQueryPlus,增加了bindOne、bindList、bindPage
// 显然这是一种更加简便的查询方式,但是如果存在多级深度的关联关系,此种方法就不适用了,还需要借助Binder
List<User> userList = userRepository.lambdaQueryPlus()
.eq(name != null, User::getUsername, name)
// 用法一、指定属性关联,只关联身份证号这个字段。
.bindList(User::getRoles);
// 用法二、全关联。
// .bindList();
// Deeper为一个深度遍历工具,可以深入到对象的多层属性内部,从而获取全局上该层级的所有对象同一属性
Binder.bindOn(Deeper.with(userList).inList(User::getRoles), Role::getMenus);
return UserMapping.MAPPER.toDto5(userList);
}
}