解题思路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:"http://www.jb51.net/../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];
}