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

  解题思路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.glzy8.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];

  }