高级示例:用户-角色-菜单(权限),三者之间分别都是多对多的关系,查询用户的时候,期望查询用户下所有的角色与权限。

1、构建实体对象

  1. @Data
  2. @Table(comment = "菜单信息")
  3. public class Menu {
  4. @ColumnComment("主键")
  5. private String id;
  6. @ColumnComment("菜单名")
  7. private String name;
  8. // 省略其他信息
  9. .......
  10. }
  1. @Data
  2. @Table(comment = "角色信息")
  3. public class Role {
  4. @ColumnComment("主键")
  5. private String id;
  6. @ColumnComment("角色名")
  7. private String name;
  8. // @BindEntityByMid是可以实现通过中间表关联数据,主要属性conditions,midEntity指定中间表实体(该实体必须有对应的MP的Mapper),
  9. //
  10. @BindEntityByMid(conditions = @MidCondition(
  11. midEntity = RoleMenu.class, selfMidField = "roleId", joinMidField = "menuId"
  12. ), orderBy = @JoinOrderBy(field = "name"))
  13. private List<Menu> menus;
  14. // 省略其他信息
  15. .......
  16. }
  1. @Data
  2. @Table(comment = "用户信息")
  3. public class User {
  4. @ColumnComment("主键")
  5. private String id;
  6. @ColumnComment("用户名")
  7. private String username;
  8. @ColumnComment("密码")
  9. private String password;
  10. // 通过中间表关联所有相关的角色。
  11. // 通过中间表的形式需要使用@Bind*ByMid
  12. @BindEntityByMid(conditions = @MidCondition(
  13. midEntity = UserRole.class, selfMidField = "userId", joinMidField = "roleId"
  14. ), orderBy = @JoinOrderBy(field = "name"))
  15. private List<Role> roles;
  16. // 省略其他信息
  17. .......
  18. }
  1. @Data
  2. @Table(comment = "角色-菜单关联关系")
  3. public class RoleMenu {
  4. @ColumnComment("主键")
  5. private String id;
  6. @ColumnComment("角色id")
  7. private String roleId;
  8. @ColumnComment("菜单id")
  9. private String menuId;
  10. }
  1. @Data
  2. @Table(comment = "用户-角色关联关系")
  3. public class UserRole {
  4. @ColumnComment("主键")
  5. private String id;
  6. @ColumnComment("用户id")
  7. private String userId;
  8. @ColumnComment("角色id")
  9. private String roleId;
  10. }

2、数据查询

  1. /**
  2. * 用户服务
  3. */
  4. @Slf4j
  5. @Service
  6. public class UserService {
  7. @Resource
  8. private UserRepository userRepository;
  9. /**
  10. * 根据用户的名字模糊查询所有用户的详细信息
  11. */
  12. @Transactional(readOnly = true)
  13. public List<UserDetailWithRoleDto> searchUserByName(String name) {
  14. // MP的lambda查询方式
  15. List<User> userList = userRepository.lambdaQuery()
  16. .eq(name != null, User::getUsername, name)
  17. .list();
  18. // 关键步骤,指定关联角色数据。如果你打开sql打印,会看到3条sql语句,第一条根据id去User表查询user信息,第二条根据userId去UserRule中间表查询所有的ruleId,第三条sql根据ruleId集合去Rule表查询全部的权限
  19. Binder.bindOn(userList, User::getRoles);
  20. // Deeper为一个深度遍历工具,可以深入到对象的多层属性内部,从而获取全局上该层级的所有对象同一属性
  21. Binder.bindOn(Deeper.with(userList).inList(User::getRoles), Role::getMenus);
  22. return UserMapping.MAPPER.toDto5(userList);
  23. }
  24. /**
  25. * 根据用户的名字模糊查询所有用户的详细信息,等价于上一个查询方式
  26. */
  27. @Transactional(readOnly = true)
  28. public List<UserDetailWithRoleDto> searchUserByName2(String name) {
  29. // 本框架拓展的lambda查询器lambdaQueryPlus,增加了bindOne、bindList、bindPage
  30. // 显然这是一种更加简便的查询方式,但是如果存在多级深度的关联关系,此种方法就不适用了,还需要借助Binder
  31. List<User> userList = userRepository.lambdaQueryPlus()
  32. .eq(name != null, User::getUsername, name)
  33. // 用法一、指定属性关联,只关联身份证号这个字段。
  34. .bindList(User::getRoles);
  35. // 用法二、全关联。
  36. // .bindList();
  37. // Deeper为一个深度遍历工具,可以深入到对象的多层属性内部,从而获取全局上该层级的所有对象同一属性
  38. Binder.bindOn(Deeper.with(userList).inList(User::getRoles), Role::getMenus);
  39. return UserMapping.MAPPER.toDto5(userList);
  40. }
  41. }