extjs 的权限问题 要求控制的对象是 菜单,按钮,URL


Posted in Javascript onMarch 09, 2010

解题思路1 : 重载Connection类
由于extjs和server端交互全都是 json格式的数据交互,server端不会控制页面的跳转,页面跳转,提示功能全都有extjs来完成。
extjs和server端的交互方法全都是继承自 Ext.data.Connection,这个类中可以拦截所有和server端交互的方法。
server端的权限控制用acegi做的,如果没通过acegi的验证,没有授权会返回到403.jsp,需要重登录会返回到 login.jsp。
因此重载Connection类,并改写其中的 handleResponse 方法,判断返回的结果是否是 403.jsp,login.jsp, 如果是就进行相应的控制,如果是正常的返回数据就继续向下执行。
我个人在403.jsp 和login.jsp 的第一行加上了 注释代码<!--权限控制自定义关键字-->,就是靠这个关键字来工作的
,代码如下:

//此处重载了Cunnection方法,用来拦截client与Server的交 互, 
//后台acegi拦截用户请求后,如果无权限,返回403.jsp;如果没登录,返回login.jsp; 
//通过Acegi拦截 后,才返回用户想要的Json结果 
Ext.override(Ext.data.Connection, { 
handleResponse : Ext.data.Connection.prototype.handleResponse.createInterceptor( 
function(response) { 
var resText=response.responseText; 
if (resText.length>10) { 
resText=resText.substr(0,9); 
} 
if (resText=='<!--login'){ 
window.top.location.href = topURL+"/login.jsp"; 
} else if (resText=='<!--deny-'){ 
if (resText=='<!--deny-'){ 
Ext.Msg.show({ 
title : '错误提示', 
msg : '禁止访问此功能,请和系统管理员联系', 
buttons : Ext.Msg.OK, 
icon : Ext.Msg.INFO 
}); 
}; 
} else if (resText=='<!--404--'){ 
Ext.Msg.show({ 
title : '错误提示', 
msg : '页面未找到', 
buttons : Ext.Msg.OK, 
icon : Ext.Msg.INFO 
}); 
} 
}) 
});

解题思路2: server端返回菜单json数据
我的菜单用tree来做的,在初始化主页面时先初始化菜单,
loader : new Ext.tree.TreeLoader({ 
dataUrl : 'getJsonMenus.do' 
}), 
这个'getJsonMenus.do'返回菜单json数据,在strut2中的配置为: 
<action name="getJsonMenus" class="jsonSystemAction" method="getJsonMenus"> 
<result type="json"> 
<param name="root">menus</param> 
</result> 
</action>

menus是个list<JsonMenu>,
JsonMenu的属性为:
private String text;
private boolean expanded;
private String id;
private boolean leaf;
private List<JsonMenu> children;
getJsonMenus.do 返回的格式是可以满足tree的格式要求的。
js代码如下
Ext.onReady(function() { 
setTimeout(function() { 
Ext.get('loading').remove(); 
Ext.getDom('header').style.visibility = 'visible'; 
var vp = new Ext.Viewport({ 
layout : 'border', 
defaults : { 
collapsible : true, 
split : true 
}, 
items : [{ 
xtype : 'box', 
region : 'north', 
applyTo : 'header', 
height : 30, 
split : false 
}, { 
title : currentUser, 
id : 'accordion-panel', 
layout : 'border', 
region : 'west', 
margins : '2 0 5 5', 
width : 200, 
minSize : 200, 
maxSize : 250, 
bodyStyle : 'background-color:#DFE8F6', 
defaults : { 
border : false 
}, 
bbar : [{ 
text : '开始', 
iconCls : 'icon-plugin', 
menu : new Ext.menu.Menu({ 
items : [{ 
text : '关于系统', 
iconCls : 'icon-info', 
handler : function() { 
new Ext.Window({ 
closeAction : 'close', 
resizable : false, 
bodyStyle : 'padding: 7', 
modal : true, 
title : '关于本系统', 
html : '本系统采用目前较为流行的技术实现,<br>前台使用了ExtJs技术,所以实现了跨浏览器<br>' + 
' 本程序在IE6,IE7,FireFox3均测试通过!<br><br>主要技术: Struts2 + Spring + iBatis + ExtJs<br><br>' 
+ '数  据  库: Oracle 9i', 
width : 300, 
height : 200 
}).show(); 
} 
}, { 
text : '退出系统', 
iconCls : 'icon-delete', 
handler : function() { 
Ext.Msg.confirm('操作提示', '您确定要退出本系统?', function(btn) { 
if ('yes' == btn) { 
Ext.Ajax.request({ 
url : 'logout.do', 
success : function() { 
location = '/'; 
}, 
failure : function() { 
Ext.Msg.show({ 
title : '错误提示', 
msg : '退出系统失败!', 
icon : Ext.Msg.ERROR, 
buttons : Ext.Msg.OK 
}); 
} 
}); 
} 
}); 
} 
}] 
}) 
}], 
items : [{ 
layout : 'accordion', 
region : 'center', 
items : [{ 
title : '导航菜单', 
iconCls : 'icon-nav', 
border : false, 
items : [{ 
xtype : 'treepanel', 
border : false, 
rootVisible : false, 
autoScroll : true, 
loader : new Ext.tree.TreeLoader({ 
dataUrl : 'getJsonMenus.do' 
}), 
root : new Ext.tree.AsyncTreeNode(), 
listeners : { 
'click' : function(n) { 
try { 
var sn = this.selModel.selNode || {}; 
if (n.leaf && n.id != sn.id) { 
Ext.getCmp('content-panel').layout.setActiveItem(n.id.substring(0, n.id 
.indexOf('-')) 
+ '-panel'); 
} 
} catch (e) { 
} 
} 
} 
}] 
},{ 
title : '系统设置', 
iconCls : 'icon-nav' 
}] 
}] 
}, { 
id : 'content-panel', 
region : 'center', 
layout : 'card', 
margins : '2 5 5 0', 
activeItem : 0, 
border : false, 
items : [start, p_company, p_user, p_dept, p_system, p_subject, p_category, p_resource] 
}] 
}); 
}, 250); 
});

这样就得到了菜单,还有网友提出了异步菜单解决方法,我也把它列到下面
解题思路3 : 同步加载所有的TAG,用hidden属性控制显示
所有的tag必须要同步加载后才可以控制component的hidden属性,异步加载不好用。
同步加载的方法如下:
//FUTURE_TAG全局的TAG控制类, 控制的组件的hidden属性,key=TAG的名字,value=true(组件隐藏),false(组件显示) 
var FUTURE_TAG={tbar1: false, tbar2: true}; 
var conn = Ext.lib.Ajax.getConnectionObject().conn; 
conn.open("GET", 'getJsonTags.do',false); 
conn.send(null); 
future_tag= eval('(' + conn.responseText + ')');

在js中TAG的用法如下:
var btn_add_system = new Ext.Button({ 
text : '添加', 
iconCls : 'icon-add', 
hidden: FUTURE_TAG.system_add, 
handler : function() { 
window_add_system.show(); 
} 
});

getJsonTags.do 返回一个Map对象,key是TAG名字,value是boolean
java的写法如下:
tagMap=new HashMap<String,Boolean>(); 
for (int i=0;i<allTagList.size();i++){ 
tagMap.put(allTagList.get(i).getResString(), true); 
}

strut2配置如下:
<action name="getJsonTags" class="jsonSystemAction" method="getJsonTags"> 
<result type="json"> 
<param name="root">tagMap</param> 
</result> 
</action>

这样就可以在后台控制前台的组件是否显示了,从而达到了我们的目的。
解决思路4:
通过ajax读取服务器端的权限值,返回这样的数据:
{tbar1: false, tbar2: true}
然后在extjs中:
var vResult = eval('(' + ajaxText + ')'); //得到{tbar1: false, tbar2: true}
这样就可以直接给tbar赋值了
disabled: vResult.tbar1
disabled: vResult.tbar2
解决思路5:
设置模块权限用于设置用户可以操作的权限。允许设置用户对模块的可操作与不可操作。
弹出设置权限子窗体
设置权限之前须选择一个用户。
Js代码
var row = grid_user.getSelectionModel().getSelected(); 
if(!row){ 
alert('对不起,您还未选择数据!'); 
return; 
} 
var row = grid_user.getSelectionModel().getSelected(); 
if(!row){ 
alert('对不起,您还未选择数据!'); 
return; 
}

创建一棵树,树放置在弹出窗体的中央。
Js代码
var root=new Ext.tree.TreeNode({ 
id:"root", 
text:"所有操作", 
checked:false, 
iconCls:'task-folder' 
}); 
var tree=new Ext.tree.TreePanel({ 
frame:false, 
region:'center', 
root:root, 
animate:true, 
enableDD:false, 
border:false, 
rootVisible:true, 
autoScroll:true 
}); 
var root=new Ext.tree.TreeNode({ 
id:"root", 
text:"所有操作", 
checked:false, 
iconCls:'task-folder' }); 
var tree=new Ext.tree.TreePanel({ 
frame:false, 
region:'center', 
root:root, 
animate:true, 
enableDD:false, 
border:false, 
rootVisible:true, 
autoScroll:true 
});

创建弹出子窗体。
Js代码
var win = new Ext.Window({ 
title:'设置模块权限', 
closable:true, 
width:300, 
height:500, 
plain:true, 
layout:'border', 
modal:true, 
items:[tree] 
}); 
win.show(this); 
var win = new Ext.Window({ 
title:'设置模块权限', 
closable:true, 
width:300, 
height:500, 
plain:true, 
layout:'border', 
modal:true, 
items:[tree] 
}); 
win.show(this);

在加载数据期间,给予提示。
Js代码
Ext.MessageBox.show({ 
title:'请稍候', 
msg:'正在加载数据,请耐心等待...', 
progress:true 
}); 
Ext.MessageBox.show({ 
title:'请稍候', 
msg:'正在加载数据,请耐心等待...', 
progress:true 
});

将根节点,所选择的用户行,父节点标志作为参数调用方法。
Js代码
getNodes(row,root,'root');
getNodes(row,root,'root');
从后台中取得数据并以树形式在客户端展现
方法定义与方法内容。
Js代码
function getNodes(row,root,parent){ 
//... 
} 
function getNodes(row,root,parent){ //...}

JSON 数据的定义。
Js代码
var record_pri = new Ext.data.Record.create([ 
{name:'modelId'}, 
{name:'modelName'}, 
{name:'sort'}, 
{name:'canUse'}, 
{name:'privilegeId'} 
]); 
var store_pri = new Ext.data.Store({ 
proxy: new Ext.data.HttpProxy({url:'../'}), 
reader: new Ext.data.JsonReader({root:'rows'},record_pri) 
}); 
var record_pri = new Ext.data.Record.create([ 
{name:'modelId'}, 
{name:'modelName'}, 
{name:'sort'}, 
{name:'canUse'}, 
{name:'privilegeId'} 
]); var store_pri = new Ext.data.Store({ 
proxy: new Ext.data.HttpProxy({url:'../'}), 
reader: new Ext.data.JsonReader({root:'rows'},record_pri) 
});

无刷新请求,获取数据并展现出来;并添加事件监听。当点击树某一节点时,判断是否已经从后台取得数据,如果还没有取则从后台获取数据,再根据返回的数据判断是叶子节点还是非叶子节点。然后以不同的方式展现与处理。
叶子节点和非叶子节点展现时,使用的图标不同。叶子节点没有添加单击事件,而非叶子节点添加了单击事件。
Js代码
Ext.Ajax.request({ 
url:'http://www.cnblogs.com/../privilegeAction.do?method=list', 
params:{ 
userId:row.get('userId'), 
parentId:parent 
}, 
success:function(response, request){ 
Ext.MessageBox.hide(); 
var res = Ext.util.JSON.decode(response.responseText); 
store_pri.loadData(res); 
for(var i=0;i<store_pri.getCount();i++){ 
var rec = store_pri.getAt(i); 
var canuse = (rec.get('canUse')=='是'?true:false); 
var modid = rec.get('privilegeId') + '-id-' + rec.get('modelId'); 
var node; 
if(rec.get('sort')=='菜单'){ 
node = new Ext.tree.TreeNode({ 
text:rec.get('modelName'), 
id:modid, 
checked:canuse, 
iconCls:'task-folder' 
}); 
node.on('click',function(node){ 
if(node.firstChild==null){ 
getNodes(row,node,get_mod_id(node.id)); 
} 
}); 
} else { 
node = new Ext.tree.TreeNode({ 
text:rec.get('modelName'), 
id:modid, 
checked:canuse, 
iconCls:'task' 
}); 
} 
node.on('checkchange',function(node,check){ 
Ext.Ajax.request({ 
url:'http://www.cnblogs.com/../privilegeAction.do?method=save2', 
params:{ 
privilegeId:get_rec_id(node.id), 
canuse:(check?'是':'否') 
}, 
success:function(response, request){ }, 
failure:function(){ 
Ext.MessageBox.hide(); 
alert('sorry!'); 
} 
}); 
}); 
root.appendChild(node); 
} 
root.expand(); 
}, 
failure:function(){ 
Ext.MessageBox.hide(); 
alert('sorry!'); 
} 
}); 
Ext.Ajax.request({ 
url:'http://www.cnblogs.com/../privilegeAction.do?method=list', 
params:{ 
userId:row.get('userId'), 
parentId:parent 
}, 
success:function(response, request){ 
Ext.MessageBox.hide(); 
var res = Ext.util.JSON.decode(response.responseText); 
store_pri.loadData(res); 
for(var i=0;i<store_pri.getCount();i++){ 
var rec = store_pri.getAt(i); 
var canuse = (rec.get('canUse')=='是'?true:false); 
var modid = rec.get('privilegeId') + '-id-' + rec.get('modelId'); 
var node; 
if(rec.get('sort')=='菜单'){ 
node = new Ext.tree.TreeNode({ 
text:rec.get('modelName'), 
id:modid, 
checked:canuse, 
iconCls:'task-folder' 
}); 
node.on('click',function(node){ 
if(node.firstChild==null){ 
getNodes(row,node,get_mod_id(node.id)); 
} 
}); 
} else { 
node = new Ext.tree.TreeNode({ 
text:rec.get('modelName'), 
id:modid, 
checked:canuse, 
iconCls:'task' 
}); 
} 
node.on('checkchange',function(node,check){ 
Ext.Ajax.request({ 
url:'https://3water.com/../privilegeAction.do?method=save2', 
params:{ 
privilegeId:get_rec_id(node.id), 
canuse:(check?'是':'否') 
}, 
success:function(response, request){ 
}, 
failure:function(){ 
Ext.MessageBox.hide(); 
alert('sorry!'); 
} 
}); 
}); 
root.appendChild(node); 
} 
root.expand(); 
}, 
failure:function(){ 
Ext.MessageBox.hide(); 
alert('sorry!'); 
} });

当非叶子节点被点击时,递归地调用方法来获取孩子节点。
获取行的ID和模块的ID。树的节点将行的ID和模块的ID一起取出来了。不然的话,如果只取得模块ID,而不取行ID,那么在修改的时候,则不能进行正确的修改。
Js代码
function get_rec_id(str){ 
var arr = str.split('-id-'); 
return arr[0]; 
} 
function get_mod_id(str){ 
var arr = str.split('-id-'); 
return arr[1]; 
}
Javascript 相关文章推荐
更换select下拉菜单背景样式的实现代码
Dec 20 Javascript
探索Emberjs制作一个简单的Todo应用
Nov 07 Javascript
Javascript 垃圾收集机制介绍理解
May 14 Javascript
深入浅析Node.js 事件循环
Dec 20 Javascript
全面介绍javascript实用技巧及单竖杠
Jul 18 Javascript
jQuery EasyUI提交表单验证
Jul 19 Javascript
基于Vue.js实现数字拼图游戏
Aug 02 Javascript
jQuery使用Layer弹出层插件闪退问题
Dec 22 Javascript
ES6中Array.copyWithin()函数的用法实例详解
Sep 16 Javascript
前端防止用户重复提交js实现代码示例
Sep 07 Javascript
vue实现固定位置显示功能
May 30 Javascript
javascript浅层克隆、深度克隆对比及实例解析
Feb 09 Javascript
javascript 简单抽屉效果的实现代码
Mar 09 #Javascript
Javascript常考语句107条收集
Mar 09 #Javascript
风吟的小型JavaScirpt库 (FY.JS).
Mar 09 #Javascript
Jquery实现无刷新DropDownList联动实现代码
Mar 08 #Javascript
JavaScript this调用规则说明
Mar 08 #Javascript
javascript 放大镜 v1.0 基于Yui2 实现的放大镜效果
Mar 08 #Javascript
JavaScript中的闭包原理分析
Mar 08 #Javascript
You might like
php is_file()和is_dir()用于遍历目录时用法注意事项
2010/03/02 PHP
Session的工作机制详解和安全性问题(PHP实例讲解)
2014/04/10 PHP
ThinkPHP自定义函数解决模板标签加减运算的方法
2015/07/03 PHP
PHP匿名函数和use子句用法实例
2016/03/16 PHP
CodeIgniter框架基本增删改查操作示例
2017/03/23 PHP
php生成短网址/短链接原理和用法实例分析
2020/05/29 PHP
javascript判断单选框或复选框是否选中方法集锦
2007/04/04 Javascript
新老版本juqery获取radio对象的方法
2010/03/01 Javascript
基于jquery插件制作左右按钮与标题文字图片切换效果
2013/11/07 Javascript
详解Javascript 装载和执行
2014/11/17 Javascript
原生javascript实现分享到朋友圈功能 支持ios和android
2016/05/11 Javascript
js中最容易被忽视的事件问题大总结
2016/05/15 Javascript
jQuery实现的图片轮播效果完整示例
2016/09/12 Javascript
ES6入门教程之let和const命令详解
2017/05/17 Javascript
原生js实现密码输入框值的显示隐藏
2017/07/17 Javascript
Iphone手机、安卓手机浏览器控制默认缩放大小的方法总结(附代码)
2017/08/18 Javascript
解决在vue项目中webpack打包后字体不生效的问题
2018/09/01 Javascript
JS实现textarea通过换行或者回车把多行数字分割成数组并且去掉数组中空的值
2018/10/29 Javascript
nodejs提示:cross-device link not permitted, rename错误的解决方法
2019/06/10 NodeJs
Node.js API详解之 zlib模块用法分析
2020/05/19 Javascript
浅谈JS for循环中使用break和continue的区别
2020/07/21 Javascript
vue-admin-template配置快捷导航的代码(标签导航栏)
2020/09/04 Javascript
基于Python的关键字监控及告警
2017/07/06 Python
Python中函数及默认参数的定义与调用操作实例分析
2017/07/25 Python
分析python切片原理和方法
2017/12/19 Python
Selenium(Python web测试工具)基本用法详解
2018/08/10 Python
python多维数组分位数的求取方式
2020/03/03 Python
如何利用python生成MD5并去重
2020/12/07 Python
html+css3实现的登录界面
2020/12/09 HTML / CSS
德国百年厨具品牌WMF美国站:WMF美国
2016/09/12 全球购物
Rosetta Stone官方网站:语言学习
2019/01/05 全球购物
2014年销售工作总结与计划
2014/12/01 职场文书
北京导游词
2015/02/12 职场文书
2015年扶贫帮困工作总结
2015/05/20 职场文书
煤矿隐患排查制度
2015/08/05 职场文书
Java中CyclicBarrier和CountDownLatch的用法与区别
2021/08/23 Java/Android