首先准备好5张表
user_info表,用户的信息表
role表,角色表(比如超级管理员、管理员、审核员、采购......)
创建user_role表,user_info表,role表的中间表
注意了,role_id和user_id是 user_info表和role表的关联id
auth_info表 菜单权限
创建roler_ayth表 ,auth表和role表的中间表
注意了,role_id和auth_id是 role_id表和auth_info表的关联id
也就是用户和角色有和中间表,角色和菜单表有个中间表
有表了我们开始做菜单树
1、创建实体类,mapper,service实现接口,impl实现类,映射文件mapper
博主用的是MyBatisCodeHelperPro插件,用逆向工程也就是从菜单树开始查询(MybatisX、Mybatis puls、Mybatis..插件必须卸载会冲突的,新手可以试用7天,价格在59人民币一年这样)
首先链接数据源
找到菜单权限auth_info表 右键
最后确定
这就是我们说的实体类,mapper,service实现接口,impl实现类,映射文件mapper
2、AuthInfoMapper类
package com.pn.service;import com.pn.entity.AuthInfo;
import java.util.List;public interface AuthInfoService{public List<AuthInfo> queryAuthInfoByUid(Integer userId);
}
3、AuthInfoMapper.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.pn.mapper.AuthInfoMapper"><!-- 根据用户ID查用户权限菜单--><!-- 得出合法行这个是固定的: select t3.* from user_role t1, role_auth t2, auth_info t3where t1.role_id = t2.role_id and t2.auth_id = t3.auth_id and t1.user_id = #{userId} -->
<!-- 其他条件根据自己的表来,比如博主这个t3.auth_state=1是说明开启的 --><select id="getAuthInfoByUid" resultType="AuthInfo">select t3.* from user_role t1, role_auth t2, auth_info t3where t1.role_id = t2.role_id and t2.auth_id = t3.auth_idand t3.auth_state = 1and t3.auth_type != 3and t1.user_id = #{userId}</select>
</mapper>
4、AuthInfoService 实现类接口
package com.pn.service;import com.pn.entity.AuthInfo;
import java.util.List;public interface AuthInfoService{public List<AuthInfo> queryAuthInfoByUid(Integer userId);
}
5、AuthInfoServiceImpl 实现类
package com.pn.service.impl;import com.alibaba.fastjson.JSON;
import com.pn.entity.AuthInfo;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.pn.mapper.AuthInfoMapper;
import com.pn.service.AuthInfoService;
import org.springframework.util.StringUtils;import java.time.Duration;
import java.util.ArrayList;
import java.util.List;@Service
public class AuthInfoServiceImpl implements AuthInfoService{@Autowiredprivate AuthInfoMapper authInfoMapper;// 0库 博主用的是自己封装好的redis分库的,可以自己用自己的,也可以不用//@Autowired//@Qualifier("reactiveRedisTemplateDb0")//private ReactiveRedisTemplate<String, Object> redis;/*** 查询用户菜单数的业务方法* @param userId* @return*/@Overridepublic List<AuthInfo> queryAuthInfoByUid(Integer userId) {//先从redis查缓存,因为权限很少改动,所有放缓存,//String authTerrJson = (String) redis.opsForValue().get("authTree:"+userId).block();//有的话string转json给前端//if (StringUtils.hasText(authTerrJson)) {// return JSON.parseArray(authTerrJson, AuthInfo.class);//}//查redis无缓存,查数据库List<AuthInfo> allauthInfo = authInfoMapper.getAuthInfoByUid(userId);// 将查出的菜单List<AuthInfo>转成菜单树,需要递归算法List<AuthInfo> authInfoList = allAuthToAuthTree(allauthInfo,0);// 查出的菜单树存redis,并设置有效期//redis.opsForValue().set("authTree:"+userId, JSON.toJSONString(authInfoList), Duration.ofSeconds(3600*24)).subscribe();return authInfoList;}// 递归算法,必须是私有的private List<AuthInfo> allAuthToAuthTree(List<AuthInfo> allauthInfo, Integer pid) {//查出一级菜单List<AuthInfo> allauthInfoList = new ArrayList<>();for (AuthInfo authInfo : allauthInfo) {if (authInfo.getParentId().equals(pid)) {allauthInfoList.add(authInfo);}}// 从一级菜单拿二级菜单for (AuthInfo firstauthInfo : allauthInfoList) {List<AuthInfo> firstauthInfoList = allAuthToAuthTree(allauthInfo,firstauthInfo.getAuthId());firstauthInfo.setChildAuth(firstauthInfoList);}//返回菜单树return allauthInfoList;}
}
6、AuthInfo实体类
package com.pn.entity;import java.io.Serializable;
import java.util.Date;
import java.util.List;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 权限表*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AuthInfo implements Serializable {private Integer authId;/*** 父id为空或为0,表示一级权限*/private Integer parentId;private String authName;private String authDesc;private Integer authGrade;/*** 1 模块 、2 列表、 3 按钮*/private String authType;private String authUrl;private String authCode;private Integer authOrder;/*** 1 启用 、0 禁用*/private String authState;private Integer createBy;private Date createTime;private Integer updateBy;private Date updateTime;/*** 存放当前菜单下的所有子菜单*/private List<AuthInfo> childAuth;
}
7、最后控制器,更具自己的前端给到的数据写
/*** 用户权限*/// 注入UserService接口@Autowiredprivate AuthInfoService authInfoService;
@RequestMapping("user/auth-list")public Result userAuthTree(@RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token) {//获取到token,并解析CurrentUser currentUser = tokenUtil.getCurrentUser(token);// 主要是这个 接口传递用户idList<AuthInfo> authInfos = authInfoService.queryAuthInfoByUid(currentUser.getUserId());return Result.ok("获取成功",authInfos);}