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了)
以上純屬個人的見解,如有問題請聯繫本人!