OA的权限设置
OA的权限设置:
oa的权限设置在企业中一般都是使用ajax做的,
页面刷新的方式就会比较难,所以一般是ajax将权限展示出来来选择;
--
设置权限的需求分析:
1、显示隐藏的div
2、动态的显示用户名称
3、动态的加载权限树
4、显示全选复选框按钮
5、权限的回显
6、全选复选框的功能
7、保存的功能:建立用户和权限之间的关系
--
一般是:用户和角色挂钩,角色再和权限进行挂钩;
很多的前台需求的时候就需要组织好js的结构,如果是function的累积,就会比较难以维护;
-==========
好的结构,js 的结构:
js的执行,不会是凭空执行,要么加载的时候执行,要么在事件上执行;
js的函数大部分情况是事件触发的时候执行;触发事件写功能需要用到数据;
根据需求,分析结构框架:
* js的结构组织
* 1、所有的事件的声明写在一起
* 2、所有的数据的声明写在一起
* 3、关于业务逻辑方面的内容写在一起
--
var privilege = {
/**
* 初始化事件和数据
*/
init: {
/**
* 初始化事件
*/
initEvent: function(){
},
/**
* 初始化数据
*/
initData: function(){
}
},
/**
* 整个页面所需要的数据全部存放在这里
*/
data: {
/**
* 用户的信息
*/
user: {
uid: '',
username: ''
}
},
/**
* 业务逻辑的操作
*/
businessOption: {
/**
* 操作div
*/
divOption: {
},
/**
* 操作用户
*/
userOption: {
},
/**
* 权限树的操作
*/
privilegeOption: {
}
}
};
$().ready(function(){
privilege.init.initEvent();
});
---
上面的结构是比较好的结构;
就比如之前的业务逻辑内容如果都是写在post的回调函数中,那么可能造成里面的内容越来越多,不利于维护,所以需要将其单独写出来;
分为初始化,[jQuery也是这么做,有init对应的方法],数据,事件;
事件又可以划分为,操作div[divOption],操作权限树[privilegeOption],操作用户[userOption];
----=========
事件整体划分,设置权限点击,树的操作事件,保存按钮;
--------=======
首先
1,初始化事件:点击"设置权限";js的的效果都是事件的出发,最初是有三个事件,超链接【设置权限】 树【初始化树】 提交按钮[保存权限设置信息]
/**
* 初始化事件和数据
*/
init: {
/**
* 初始化事件
*/
initEvent: function(){
/**
* 给设置权限添加click事件
*/
//遍历所有的超级链接
$("a").each(function(){
if ($(this).text() == "设置权限") {
$(this).css("cursor", "pointer");
$(this).unbind("click");
$(this).bind("click", function(){
/**
* 1、显示隐藏的div
* 获取用户名称
2、动态的显示用户名称
3、动态的加载权限树
4、显示全选复选框按钮
5、权限的回显
6、全选复选框的功能
7、保存的功能:建立用户和权限之间的关系
*/
//显示隐藏的div
privilege.businessOption.divOption.showDiv();
//经过需求分析,不仅要获取用户的名称,而且要获取uid
privilege.init.initData.apply(this);//this.initData(); initData的方法的调用者是超级链接
//动态的显示用户
privilege.businessOption.userOption.showUser();
/**
* 在点击设置权限之后,在权限树加载出来之前,显示id为loading的图片
* 在权限树加载出来以后,隐藏loading的图片,显示权限树
*/
$("#loading").show();
$("#privilegeTree").hide();
//加载权限树
privilege.businessOption.privilegeOption.loadPrivilegeTree();
});
}
});
/**
* 给全选复选框增加change事件
*/
$("#allchecked").unbind("change");
$("#allchecked").bind("change", function(){
privilege.businessOption.privilegeOption.allCheckBox.apply(this);
});
/**
* 绑定保存的事件
*/
$("#savePrivilege").unbind("click");
$("#savePrivilege").bind("click",function(){
privilege.businessOption.privilegeOption.savePrivilege();
});
},
/**
* 初始化数据
*/
initData: function(){
privilege.data.user.username = $(this).parent().siblings("td:first").text()
privilege.data.user.uid = $(this).parent().siblings("input[type='hidden']").val();
}
},
然后:加载;;;;
$().ready(function(){
privilege.init.initEvent();
});
显示用户信息,需要在点击"设置权限"要初始化用户信息,需要将uid以隐藏域存在于该行记录中,然后点击这个之后,根据该行记录查找用户名和uid;
<tbody id="TableData" class="dataContainer" datakey="userList">
<s:iterator value="#userList">
<tr class="TableDetail1 template">
<td><s:property value="username"/></td>
<s:hidden name="uid"></s:hidden>
<td><s:property value="department.getDname()"/></td>
<td>
<s:iterator value="posts">
<s:property value="pname"/>
</s:iterator>
</td>
<td>
<s:a action="userAction_delete?uid=%{uid}">删除</s:a>
<s:a action="userAction_updateUI?uid=%{uid}">修改</s:a>
<a>设置权限</a>
</td>
</tr>
</s:iterator>
</tbody>
--
这里的方式是调用这个的方法将这个对象传递进去,然后查找父节点的兄弟节点:
privilege.init.initData.apply(this);//this.initData(); initData的方法的调用者是超级链接
/**
* 初始化数据
*/
initData: function(){
privilege.data.user.username = $(this).parent().siblings("td:first").text()
privilege.data.user.uid = $(this).parent().siblings("input[type='hidden']").val();
}
这时候可以使用firebug进行编写,
2,在点击的时候获取值--初始化值;
$(this).parent().sbilings("td:first").text();//调用者是a超链接,得到父节点的第一个兄弟节点,这里就是对应的用户名;
$(this).parent().sbilings("input:hidden").text();//兄弟节点中,input:hidden ;
关键是这个this怎么解决?
将调用者的对象传递过去,apply;
privilege.init.initData.apply(this);// initData的方法的调用者是超级链接
apply方法相当于指定调用者调用该方法;
上面的方法相当于this.initData(); 区别是使用apply可以动态的改变该方法的调用者;
当然,这里的调用哪个者唯一,是this;
--
call 和 apply :http://uule.iteye.com/blog/1158829
call方法:
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
apply方法:
语法:apply([thisObj[,argArray]])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
call是直接调用,apply只是一次使用,相对来说,apply是不可能将该方法放到指定的参数对象上,也就是可以动态的修改调用者,而call是直接将其给到新对象上,相当于实现了继承;继承还可以用原型的方式实现;
------
3.点击了,初始化用户信息之后,就可以将信息显示到对应的位置;
//动态的显示用户
privilege.businessOption.userOption.showUser();
==
/**
* 操作用户
*/
userOption: {
showUser: function(){
$("#userImage").text(privilege.data.user.username);
}
},
页面上使用的是
<div class="ItemBlock_Title1">
<img border="0" width="4" height="7" src="${pageContext.request.contextPath}/css/blue/images/item_point.gif"/>
<s:label id="userImage"></s:label>//这里用label标签将信息展示出来;
</div>
=======、
4,加载权限树
privilegeOption:
--
/**
* 权限树的操作
*/
privilegeOption: {
zTree: '',//权限树
setting: {
isSimpleData: true,
treeNodeKey: "mid",
treeNodeParentKey: "pid",
showLine: true,
root: {
isRoot: true,
nodes: []
},
checkable: true,
callback: {
change: function(event, treeId, treeNode){
privilege.businessOption.privilegeOption.controlCheckBox();
},
beforeChange:function(){
privilege.businessOption.privilegeOption.updateCheckType({
"Y":"p","N":'s'
});
}
}
},
/**
* 加载权限树
*/
loadPrivilegeTree: function(){
$.post("privilegeAction_showPrivileges.action", {
uid:privilege.data.user.uid
}, function(data){
privilege.businessOption.privilegeOption.zTree = $("#privilegeTree").zTree(privilege.businessOption.privilegeOption.setting, data.privilegeList);
/**
* 把整个树加载完成以后,让全选复选框恢复功能
*/
$("#allchecked").attr("disabled", "");
$("#loading").hide();
$("#privilegeTree").show();
/**
* 设置全选复选框的初始值
*/
privilege.businessOption.privilegeOption.controlCheckBox();
});
},
/**
* 全选复选框的功能
*/
allCheckBox: function(){
/**
* 先改变setting中checkType的规则
*/
privilege.businessOption.privilegeOption.updateCheckType({
"Y": "ps", "N": "ps"
});
/**
* 判断该复选框是否被选中
*/
if ($(this).attr("checked")) {//选中
privilege.businessOption.privilegeOption.zTree.checkAllNodes(true);
}
else {//没有选中
privilege.businessOption.privilegeOption.zTree.checkAllNodes(false);
}
},
/**
* 控制全选复选框是否被选中
*/
controlCheckBox: function(){
var uncheckedNodes = privilege.businessOption.privilegeOption.zTree.getCheckedNodes(false);
if (uncheckedNodes.length == 0) {//全部选中
$("#allchecked").attr("checked", true);
}
else {//没有被全部选中
$("#allchecked").attr("checked", false);
}
},
/**
* 改变setting中checkType的规则
*/
updateCheckType:function(checkTypeJSON){
/**
* 1、先获取setting
* 2、改变setting中checkType的值
* 3、更新setting
*/
var setting = privilege.businessOption.privilegeOption.zTree.getSetting();
setting.checkType = checkTypeJSON;
privilege.businessOption.privilegeOption.zTree.updateSetting(setting);
},
/**
* 建立用户和权限之间的关联
*/
savePrivilege:function(){
/**
* 被选中的权限
*/
var checkedNodes = privilege.businessOption.privilegeOption.zTree.getCheckedNodes(true);
var checkedStr = "";
for(var i=0;i<checkedNodes.length;i++){
if(i==checkedNodes.length-1){
checkedStr = checkedStr + checkedNodes[i].mid;
}else{
checkedStr = checkedStr + checkedNodes[i].mid + ",";
}
}
var parameter = {
uid:privilege.data.user.uid,
ids:checkedStr
};
$.post("privilegeAction_savePrivilege.action",parameter,function(data){
alert(data.message);
});
}
}
一般企业中,菜单和权限是不一样的,这里只是作为简单的方式考虑;
这里加载树可以使用前面封装的方法,就是传递json方式,也可以直接加载;
一个页面的权限控制,就是将权限限定到按钮,分配,按钮入库,将按钮和用户之间建立关系;按钮也就对应着action;
把到按钮级的各个权限归类合并,保存到表中或xml文件中,在创建权限组表,允许该权限组可执行多个权限的操作,这样方便了管理员的管理,不用对每个用户都细化权限操作,只要分配权限组即可,程序中判断权限组或具体权限来显示或不显示按钮,对点击按钮后执行操作的代码也要判断权限,防止非法权限执行,这些可以写成通用类来判断执行;
前台的话也可以直接判断使用jstl标签什么的,不过这个就不是很安全了,建议还是使用spring-aop或者struts2拦截器;
==
SSH整合后分页页面卡死 :
Reply:你是不是用了OpenSessionInView模式。如果用了,那么在dao层获得session的代码你就要小心了。要写成getHibernateTemplate().getSessionFactory().getCurrentSession();这样才对。但是如果你写成了getHibernateTemplate().getSessionFactory().openSession();那么它每次执行都会开启一个新的session。并且线程结束了也不会自动关闭。所以点击两三次就会卡死了。因为session资源没有得到释放。
--
需要将权限和用户关联:
采用用户直接和菜单关联起来,进行配置,新Dao,Service,Action关联操作Menuitem;
将User和Menuitem之间建立多对多关联关系,
测试建立表;
在
//加载权限树
privilege.businessOption.privilegeOption.loadPrivilegeTree();
引入ztree的样式和js文件;
----
全选的bug问题,就是在权限树加载完成之前是不允许选择checkbox的;就是设置这个checkbox不可编辑;
==
<table cellpadding="0" cellspacing="0" class="mainForm">
<!--表头-->
<thead>
<tr align="LEFT" valign="MIDDLE" id="TableTitle">
<td width="300px" style="padding-left: 7px;">
<!-- 如果把全选元素的id指定为selectAll,并且有函数selectAll(),就会有错。因为有一种用法:可以直接用id引用元素 -->
<input type="checkbox" id="allchecked" disabled="disabled"/>
<label for="cbSelectAll">全选</label>
</td>
</tr>
</thead>
<!--显示数据列表-->
<tbody id="TableData">
<tr class="TableDetail1">
<!-- 显示权限树 -->
<td>
<img id="loading" src="${pageContext.request.contextPath}/css/images/loading.gif">
<ul id='privilegeTree' class="tree">
</td>
</tr>
</tbody>
</table>
在默认的情况下设置,<input type="checkbox" id="allchecked" disabled="disabled"/>不可用
等到加载完成之后将其设置为可编辑;
/**
* 加载权限树
*/
loadPrivilegeTree: function(){
$.post("privilegeAction_showPrivileges.action", {
uid:privilege.data.user.uid
}, function(data){
privilege.businessOption.privilegeOption.zTree = $("#privilegeTree").zTree(privilege.businessOption.privilegeOption.setting, data.privilegeList);
/**
* 把整个树加载完成以后,让全选复选框恢复功能
*/
$("#allchecked").attr("disabled", "");//加载完成之后设置为可操作checkbox
$("#loading").hide();
$("#privilegeTree").show();
/**
* 设置全选复选框的初始值
*/
privilege.businessOption.privilegeOption.controlCheckBox();
});
},
上面的操作有浏览器兼容问题,firefox不可以,IE可以;
企业中一般是采用一张加载图片的方式隐藏起来,等到加载完成之后显示;
<img id="loading" src="${pageContext.request.contextPath}/css/images/loading.gif">
<ul id='privilegeTree' class="tree">
对应操作是:
/**
* 在点击设置权限之后,在权限树加载出来之前,显示id为loading的图片
* 在权限树加载出来以后,隐藏loading的图片,显示权限树
*/
$("#loading").show();
$("#privilegeTree").hide();
//加载权限树
privilege.businessOption.privilegeOption.loadPrivilegeTree();
然后在loadPrivilegeTree里面加载完成之后:
$("#loading").hide();
$("#privilegeTree").show();
----
选择框的全选和反选:
/**
* 全选复选框的功能
*/
allCheckBox: function(){
/**
* 先改变setting中checkType的规则
*/
privilege.businessOption.privilegeOption.updateCheckType({
"Y": "ps", "N": "ps"
});
/**
* 判断该复选框是否被选中
*/
if ($(this).attr("checked")) {//选中
privilege.businessOption.privilegeOption.zTree.checkAllNodes(true);
}
else {//没有选中
privilege.businessOption.privilegeOption.zTree.checkAllNodes(false);
}
},
/**
* 控制全选复选框是否被选中
*/
controlCheckBox: function(){
var uncheckedNodes = privilege.businessOption.privilegeOption.zTree.getCheckedNodes(false);
if (uncheckedNodes.length == 0) {//全部选中
$("#allchecked").attr("checked", true);
}
else {//没有被全部选中
$("#allchecked").attr("checked", false);
}
},
/**
* 改变setting中checkType的规则
*/
updateCheckType:function(checkTypeJSON){
/**
* 1、先获取setting
* 2、改变setting中checkType的值
* 3、更新setting
*/
var setting = privilege.businessOption.privilegeOption.zTree.getSetting();
setting.checkType = checkTypeJSON;
privilege.businessOption.privilegeOption.zTree.updateSetting(setting);
},
/**
* 建立用户和权限之间的关联
*/
savePrivilege:function(){
/**
* 被选中的权限
*/
var checkedNodes = privilege.businessOption.privilegeOption.zTree.getCheckedNodes(true);
var checkedStr = "";
for(var i=0;i<checkedNodes.length;i++){
if(i==checkedNodes.length-1){
checkedStr = checkedStr + checkedNodes[i].mid;
}else{
checkedStr = checkedStr + checkedNodes[i].mid + ",";
}
}
var parameter = {
uid:privilege.data.user.uid,
ids:checkedStr
};
$.post("privilegeAction_savePrivilege.action",parameter,function(data){
alert(data.message);
});
}
全选和不全选的控制,1,加载的时候需要判断,设置是否选中这个;2,改变某一个的选择时,控制是否选中这个全选框;
这个控制是否选中可以抽取出来;就是判断下面没选中的长度是否为0;
--
这里还需要修改树的选择级联关系,根据业务,将树的操作,选择一个,影响父节点,不影响子节点;取消一个影响子节点不影响父节点;
setting里面的checkType,可以设置这个属性;
但是发现,这个以修改,影响到全选复选框的操作;
所以应该是全选复选框的时候需要修改checkType;
/**
* 改变setting中checkType的规则
*/
updateCheckType:function(checkTypeJSON){
/**
* 1、先获取setting
* 2、改变setting中checkType的值
* 3、更新setting
*/
var setting = privilege.businessOption.privilegeOption.zTree.getSetting();
setting.checkType = checkTypeJSON;
privilege.businessOption.privilegeOption.zTree.updateSetting(setting);
},
ztree的checkbox操作触发的是onChange方法,也就是callback里面的change属性;
就是在全选操作的时候需要修改
/**
* 全选复选框的功能
*/
allCheckBox: function(){
/**
* 先改变setting中checkType的规则
*/
privilege.businessOption.privilegeOption.updateCheckType({
"Y": "ps", "N": "ps"
});
/**
* 判断该复选框是否被选中
*/
if ($(this).attr("checked")) {//选中
privilege.businessOption.privilegeOption.zTree.checkAllNodes(true);
}
else {//没有选中
privilege.businessOption.privilegeOption.zTree.checkAllNodes(false);
}
},
=====
setting: {
isSimpleData: true,
treeNodeKey: "mid",
treeNodeParentKey: "pid",
showLine: true,
root: {
isRoot: true,
nodes: []
},
checkable: true,
callback: {
change: function(event, treeId, treeNode){
privilege.businessOption.privilegeOption.controlCheckBox();
},
beforeChange:function(){
privilege.businessOption.privilegeOption.updateCheckType({
"Y":"p","N":'s'
});
}
}
},
=================================
/**
* 建立用户和权限之间的关联
*/
savePrivilege:function(){
/**
* 被选中的权限
*/
var checkedNodes = privilege.businessOption.privilegeOption.zTree.getCheckedNodes(true);
var checkedStr = "";
for(var i=0;i<checkedNodes.length;i++){
if(i==checkedNodes.length-1){
checkedStr = checkedStr + checkedNodes[i].mid;
}else{
checkedStr = checkedStr + checkedNodes[i].mid + ",";
}
}
var parameter = {
uid:privilege.data.user.uid,
ids:checkedStr
};
$.post("privilegeAction_savePrivilege.action",parameter,function(data){
alert(data.message);
});
}
在Menuitem实体中的getUsers方法上加 @JSON(serialize=false)
--
@Repository("privilegeDao")
public class PrivilegeDaoImpl extends CommonDaoImpl<Menuitem> implements PrivilegeDao<Menuitem>{
@Override
public Set<Menuitem> getMenuitemsByIds(String ids) {
// TODO Auto-generated method stub
return new HashSet<Menuitem>(this.hibernateTemplate.find("from Menuitem where mid in("+ids+")"));
}
@Override
public Collection<Menuitem> getMenuitemsByUid(Long uid) {
/**
* 1、加载所有的权限节点
* 2、把用户能够访问到的节点也加载出来
* 3、把所有的权限节点中用户能够访问到的节点的checked设置为true
*/
//所有的菜单树
Collection<Menuitem> allMenuitems = this.hibernateTemplate.find("from Menuitem");
//用户能够访问到的菜单
Collection<Menuitem> userMenuitems = this.hibernateTemplate.find("from Menuitem m inner join fetch m.users u where u.uid=?",uid);
for(Menuitem menuitem:allMenuitems){
for(Menuitem menuitem2:userMenuitems){
//判断所有的菜单树中是否有用户能够访问到的菜单
if(menuitem2.getMid().longValue()==menuitem.getMid().longValue()){//正在遍历的菜单项是用户能够访问到的菜单
menuitem.setChecked(true);
}
}
}
return allMenuitems;
}
}
----
Menuitem里面加了一个属性checked;
还有一个
@JSON(serialize=false)
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
private Set<User> users = new HashSet<User>();
这个是限定json插件不解析这个属性;不加载这个属性;或者获取出来的时候设置为null;
使用配置的时候其实JSONResult类里面有includeProperties和excludeProperties;
--
public String showPrivileges() throws Exception{
this.privilegeList = this.privilegeService.getMenuitemsByUid(this.uid);
Thread.sleep(1000);
return SUCCESS;
}
public String savePrivilege(){
/**
* 建立用户和权限之间的关联
*/
Set<Menuitem> privileges = this.privilegeService.getMenuitemsByIdS(this.ids);
User user = this.userService.getUserById(this.uid);
user.setMenuitems(privileges);
this.userService.updateUser(user);
this.message = "操作成功";
return SUCCESS;
}
浙公网安备 33010602011771号