1.声明
当前内容用于本人复习和使用mybatis和使用mybatisplus.以及在开发权限demo中的过程中出现的部分问题的思考和实现
模型
- 用户具有基本信息(age,name…),并且具有角色(多个)
- 一个角色具有多个权限
所以存在基本的表为:用户表,权限表,角色表,用户角色表,角色权限表(通过角色控制权限)
关于一个角色可以直接分配权限的情况不再本内容的考虑范围之内(如果存在就必须有用户权限表)
2.创建对应的表
3.分析我们在前台需要的数据内容
所以我们在用户类中直接添加List<Role>
就可以了,所以当前的mapper.xml中必须使用<collection/>
标签,但是一个<collection/>
标签中必须再包含一个<collection/>
标签(这里存在一个坑,无法实现嵌套的sql解析MyBatis不支持
)
4.创建各种需要的实体类
使用代码生成器生成的实体类,然后加工后的实体类如下:
权限表
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Permiss implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
}
角色表
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private List<Permiss> permisses;// 一个角色对应多个权限
}
角色权限表
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class RolePermissRelation implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer rid;
private Integer pid;
}
用户表
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private String pwd;
private Integer age;
private String adress;
@TableField("createTime")
private LocalDateTime createTime;
private List<Role> roles;//一个用户可以存在多个角色,角色中具有权限
/*
* private Set<Permiss> otherPermiss; // 除了角色之外的权限
*/
}
用户角色表
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class UserRoleRelation implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer uid;
private Integer rid;
}
创建controller层
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserMapper userMapper;
@Autowired
PermissMapper permissMapper;
@RequestMapping("/findAll")
public ResponseEntity<?> findAll(){
List<User> users = userMapper.findAllUsers();
return ResponseEntity.ok(users);
}
}
5.方案一,使用嵌套select方式
这里解决查询User类的Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hy.springboot.mybatisplus.rolepermiss.mapper.UserMapper">
<resultMap type="user" id="tableUser">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
<result column="age" property="age"/>
<result column="address" property="address"/>
<result column="createTime" property="createTime"/>
<collection property="roles" javaType="ArrayList" column="rid" select="selectRoleById" ofType="Role">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="permisses" javaType="ArrayList" column="rid" select="selectPermissById" ofType="Permiss">
<id column="id" property="id"/>
<result column="name" property="name"/>
</collection>
</collection>
</resultMap>
<!-- 通过角色id查询角色和权限编号 -->
<select id="selectRoleById" resultType="role">
SELECT *,id rid FROM role
WHERE id = #{rid}
</select>
<!-- 通过权限编号查询权限 -->
<select id="selectPermissById" resultType="permiss">
SELECT p.`id`,p.`name` FROM
role_permiss_relation rpr
INNER JOIN permiss p ON p.`id`=rpr.`pid`
INNER JOIN role r ON r.`id`=rpr.`rid`
WHERE r.`id`=#{rid}
</select>
<select id="findAllUsers" resultMap="tableUser">
SELECT u.*,ur.`id` AS rid
FROM `user` AS u
LEFT JOIN user_role_relation ur ON ur.`uid`=u.`id`
</select>
</mapper>
我们再Mapper层创建了一个findAllUsers的方法,不传递任何参数
public interface UserMapper extends BaseMapper<User> {
List<User> findAllUsers();//名称不能覆盖父类的方法,否则重写无效
}
测试结果:
发现并没有执行permisses的查询操作,发现后台也没有打印对应的sql(我们按照逻辑执行操作),原因:MyBatis不支持超过两层的嵌套查询
所以本操作是不可行的!(想要一次查询完)
方案:使用<collection resultMap="">
,方式也是一样的
这里需要注意的一个错误是:Cannot define both nestedQueryId and nestedResultMapId in property
,这个错误的意思是:select标签和resultMap标签不能同时存在同一个标签中(删除其中一个即可)
解决方案:只嵌套一层集合操作,然后通过service层循环查出再赋值即可完成
@RequestMapping("/findAll")
public ResponseEntity<?> findAll() {
List<User> users = userMapper.findAllUsers();
for (User user : users) {
List<Role> roles = user.getRoles();
for (Role role : roles) {
Integer id = role.getId();
List<Permiss> permiss = permissMapper.selectListByRid(id);
role.setPermisses(permiss);
}
}
return ResponseEntity.ok(users);
}
使用这个方式可以实现查询效果
结果成功!
6.方案二,使用resultMap方式
直接在<collection>
标签中使用resultMap即可,一个resultMap中嵌套另外一个resultMap
使用resultMap可以实现,但是需要手动将所有需要查询的字段全部查询出来并且设定不同的别名方式才能实现
缺点,需要手动实现各种字段处理,这个地方就不贴实现代码了
7.总结
1.使用mybatisplus实现的时候,我们不能再接口中创建名称相同的方法,否则这个查询就会让mybatisplus实现
(例如:UserMapper中重写findList方法,就会调用mybatisplus的默认方法)
2.在使用<collection>
标签的时候注意不要让select和resultMap这两个同时共存,否则会报错的
3.在实现tree视图的查询的时候可以使用resultMap(比较单调的嵌套)
,在查询其他的方式多层嵌套的时候,建议只嵌套一层使用select
,其他的通过其他地方实现(结构比较清晰!)
4.在使用<collection>
标签的时候要注意javaType
,不同的结果对应不同的java类型,例如List的默认使用ArrayList,如果使用Set的时候(一个mybatis中未配置的类型),会报错(我们需要手动在myabtis中添加factory.setTypeAliases(HashSet.class);,然后我们就可以使用HashSet了)
以上纯属个人的见解,如有问题请联系本人!