在做权限管理的时候遇到了一些问题,关于权限的树形结构本来可以有很多选择,但是当时一直使用easyUI所以还是选择了她的Tree结构,在坚信吃的屎多了自然人就会聪明的信条下终于还是给搞出来了。所以记录一下。
我觉得有必要介绍一下,easyUI的属性控件展示的方式有好几种,一种是静态的。一种是通过js动态加载,我使用的异步的加载。
在这之前我要介绍一下自己的表结构,就是普通的rbac: t_user,t_user_role,t_role,t_role_permission,t_permission
1.声明一个tree
<ul id="tt" class="easyui-tree" checkbox="true"></ul>
其中checkbox指的是否是那种单选的那种tree,看,有这两种
2.因为是要进行权限管理,所以需要选中当前行,获取当前角色对象,而且重新打开这个tree。
对,就是这个样子。
这个是body中加入的一个窗口
<div id="menuWindow" class="easyui-window" title="My Window" closed="true" style="width:300px;height:400px;padding:5px;">
<ul id="tt" class="easyui-tree" ></ul>
<br />
<input type="button" value="authority" onclick="getChecked()"/>
</div>
这个是js代码:
function authority(){
var row = $('#dg').datagrid('getSelected');
$('#tt').tree({
url : "loadmenu?roleid="+row.id,
lines : true,
checkbox : true
<%-- onLoadSuccess : function(node, data){
for(var i=0;i<data.length;i++){
alert(data[i].checked);
}
}--%>
});
这里只要你返回的json数据格式符合要求,那么他就会给你展示出来,onLoadSuccess : function(node, data){}表示的当成功加载到数据的时候进行的方法。
3.数据格式
既然说到了数据格式只要符合他的标准,那么我们看文档的时候就会发现他需要的什么样的数据格式。这里我直接将我包装起来的EasyUITree拿出来。
public class EasyUITree {
public static String STATE_OPEN = "open";
public static String STATE_CLOSED = "closed";
private Integer id;
private String text;
private boolean checked;
private String state = STATE_OPEN;
private String attributes;
private List<EasyUITree> children;
public EasyUITree() {
this(null, null, STATE_OPEN);
}
public EasyUITree(Integer id, String text) {
this(id, text, STATE_OPEN);
}
public EasyUITree(Integer id, String text, String state) {
this.id = id;
this.text = text;
this.state = state;
this.children = new ArrayList<EasyUITree>();
}
//setget方法省略
}
text是内容,
checked是是否选中,
attributes是追加一个自定义属性,
state这个属性、当他为open时、说明这个节点是个文件夹、会以文件夹的形式显示,当他是closed的时候、说明这个节点是一个具体的文件节点、不会以文件夹的形式显示。
这里:我将从数据库中查到的权限信息进行再次封装到easyUITree里面。这样返还回去之后就可以直接进行显示了。
4.如何查询权限信息,并将其封装
这里需要查询两部分数据,一个是所有的权限信息结构,一个是当前角色的权限信息结构。
a)查询权限信息
mapper接口
public interface PermissionMapper {
public List<Permission> findByRoleId(int uid);
public List<Permission> findAll();}
mapper.xml
<select id="findByRoleId" parameterType="int" resultType="cn.zwq.vo.Permission">
select * from t_permission where id in (
select pid from t_role_permission where rid = #{rid})
</select>
<select id="findAll" resultType="cn.zwq.vo.Permission">
select * from t_permission
</select>
PermissionService 接口我就不写了
serviceimpl.java
@Service("permissionService")
public class PermissionServiceImpl implements PermissionService{
@Autowired
private PermissionMapper permissionMapper;
public List<Permission> findByRoleId(int roleId) {
return MenuUtil.getMenu(permissionMapper.findByRoleId(roleId));
}
public List<Permission> findAll() {
return MenuUtil.getMenu(permissionMapper.findAll());
}
}
b)进行封装
这里我直接贴出来这个permission的属性
private int id;
private String name;
private String url;
private int orderNo;
private int pid;
private String type;
private String percode;
private String pids;
private List<Permission> children = new ArrayList<Permission>();
我利用工具类直接将permission存在了一个list中
public class MenuUtil {
public static List<Permission> getMenu(List<Permission> list){
Map<Integer,Permission> map = new HashMap<Integer,Permission>();
for(Permission p:list){
if(p.getPid()==0){
map.put(p.getId(), p);
}
}
for(Permission p:list){
if(p.getPid()==0){
continue;
}
Permission permission = map.get(p.getPid());
permission.getChildren().add(p);
}
//将菜单装在list里面了。需要排序
List<Permission> menus = new ArrayList<Permission>();
Iterator<Permission> iter = map.values().iterator();
while(iter.hasNext()){
menus.add(iter.next());
}
Collections.sort(menus);
for(Permission sp:menus){
Collections.sort(sp.getChildren());
}
return menus;
}
}
5.在控制器中将它再封装到easyUITree中
@RequestMapping("/loadmenu")
@ResponseBody
public List<EasyUITree> loadMenu(Integer roleid){
//findByRoleId(roleid)获取当前角色权限,并为其selected
List<Permission> chekedList = permissionService.findByRoleId(roleid);
//从数据库中查询的保存tree的集合、比如id、父类id、text等等、可自己扩展
List<Permission> list = permissionService.findAll();
List<EasyUITree> eList = getEasyUITreeList(list,chekedList);
return eList;
}
private List<EasyUITree> getEasyUITreeList(List<Permission> list,List<Permission> chekedList) {
//用于前台显示的tree的属性、比如id、state、text、checked等等
List<EasyUITree> eList = new ArrayList<EasyUITree>();
Map<Integer,EasyUITree> eMap = new HashMap<Integer,EasyUITree>();
if(list.size() != 0){
for(Permission p : list){
EasyUITree e = new EasyUITree();
e.setId(p.getId());
e.setText(p.getName());
//e.setChecked(true);
//e.setAttributes(p.getUrl()); 为元素追加一个自定义属性
int count = p.getChildren().size();
if(count > 0){
for(Permission pchild:p.getChildren()){
EasyUITree echild = new EasyUITree();
echild.setId(pchild.getId());
echild.setText(pchild.getName());
//echild.setChecked(true);
//echild.setAttributes(pchild.getUrl());
e.getChildren().add(echild);
}
}
eMap.put(e.getId(), e);
}
for(Permission p : chekedList){
EasyUITree e = new EasyUITree();
e.setId(p.getId());
e.setText(p.getName());
e.setChecked(true);
int count = p.getChildren().size();
if(count > 0){
for(Permission pchild:p.getChildren()){
EasyUITree echild = new EasyUITree();
echild.setId(pchild.getId());
echild.setText(pchild.getName());
echild.setChecked(true);
e.getChildren().add(echild);
}
}
eMap.put(e.getId(), e);
}
}
eList.addAll(eMap.values());
return eList;
}
6.喝口水,将选中的权限信息返回后台处理
js代码
function getChecked(){
var nodes = $('#tt').tree('getChecked');//获取:checked的结点.
var s = '';
for(var i=0; i<nodes.length; i++){
if (s != '') s += ',';
s += nodes[i].id;//例如:菜单的menuID
}
//alert(s);
var row = $('#dg').datagrid('getSelected');
$.post("changeAuthority",{
ids:s,
roleId:row.id,
},function(data){
if(data){
$("#menuWindow").window("close");
};
});
}
这里往后我就不写了。哈哈哈哈哈哈哈