[size=large]这个功能的思路是自己原创的,没看过其他例子,其实是在做之前网上搜了很多也没个可以参考的例子.主要技术是后台springsecurity做拦截判断,前台Extjs4做按钮动态渲染.如果你不了解springsecrity,那你可以先看下我的另一篇相关博客

[b]创建数据库表(liqiubase方式创建看上一篇)[/b] [/size]

<createTable tableName="permissions">  
            <column name="id" type="bigint">  
                <constraints nullable="false" primaryKey="true" />  
            </column>  
            <!-- 权限名称 -->
            <column name="name" type="varchar(32)" />
            <!-- 该权限需要访问的链接 -->
            <column name="actionurl" type="varchar(256)" /> 
            <!-- 该权限需要用到的js -->
            <column name="jsurl" type="varchar(256)" />
            <!-- 权限等级 1主菜单 2子菜单 3及以下按钮 -->
            <column name="level" type="int" />
            <!-- 菜单父级id -->
            <column name="parentid" type="bigint"/>
            <!-- 排序编号 -->
            <column name="ordernum" type="int" defaultValue="0"/>  
        </createTable>



[size=large]这张是权限表,也是菜单(按钮)表,每个菜单都有他自己需要访问链接的权限,当菜单类型为子菜单或按钮时还需要配置该按钮对应的js文件,对没错,每个按钮都有自己独立的js文件,在用户没有按钮权限的时候,前端是js都不需要加载的



[b]添加菜单初始数据[/b]


[/size]



<insert tableName="permissions">
        	<column name="id" value="1"/>  
            <column name="name" value="用户管理" />
            <column name="level" value="1" />
            <column name="parentid" value="-1"/>
            <column name="ordernum" value="1"/>
        </insert>
        <insert tableName="permissions">
        	<column name="id" value="101"/>  
            <column name="name" value="账号管理" />
            <column name="actionurl" value="account!query.action" /> 
            <column name="jsurl" value="user/account/searchGrid" />
            <column name="level" value="2" />
            <column name="parentid" value="1"/>
            <column name="ordernum" value="1"/>
        </insert>
        <insert tableName="permissions">
        	<column name="id" value="102"/>  
            <column name="name" value="角色管理" />
            <column name="actionurl" value="" /> 
            <column name="jsurl" value="user/role/mainPanel" />
            <column name="level" value="2" />
            <column name="parentid" value="1"/>
            <column name="ordernum" value="2"/>
        </insert>
        <insert tableName="permissions">
        	<column name="id" value="1001"/>  
            <column name="name" value="新增" />
            <column name="actionurl" value="account!save.action" /> 
            <column name="jsurl" value="user/account/searchGridAddBtn" />
            <column name="level" value="3" />
            <column name="parentid" value="101"/>
            <column name="ordernum" value="1"/>
        </insert>
        <insert tableName="permissions">
        	<column name="id" value="1004"/>  
            <column name="name" value="修改" />
            <column name="actionurl"   value="account!save.action,account!find.action" /> 
            <column name="jsurl" value="user/account/searchGridUpdBtn" />
            <column name="level" value="3" />
            <column name="parentid" value="101"/>
            <column name="ordernum" value="1"/>
        </insert>




[size=large]添加了一个父级菜单用户管理,两个子集菜单账号管理和角色管理,同时在账号管理下添加两个按钮新增和修改,需要注意的是新增的授权链接是account!save.action而修改的授权链接是account!save.action,account!find.action,因为修改需要先查再能改,当用户被授予新增和修改两个权限的时候,访问account!save.action,account!find.action也就不会受阻了



[b]创建角色表和角色权限关联表[/b]


[/size]


<createTable tableName="roles">  
        	<column name="id" type="bigint">  
                <constraints nullable="false" primaryKey="true" />  
            </column>
            <column name="rolename" type="varchar(32)" />
		</createTable>

		<insert tableName="roles">  
            <column name="id" value="1" />  
            <column name="rolename" value="超级管理员" />  
        </insert>
<createTable tableName="role_permission">  
            <column name="id" type="bigint">  
                <constraints nullable="false" primaryKey="true" />  
            </column>  
            <column name="perid" type="bigint" />
            <column name="roleid" type="bigint" /> 
        </createTable>




[size=large]角色和权限是多对多的关系,一个角色可以有多个权限,一个权限也可以属于多个角色,


配完初始数据以后前台展示大致是这样的(图片太大请在新窗口打开)[/size]


[img]http://dl2.iteye.com/upload/attachment/0110/3935/d7e898bc-1efd-34b3-ab94-8f6a3f974b0d.jpg[/img]



[size=large]


拥有角色管理的的用户可以添加删除角色,同时可以为没每个角色分配权限


[b]创建用户角色关联表[/b]


[/size]


<createTable tableName="account_role">  
            <column name="accountid" type="bigint" />
            <column name="roleid" type="bigint" /> 
        </createTable>
        <insert tableName="account_role">
            <column name="accountid" value="1" />
            <column name="roleid" value="1" /> 
        </insert>



[size=large]


这里给admin初始化了id为1的角色,也就是超级管理员,同样


拥有账号管理里的用户可以为账号添加角色


[/size]


[img]http://dl2.iteye.com/upload/attachment/0110/3944/6dfbee3e-fa7b-38f8-a9d9-4957e702118b.jpg[/img]


[size=large]到这里数据的配置基本讲完了,再展示下初始数据的liqiubase文件,大致就是那几张表,


最后我再给游客2分配了几个权限,新增一个角色为游客2的账号[/size]


[img]http://dl2.iteye.com/upload/attachment/0110/3948/d595180d-68b6-3a56-ab41-b109ec4ec99e.jpg[/img]




[img]http://dl2.iteye.com/upload/attachment/0110/4029/66a7093a-30df-3742-bd72-6053889ceabc.jpg[/img]




[img]http://dl2.iteye.com/upload/attachment/0110/3956/f9e4412e-70e6-386c-9b56-0adbf4eeedc5.jpg[/img]



[size=large]以上展示的只是数据配置的过程,通俗的讲就是想法,


现在想法已经出来了,权限也分配好了真正的权限控制核心代码就开始了,首先展示下我的hibernate entity


[/size]


package cn.sdh.entity;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.struts2.json.annotations.JSON;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;

import cn.sdh.common.base.AuditEntity;

@SuppressWarnings("serial")
@Entity
@Table(name="accounts")
public class Account extends AuditEntity implements UserDetails {


	public Account(){
	}

	public Account(Long id, String username, String password, String email,Date lastLoginTime, int userType){
		this.id = id;
		this.username = username;
		this.password = password;
		this.email = email;
		this.lastLoginTime = lastLoginTime;
		this.userType = userType;
	}

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ACCOUNT")
	@SequenceGenerator(name = "SEQ_ACCOUNT", sequenceName = "SEQ_ACCOUNT", initialValue = 2, allocationSize = 1)
	@Column(name="id")
	private Long id;

	@Column(name="username")
	private String username;

	@Column(name="password")
	private String password;

	@Column(name="email")
	private String email;

	//@Type(type="cn.sdh.common.userType.dateToInt")
	@Column(name="lastlogintime")
	private Date lastLoginTime;

	private int userType;//用户类型-1:超级管理员 0普通用户 1+级用户

	//是否在线
	@Transient
	private int isOnLine;

	//搜索时间 起止
	@Transient
	private Date lastLoginTime1;

	@Transient
	private Date lastLoginTime2;

	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name="account_role",joinColumns={@JoinColumn(name="accountid")},inverseJoinColumns={@JoinColumn(name="roleid")})
	private List<Role> roles = new ArrayList<Role>();

	@Transient
	private File photo;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public List<Role> getRoles() {
		return roles;
	}

	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}

	public Date getLastLoginTime() {
		return lastLoginTime;
	}

	public void setLastLoginTime(Date lastLoginTime) {
		this.lastLoginTime = lastLoginTime;
	}

	/**
	 * 告诉spring当前用户的角色
	 */
	@Override
	@JSON(serialize=false)
	public Collection<GrantedAuthority> getAuthorities() {
		Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
		for (Role role : this.getRoles()) {
			authSet.add(new GrantedAuthorityImpl(role.getId().toString()));
		}
		return authSet;
	}

	@Override
	@JSON(serialize=false)
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	@JSON(serialize=false)
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	@JSON(serialize=false)
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	@JSON(serialize=false)
	public boolean isEnabled() {
		return true;
	}

	public Date getLastLoginTime1() {
		return lastLoginTime1;
	}

	public void setLastLoginTime1(Date lastLoginTime1) {
		this.lastLoginTime1 = lastLoginTime1;
	}

	public Date getLastLoginTime2() {
		return lastLoginTime2;
	}

	public void setLastLoginTime2(Date lastLoginTime2) {
		this.lastLoginTime2 = lastLoginTime2;
	}

	public int getUserType() {
		return userType;
	}

	public void setUserType(int userType) {
		this.userType = userType;
	}

	public int getIsOnLine() {
		return isOnLine;
	}

	public void setIsOnLine(int isOnLine) {
		this.isOnLine = isOnLine;
	}

	@JSON(serialize=false)
	public List<Permission> getSignPer(){

		List<Permission> perList = new ArrayList<Permission>();

		for(Role role : this.getRoles()){
			List<Permission> sublist = role.getPermissionList();

			for(int h = 0; h<sublist.size(); h++){
				boolean continueFlag = false;

				for(int j = 0;j<perList.size();j++){
					if(role.getPermissionList().get(h).getId()==perList.get(j).getId()){
						continueFlag = true;

						break;
					}

				}

				if(continueFlag){
					continue;
				}
				if(role.getPermissionList().get(h).getLevel()==2){
					role.getPermissionList().get(h).setLeaf(1);
				}
				role.getPermissionList().get(h).setChildren(null);
				//role.getPermissionList().get(h).setControlType(role.getPermissionList().get(h).getControlType());
				perList.add(role.getPermissionList().get(h));
			}

		}

		return perList;
	}

	public File getPhoto() {
		return photo;
	}

	public void setPhoto(File photo) {
		this.photo = photo;
	}

}



package cn.sdh.entity;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.struts2.json.annotations.JSON;

import cn.sdh.common.base.AuditEntity;

/**
 * 权限类(菜单,按钮,功能)
 * @author 孙东辉
 */
@Entity
@Table(name="permissions")
public class Permission extends  AuditEntity{

	/**
	 * 
	 */
	private static final long serialVersionUID = 7930766554705439940L;


	@Id
	@Column(name="id")
	private Long id;


	@Column(name="name")
	private String name;

	/**
	 * 访问地址
	 */
	@Column(name="actionurl")
	private String actionUrl;

	/**
	 * js文件地址
	 */
	@Column(name="jsurl")
	private String jsUrl;

	/**
	 * 等级 1-N
	 */
	@Column(name="level")
	private int level;

	/**
	 * 父级编号
	 */
	@Column(name="parentid")
	private Long parentid;

	/**
	 * 弹出的控件类
	 */
	@Transient
	private String controlType;

	@Transient
	private int leaf;

	@Transient
	private boolean checked;

	@Transient
	private boolean expanded = true;

	@OneToMany(fetch=FetchType.EAGER)
	@JoinColumn(name = "parentid", referencedColumnName="id",insertable=false,updatable=false)
	private List<Permission> children;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getActionUrl() {
		return actionUrl;
	}

	public void setActionUrl(String actionUrl) {
		this.actionUrl = actionUrl;
	}

	public String getJsUrl() {
		return jsUrl;
	}

	public void setJsUrl(String jsUrl) {
		this.jsUrl = jsUrl;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}

	public Long getParentid() {
		return parentid;
	}

	public void setParentid(Long parentid) {
		this.parentid = parentid;
	}

	@JSON(name="text")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getControlType() {
		if(this.jsUrl!=null)
			return getControlTypeByDg(this.jsUrl);
		else
			return this.controlType;
	}

	public void setControlType(String controlType) {
		this.controlType = controlType;
	}

	public int getLeaf() {
		if(this.level==3){
			return 1;
		}
		return this.leaf;
	}

	public void setLeaf(int leaf) {
		this.leaf = leaf;
	}

	public boolean isChecked() {
		return checked;
	}

	public void setChecked(boolean checked) {
		this.checked = checked;
	}

	public List<Permission> getChildren() {
		return children;
	}

	public void setChildren(List<Permission> children) {
		this.children = children;
	}

	public boolean isExpanded() {
		return expanded;
	}

	public void setExpanded(boolean expanded) {
		this.expanded = expanded;
	}

	/**
	 * 通过路径获得组件名称
	 * @param path
	 * @return
	 */
	public String getControlTypeByDg(String path){
		if(path.indexOf("/")>=0){
			path = path.replaceFirst(path.substring(path.indexOf("/"),path.indexOf("/")+2), path.substring(path.indexOf("/")+1,path.indexOf("/")+2).toUpperCase());

			return getControlTypeByDg(path);
		}else{
			return path;
		}

	}

}



package cn.sdh.entity;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import cn.sdh.common.base.AuditEntity;

/**
 * 角色类
 * @author 孙东辉
 */
@Entity
@Table(name="roles")
public class Role extends  AuditEntity{

	/**
	 * 
	 */
	private static final long serialVersionUID = 5459879676154477558L;

	@Id
	@Column(name="id")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ROLE")
	@SequenceGenerator(name = "SEQ_ROLE", sequenceName = "SEQ_ROLE", initialValue = 100, allocationSize = 1)
	private Long id;

	/**
	 * 角色名称
	 */
	@Column(name="rolename")
	private String roleName;

	/**
	 * 拥有的权限集合
	 */
	@ManyToMany(fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("level")
	@JoinTable(name="role_permission",joinColumns={@JoinColumn(name="roleid")},inverseJoinColumns={@JoinColumn(name="perid")})
	private List<Permission> permissionList = new ArrayList<Permission>();


	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getRoleName() {
		return roleName;
	}

	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}

	public List<Permission> getPermissionList() {
		return permissionList;
	}

	public void setPermissionList(List<Permission> permissionList) {
		this.permissionList = permissionList;
	}

}




[size=large]Account作为springsecrity的账户类必须实现UserDetails接口,实现的getAuthorities方法是告诉spring当前用户的角色,还有个自定义方法getSignPer用于获取当前用户的权限列表,Permission类有个方法getControlTypeByDg通过配置的jsUrl链接获取Extjs的组件类名,他们的用处后面就能看到,这里补充下我用的是Hibernate的注解方式,严格来讲项目中除了公共配置部分,其他包括Struts Spring等需要xml配置的我全用了注解,如果你对注解不是很了解用xml配置的形式也是可以的



用户通过springsecrity登录成功的时候,会把Account对象保存它的上下文,然后访问这个跳转到主页的action方法,action方法中从springsecrity上下文中获取到Account后通过getSignPer方法获取当前用户的权限(也就是菜单),下面就是用户cccq3y的菜单了


[/size]



/**
	 * 跳转到主页
	 * 
	 * @throws JSONException
	 */
	public String index() throws JSONException {

		entity = SpringSecurityUtils.getCurrentUser();

		List<Permission> perList = entity.getSignPer();

		HttpServletRequest request = ServletActionContext.getRequest();
		request.setAttribute("perList", perList);
		request.setAttribute("perListJson", JSONUtil.serialize(perList));

		return "index";
	}





[img]http://dl2.iteye.com/upload/attachment/0110/4020/9f8e88f9-fd69-3a63-a9ec-34ac79a172d8.jpg[/img]


[size=large]当用户点击新增确认按钮时,浏览器会向后台提交一个表单,url为account!save.action,首先会被springsecrity的MyFilterInvocationSecurityMetadataSource拦截到[/size]



package cn.sdh.audit;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import cn.sdh.common.exception.ServiceException;
import cn.sdh.entity.Permission;
import cn.sdh.entity.Role;
import cn.sdh.service.RoleService;
import cn.sdh.utils.MyCacheUtil;

/**
 * 告诉spring当前访问链接 需要什么权限 在这边定义
 * @author 孙东辉
 *
 */
@Service
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

	@Autowired
	private RoleService roleService;

	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {

		//这个是当前访问的链接
		String requestUrl = ((FilterInvocation) object).getRequestUrl();

		//设置哪些页面不需要权限就可访问
		if(requestUrl.indexOf("account!index.action") >= 0 
				|| requestUrl.indexOf("index.jsp") >= 0
				|| requestUrl.indexOf("permission!queryBtnListByControlType.action") >= 0
				|| requestUrl.indexOf("account!searchOnlineList.action")>=0
				|| requestUrl.indexOf("queryDicDataByKey.action")>=0){
			return null;
		}

		// 对于带参数的请求,截取?前面的uri
		int urlIndex = requestUrl.indexOf("?");

		if (urlIndex != -1) {
			requestUrl = requestUrl.substring(0, urlIndex);
		}

		//如果第一位是/ 去掉
		if(requestUrl.startsWith("/")){
			requestUrl = requestUrl.substring(1);
		}

		//从缓存中取当前系统的所有角色
		List<Role> roles = (List<Role>) MyCacheUtil.getRolesList();


		if(roles == null || roles.size()==0){//如果缓存中没有

			try {
				roles = roleService.query();

				//把角色放入缓存
				MyCacheUtil.setRolesList(roles);
			} catch (ServiceException e) {
				throw new IllegalArgumentException(e.getMsg());
			}
		}

		Collection<ConfigAttribute> c = new HashSet<ConfigAttribute>();
		//遍历所有角色
		List<Permission> permissionList = null;
		if(roles.size()>0){
			for(int i = 0;i<roles.size();i++){
				permissionList = roles.get(i).getPermissionList();

				for(int j = 0;j<permissionList.size();j++){
					//如果权限中的actionUrl包含当前访问的链接,当说明现在这个角色是可以访问该链接的
					if(permissionList.get(j)!=null&&permissionList.get(j).getActionUrl()!=null&&permissionList.get(j).getActionUrl().indexOf(requestUrl)>=0){
						ConfigAttribute configAttribute = new SecurityConfig(roles.get(i).getId()+"");
						c.add(configAttribute);
						break;
					}
				}

			}
		}else{
			return null;
		}

		//最后返回的是一个角色的集合,并且这些角色都是可以访问该链接的
		return c;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {

		return null;
	}

	public boolean supports(Class<?> clazz) {

		return true;
	}

}



[size=large]返回的角色中应该有一个是游客2的id,然后再被MyAccessDecisionManager拦截到[/size]


package cn.sdh.audit;

import java.util.Collection;
import java.util.Iterator;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

/**
 * 自定义访问决定器 控制用户能否访问该链接
 * @author sun
 *
 */
public class MyAccessDecisionManager implements AccessDecisionManager {


	public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {

		//如果访问的页面没有权限限制 那么不做拦截继续访问 如果未空说明该页面不需要任何角色
		// 注意这里的configAttributes 其实就是MyFilterInvocationSecurityMetadataSource返回的 
		if (configAttributes == null) {
			return;
		}

		//如果有权限限制 那么需要迭代权限 验证用户所拥有的权限是否包含 当前页面的访问权限
		Iterator<ConfigAttribute> ite = configAttributes.iterator();
		while (ite.hasNext()) {

			//获取访问页面需要的权限
			ConfigAttribute ca = ite.next();

			//获取访问页面需要的权限的权限名称
			String needRole = ((SecurityConfig) ca).getAttribute();

			//迭代用户所拥有的权限
			for (GrantedAuthority ga : authentication.getAuthorities()) {
				//如果用户的其中一个权限满足 访问链接需要的其中一个权限,那么访问将继续
				if (needRole.equals(ga.getAuthority())) {
					return;
				}
			}
		}
		//否则 访问将被终止
		throw new AccessDeniedException("没有权限访问");
	}

	public boolean supports(ConfigAttribute attribute) {
		// TODO Auto-generated method stub
		return true;
	}

	public boolean supports(Class<?> clazz) {
		// TODO Auto-generated method stub
		return true;
	}



}



[size=large]注释写个很清楚了,把当前用户所拥有的角色和MyFilterInvocationSecurityMetadataSource返回的访问当前链接需要哪些角色,如果包含说明当前用户能访问该链接了,再没抛AccessDeniedException错误的情况下验证都通过



最后再说下前端代码,首先主页的jsp要根据权限加载js文件


[/size]


<!-- 根据权限加载js文件 -->
	<s:iterator value="#request.perList" var="bean">
		<s:if test="#bean.jsUrl!=null">
			<script type="text/javascript" src="common/jscode/<s:property value="#bean.jsUrl"/>.js"></script>
		</s:if>
	</s:iterator>




[size=large]然后来感受下extjs4的强大之处了,首先我封装一个公共的权限工具条[/size]


/**
 * 权限按钮工具条
 */
Ext.define("app.base.auditbar", {
	extend : "Ext.toolbar.Toolbar",
	alias : 'widget.auditbar',
	initComponent : function() {
		var me = this;

		var call = function(){
			var sme = me;

			// 根据组件类型 获取它所有的按钮
			Ext.Ajax.request({
				url : 'permission!queryBtnListByControlType.action',
				params : {
					'entity.controlType' : me.compont
				},
				success : new app.ajaxHand({
					success : function(result,scope) {
						var btns = result.searchList;

						for ( var i = 0; i < btns.length; i++) {
							if(scope){
								sme = scope;
							}
							sme.insert(i, [ {
								xtype : btns[i].controlType,
								text : btns[i].text
							} ]);
						}
					}
				},sme)

			});
		};

		if(me.remote){
			call();
		}


		if(me.searchItems){
			if(!me.items){
				me.items = [];
			}
			me.items =me.items.concat(['->', {
				xtype : "searchItems",
				items : me.searchItems
			} ]);
		}

		me.callParent(me);
	}
});



[size=large]然后是grid基类[/size]


Ext.define("app.base.grid", {
	extend : "Ext.grid.Panel",

	//日期
	dateRender : function(){return Ext.util.Format.dateRenderer(app.constant.date_render);},

	//日期加时间
	datetimeRender : function(){return Ext.util.Format.dateRenderer(app.constant.datetime_render);},

	//单元格编辑插件
	editingPlugin : function(){ return Ext.create('Ext.grid.plugin.CellEditing',{});},

	//行编辑插件
	rowEditingPlugin : function(){return Ext.create('Ext.grid.plugin.RowEditing', {
        clicksToMoveEditor: 1,
        errorSummary : false,
        autoCancel: true
    });},

    //行复选框
    selModelPlugin : function(){return Ext.create("Ext.selection.CheckboxModel");},

	initComponent : function(){
		var me = this;
		if(me.paging){
			me.bbar = Ext.create('app.base.paging',{
				store:me.store
			});
		}
		me.tbar = Ext.create('app.base.auditbar',{
			compont : me.xtype,
			searchItems : me.searchItems,
			remote:me.auditbarEnable,
			items : me.btns
		});

		this.callParent();
	},

	//添加行
	addRow : function(){
		this.store.insert(0,new (Ext.ModelManager.getModel(this.model)));
		this.editing.cancelEdit();
		if(this.editing){
			this.editing.startEdit(0,0);
		}
	},

	//删除行
	deleteRow : function(){

		var recode = this.getSelectionModel().getSelection();

		this.store.remove(recode);
	},

	//验证选中行
	checkSelectRow : function(count,tip){
		if(!count){
			count = 1;
		}
		tip = tip || "请"+(count!=1?"至少":"")+"选择一行要删除的记录";

		var recode = this.getSelectionModel().getSelection();

		if(recode.length==0||(count==1&&recode.length>1)){
			app.alert(tip);
			return false;
		}

		var usedata = [];
		var ids = "";
		for(var i = 0;i<recode.length;i++){
			usedata.push(recode[i].data);
			ids += recode[i].data.id;
			if(i!=recode.length-1){
				ids += ",";
			}
		}
		usedata.unshift(ids);

		return usedata;
	}

});



[size=large]把当前组件的xtype作为参数,到后台获取对应的父级菜单,再根据用户拥有的按钮权限获取这个用户在当前组件的按钮权限,那么问题来了,我是如果通过xtype定位到那条权限数据的呢,真相是我在配置账号管理这个权限的时候配置的jsUrl为user/account/searchGrid然后通过上面Permission类自定义的getControlTypeByDg方法转成xtype,再来看看我的grid子类就清楚了[/size]


Ext.define("app.user.account.searchGrid", {
	extend : "app.user.account.grid",
	alias: 'widget.userAccountSearchGrid',

	initComponent : function(){
		var me = this;
		me.editing = me.rowEditingPlugin();
		Ext.apply(this,{
			plugins : [me.editing],
			paging : true,
			selModel : me.selModelPlugin(),
			searchItems :[{
    			fieldLabel : '用户名',
    			xtype : 'textfield',
    			labelAlign : 'right',
    			name : 'entity.username',
    			labelWidth : 45
    		},{
    			fieldLabel : '邮箱',
    			xtype : 'textfield',
    			labelAlign : 'right',
    			name : 'entity.email',
    			labelWidth : 45
    		},{
    			fieldLabel : '上次登录起',
    			xtype : 'datefield',
    			labelAlign : 'right',
    			name : 'entity.lastLoginTime1',
    			labelWidth : 75
    		},{
    			fieldLabel : '上次登录止',
    			xtype : 'datefield',
    			labelAlign : 'right',
    			name : 'entity.lastLoginTime2',
    			labelWidth : 75
    		}]
		});

		me.callParent();
	}
});



[size=large]alias:widget.userAccountSearchGrid,这样就能和后台的权限做对应了,而且在点击菜单树的时候同样用到这个功能,我会根据当前被点击菜单的jsUrl属性转义成xtype,然后很方便的加载对应的组件,就这么简单.最后展示下我的js文件目录




[img]http://dl2.iteye.com/upload/attachment/0110/4032/fa508ba8-ae76-36ea-bbce-faa413ed1be7.jpg[/img]