十四、根据权限定制菜单显示
Shiro根据权限过滤用户对系统模块URL的非法访问,系统主页面的功能菜单也需要根据不同权限显示不同的功能菜单,无权访问的功能模块,其对应的菜单就不需要显示系统主页面上,Shiro的权限授权和菜单授权可以统一配置,但统一设计比较复杂,故分为两个模块完成。
菜单与功能表 gf_function
角色表 gf_role
菜单角色中间表 gf_menu2role
菜单与角色构成多对多关系
SQL
create table gf_menu2role(id varchar(32),
funcid varchar(32),
roleid varchar(32));
Mapper SQL
<!--
菜单角色授权表,哪些角色具有哪些菜单权限配置,此表主要定制界面上的菜单显示
-->
<insert id="saveMenuRole" parameterType="com.gf.statusflow.def.Menu2RoleInfo">
insert into gf_menu2role(id,funcid,roleid)
values(#{id},#{funcId},#{roleId})
</insert>
<update id="updateMenuRole" parameterType="com.gf.statusflow.def.Menu2RoleInfo">
update gf_menu2role set funcid=#{funcId},roleid=#{roleId}
where id=#{id}
</update>
<delete id="deleteMenuRoleById" parameterType="String">
delete from gf_menu2role where id=#{id}
</delete>
<delete id="deleteMenuRoleByRoleId" parameterType="String">
delete from gf_menu2role where roleid=#{roleId}
</delete>
<delete id="deleteMenuRoleByFuncId" parameterType="String">
delete from gf_menu2role where funcid=#{funcId}
</delete>
<select id="getMenuRoleById" resultType="com.gf.statusflow.def.Menu2RoleInfo">
select * from gf_menu2role where id=#{id}
</select>
<select id="getMenuRoleByRoleId" resultType="com.gf.statusflow.def.Menu2RoleInfo">
select * from gf_menu2role where roleid=#{roleId}
</select>
<select id="getMenuRoleByFuncId" resultType="com.gf.statusflow.def.Menu2RoleInfo">
select * from gf_menu2role where funcid=#{funcId}
</select>
<select id="getFuncListByUserId" resultType="com.gf.model.FunctionInfo">
select f.* from gf_function f,gf_menu2role m2r,gf_role r,gf_orguserrole our
where f.id=m2r.funcid and m2r.roleid=r.id and r.id=our.roleid
and our.entityid=#{userId}
</select>
<select id="getAclMenu" resultType="com.gf.statusflow.def.Menu2RoleInfo">
select m2r.id,r.name roleName,f.name funcName
from gf_function f,gf_role r,gf_menu2role m2r
where f.id=m2r.funcid and r.id=m2r.roleid
and (m2r.funcid like '%${funcId}%' and m2r.roleid like '%${roleId}%')
</select>
Mapper接口
/**
* 菜单角色相关Mybatis方法
*/
public void saveMenuRole(Menu2RoleInfo m2r);
public void updateMenuRole(Menu2RoleInfo m2r);
public void deleteMenuRoleById(@Param("id") String id);
public void deleteMenuRoleByRoleId(@Param("roleId") String roleId);
public void deleteMenuRoleByFuncId(@Param("funcId") String funcId);
public Menu2RoleInfo getMenuRoleById(@Param("id") String id);
public List<Menu2RoleInfo> getMenuRoleByRoleId(@Param("roleId") String roleId);
public List<Menu2RoleInfo> getMenuRoleByFuncId(@Param("funcId") String funcId);
public List<FunctionInfo> getFuncListByUserId(@Param("userId") String userId);
public List<Menu2RoleInfo> getAclMenu(@Param("funcId") String funcId,
@Param("roleId") String roleId);
IOrgModel组织机构接口
/**
* 菜单角色相关Mybatis方法
*/
public void saveMenuRole(Menu2RoleInfo m2r);
public void updateMenuRole(Menu2RoleInfo m2r);
public void deleteMenuRoleById(String id);
public void deleteMenuRoleByRoleId(String roleId);
public void deleteMenuRoleByFuncId(String funcId);
public Menu2RoleInfo getMenuRoleById(String id);
public List<Menu2RoleInfo> getMenuRoleByRoleId(String roleId);
public List<Menu2RoleInfo> getMenuRoleByFuncId(String funcId);
public List<FunctionInfo> getFuncListByUserId(String userId);
public List<Menu2RoleInfo> getAclMenu(String funcId,String roleId);
组织机构实现类DefaultOrgModel
/**
* 菜单角色相关Mybatis方法
*/
public void saveMenuRole(Menu2RoleInfo m2r)
{
try
{
mapper.saveMenuRole(m2r);
}
catch(Exception e)
{
log.error(e.getMessage());
}
}
public void updateMenuRole(Menu2RoleInfo m2r)
{
try
{
mapper.updateMenuRole(m2r);
}
catch(Exception e)
{
log.error(e.getMessage());
}
}
public void deleteMenuRoleById(String id)
{
try
{
mapper.deleteMenuRoleById(id);
}
catch(Exception e)
{
log.error(e.getMessage());
}
}
public void deleteMenuRoleByRoleId(String roleId)
{
try
{
mapper.deleteMenuRoleByRoleId(roleId);
}
catch(Exception e)
{
log.error(e.getMessage());
}
}
public void deleteMenuRoleByFuncId(String funcId)
{
try
{
mapper.deleteMenuRoleByFuncId(funcId);
}
catch(Exception e)
{
log.error(e.getMessage());
}
}
public Menu2RoleInfo getMenuRoleById(String id)
{
try
{
return mapper.getMenuRoleById(id);
}
catch(Exception e)
{
log.error(e.getMessage());
}
return null;
}
public List<Menu2RoleInfo> getMenuRoleByRoleId(String roleId)
{
try
{
return mapper.getMenuRoleByRoleId(roleId);
}
catch(Exception e)
{
log.error(e.getMessage());
}
return null;
}
public List<Menu2RoleInfo> getMenuRoleByFuncId(String funcId)
{
try
{
return mapper.getMenuRoleByFuncId(funcId);
}
catch(Exception e)
{
log.error(e.getMessage());
}
return null;
}
public List<FunctionInfo> getFuncListByUserId(String userId)
{
try
{
return mapper.getFuncListByUserId(userId);
}
catch(Exception e)
{
log.error(e.getMessage());
}
return null;
}
public List<Menu2RoleInfo> getAclMenu(String funcId,String roleId)
{
try
{
return mapper.getAclMenu(funcId,roleId);
}
catch(Exception e)
{
log.error(e.getMessage());
}
return null;
}
控制层OrgModelCtrl
@RequestMapping("/menuacl.action")
public String menuacl()
{
return "/orgmodel/menuacl";
}
@ResponseBody
@RequestMapping("/menufuncroot.action")
public List<TreeNode> menufuncroot()
{
FunctionInfo rootFi = orgmodel.getRootFunc();
if(rootFi == null)
{
rootFi = orgmodel.initFunc();
}
List<TreeNode> trees = new ArrayList<TreeNode>();
TreeNode rootTree = new TreeNode();
rootTree.setId(rootFi.getId().toString());
rootTree.setText(rootFi.getName());
rootTree.setState("closed");
Map attributes = new HashMap();
attributes.put("parentId",rootFi.getParentId());
attributes.put("path", "/");
attributes.put("fullName", "/"+rootFi.getName());
attributes.put("isload", "false");
rootTree.setAttributes(attributes);
trees.add(rootTree);
return trees;
}
@ResponseBody
@RequestMapping("/menugettreebyid")
public List<TreeNode> menugettreebyid(String id)
{
List<FunctionInfo> funs = orgmodel.getChildFunc(id);
List<TreeNode> rtn = new ArrayList<TreeNode>();
if(funs != null && funs.size()>0)
{
for(FunctionInfo fi:funs)
{
TreeNode ti = new TreeNode();
ti.setId(fi.getId().toString());
ti.setText(fi.getName());
ti.setIconCls(fi.getIcon()!=null?fi.getIcon():"pic_1");
ti.setUrl(fi.getUrl());
List<FunctionInfo> chd = orgmodel.getChildFunc(fi.getId());
if(chd != null && chd.size()>0)
ti.setState("closed");
else
{
ti.setState("open");
}
ti.addAttribute("path",fi.getPath());
ti.addAttribute("fullName",fi.getFullName());
ti.addAttribute("isload","false");
if(fi.getPriority() != null)
ti.addAttribute("priority",fi.getPriority().toString());
if(fi.getParentId() != null)
ti.addAttribute("parentId",fi.getParentId().toString());
rtn.add(ti);
}
}
return rtn;
}
@RequestMapping("/menuroleload.action")
@ResponseBody
public Map menuroleload(String funcId,String roleId,Integer page,Integer rows)
{
PageHelper.startPage(page, rows);
List<Menu2RoleInfo> lists = orgmodel.getAclMenu(funcId,roleId);
PageInfo pi = new PageInfo(lists);
Long total = pi.getTotal();
List<Menu2RoleInfo> perms = pi.getList();
Map m = new HashMap();
m.put("total", total);
m.put("rows", perms);
return m;
}
@RequestMapping("/menurolesave.action")
@ResponseBody
public Boolean menurolesave(String[] funcId,String[] roleId)
{
if(funcId != null && roleId != null)
{
for(String funcId2:funcId)
{
orgmodel.deleteMenuRoleByFuncId(funcId2);
for(String roleId2:roleId)
{
if(!"".equals(Util.fmtStr(funcId2)) && !"".equals(Util.fmtStr(roleId2)))
{
Menu2RoleInfo m2r = new Menu2RoleInfo();
m2r.setId(UUID.create("m2r"));
m2r.setFuncId(funcId2);
m2r.setRoleId(roleId2);
orgmodel.saveMenuRole(m2r);
}
}
}
}
return true;
}
@RequestMapping("/menuroledelete.action")
@ResponseBody
public Boolean menuroledelete(String[] id)
{
if(id != null)
{
for(String id2:id)
{
orgmodel.deleteMenuRoleById(id2);
}
}
return true;
}
页面JSP
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String webCtx = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<script type="text/javascript" src="<%=webCtx %>/static/easyui/jquery.min.js"></script>
<script type="text/javascript" src="<%=webCtx %>/static/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="<%=webCtx %>/static/easyui/easyui-lang-zh_CN.js"></script>
<link rel="stylesheet" href="<%=webCtx %>/static/easyui/themes/default/easyui.css"/>
<link rel="stylesheet" href="<%=webCtx %>/static/easyui/themes/icon.css"/>
<link rel="stylesheet" href="<%=webCtx %>/static/easyui/myicon.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script>
function reloadtree()
{
$.get('/menufuncroot.action',function(data)
{
$('#tree').tree({
data: data
});
}
)
}
function reloadroletree()
{
$.get('/roleroot.action',function(data)
{
$('#roletree').tree({
data: data
});
}
)
}
function addmenurole()
{
var nodes = $('#tree').tree('getChecked');
if(nodes.length == 0)
{
$.messager.alert('提示','请选择模块或者权限节点,选择模块节点时将授权此模块下所有权限');
return;
}
var funcId = '';
for(var i=0;i<nodes.length;i++)
{
funcId = funcId + nodes[i].id + ',';
}
var nodes2 = $('#roletree').tree('getChecked');
if(nodes2.length == 0)
{
$.messager.alert('提示','请选择角色节点');
return;
}
var roleId = '';
for(var i=0;i<nodes2.length;i++)
{
roleId = roleId + nodes2[i].id + ',';
}
console.log('roleid='+roleId+',funcId='+funcId);
$.ajax({
url:'/menurolesave.action?funcId='+funcId+"&roleId="+roleId,
success:function(data)
{
$('#permdg').datagrid('reload');
}
})
}
function deletemenurole()
{
var objs = $('#permdg').datagrid('getChecked');
var id = '';
for(i=0;i<objs.length;i++)
id = id + objs[i].id+ ',';
console.log('menuroledelete id='+id);
$.ajax({
url:'/menuroledelete.action?id='+id,
success:function(data)
{
$('#permdg').datagrid('reload');
}
})
}
$(document).ready(function()
{
reloadtree();
$('#tree').tree({
onBeforeExpand:function(node,param)
{
if(node.attributes.isload=='false')
{
$.ajaxSettings.async = false;
var url = '/menugettreebyid.action?id='+node.id;
$.get(url,function(data)
{
$('#tree').tree('append', {
parent: node.target,
data: data
});
}
)
$.ajaxSettings.async = true;
node.attributes.isload = 'true';
}
},
onExpand: function(node){
},
onClick: function(node){
$('#permdg').datagrid({
url:'/menuroleload.action?funcId='+node.id
});
}
});
$('#roletree').tree({
onClick: function(node){
$('#permdg').datagrid({
url:'/menuroleload.action?roleId='+node.id
});
}
});
reloadroletree();
});
</script>
</head>
<body class="easyui-layout">
<div data-options="region:'west',title:'菜单导航'" style="width:200px;padding:0px;">
<ul id="tree" class="easyui-tree" data-options="checkbox:true,cascadeCheck:false,lines:true">
</ul>
</div>
<div data-options="region:'center'">
<div id="p" class="easyui-panel" style="width:100%;height:100%" data-options="iconCls:'icon-save',closable:true">
<div class="easyui-layout" data-options="fit:true">
<div data-options="region:'west',title:'角色导航'" style="width:200px;padding:0px;">
<ul id="roletree" class="easyui-tree" data-options="checkbox:true,cascadeCheck:false,lines:true">
</ul>
</div>
<div data-options="region:'center',title:'菜单授权'">
<table id="permdg" class="easyui-datagrid" style="width:100%;height:100%"
data-options="url:'/menuroleload.action',fitColumns:true,pagination:true,
pageSize:10,pageList:[10,50,100,200],toolbar:'#tb'">
<thead>
<tr>
<th data-options="field:'id',width:100,checkbox:true">ID</th>
<th data-options="field:'funcName',width:100">模块名称</th>
<th data-options="field:'roleName',width:100">授权角色</th>
</tr>
</thead>
</table>
<div id="tb">
<a id="btn" onclick="addmenurole()" class="easyui-linkbutton" data-options="iconCls:'icon-add'">添加授权</a>
<a id="btn" onclick="deletemenurole()" class="easyui-linkbutton" data-options="iconCls:'icon-remove'">删除授权</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
界面设计
菜单"组织机构"与“用户管理”都分配给角色Test,菜单"组织机构"下包含“部门管理”,“用户管理”,“角色管理”,“角色分配”,角色Test具有菜单"组织机构"的权限,也就具有"组织机构"下面的四个子菜单的权限。
角色Test分配给用户Test3
用户Test3登录后,只能看到菜单"组织机构"其下的四个子菜单
代码下载
git clone -b day11 https://github.com/qixiangchen/gufang_fisys.git