一、目标介绍:
通常我们登录后台根据账号的拥有的角色不一样,每个角色拥有的权限,根据不同的角色登录显示不同的菜单。这样做可以更好的进行管理
二、设计表
我觉得想现实这个功能只靠代码无法实现,或者实现很困难,所以表需要设计的合理,功能做起来就简单很多了,
我这里设置了五张表
- 第一张是用户表 :sys_user
- 第二张是角色表 : sys_role
- 第三站是用户表和角色表的关联表 : sys_user_role
- 第四张是权限表:sys_permission
- 第五张是角色和权限的关联表:sys_role_permission
三、编写代码
用户类
@Data
public class User implements Serializable {
private Integer id;
private String username;
private String cname;
private String password;
}
角色类
@Data
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String rolename;
private String cname;
}
用户和角色关联类
@Data
public class UserRole implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer userId;
private Integer roleId;
}
权限表
@Data
public class Permission implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 权限表
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 父节点id
*/
private Long pid;
/**
* 名称
*/
private String cname;
}
角色和权限关联类
@Data
public class RolePermission implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 角色id
*/
private Long roleid;
/**
* 权限id
*/
private Long permid;
}
在创建一个返回的类CNode
@Data
@ApiModelProperty(value = "角色ID")
private Long id;
private Long pid;
@ApiModelProperty(value = "角色昵称")
private String cname;
private String url;
private String icon;
private List<CNode> children;
}
直接看业务实现层,createNode方法在下面
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService, BaseService {
@Resource
private PermissionDao permissionDao;
@Override
public R getMenu() {
//getUserId()表示当前登录的用户id
List<Permission> list = permissionDao.getMenu(getUserId());
List<CNode> nodes = createNode(list, Constant.PID);
return R.ok(nodes);
}
}
PermissionDao 调用执行的方法和sql语句拿到菜单
public interface PermissionDao {
@Select("SELECT * FROM `sys_permission` WHERE ctype=0 AND id IN (\n" +
"SELECT permid FROM `sys_role_permission` WHERE roleid IN(\n" +
"SELECT roleid FROM `sys_user_role` WHERE userid=#{userId}))")
List<Permission> getMenu(@Param("userId") Long userId);
}
我把sql执行一遍结果如下:我给的参数是1,权限最大的一个,所以返回全部菜单
为了效果明显直接我把参数改成 2,在执行一次,可以明显看到用户2看到的菜单没有那么多了
角色id对应着权限id,也就是这个角色能看到的权限菜单
拿到数据后在把他变成树形结构返回去就行了
业务层的代码写在上面的,里面创建了一个私有方法,这一步就是做树形数据的
private List<CNode> createNode(List<Permission> list, Long pid) {
return list.stream()
.filter(p -> p.getPid().equals(pid))
.map(p -> {
CNode cNode = CopyBean.copyBean(p, CNode::new); //复制对象
List<CNode> nodes = createNode(list, cNode.getId());
if (!CollectionUtils.isEmpty(nodes)) {
cNode.setChildren(nodes);
}
return cNode;
}).collect(Collectors.toList());
}
pid:代表根节点id,或者说是最外面那层菜单的id ,我的根节点是-1,所以pid就是-1
CopyBean:用来将源对象复制到目标对象,将Permission复制到CNode
测试说明:
从角色和权限的关联表就能看出,拥有角色id为1的用户可以看到全部菜单,拥有角色id为2的只能看到部分菜单,
测试结果:
登录账号:admin和lisi
先使用admin登录,拿到了全部菜单权限
在使用lisi进行登录,只有系统管理的权限