跟着汤阳光同志做一个OA系统(九):权限模块
2015-12-10 08:37
302 查看
权限:
控制功能的使用
Web应用中的权限:
l 权限就是控制功能的使用(功能对应着URL)。
l 对功能的控制就是对URL的访问控制。
l 在我们的程序中,一个功能对应一个或两个URL:
• 1,例如列表或删除功能,只对应一个URL.
• 2,例如添加或修改功能,对应两个URL:..add, ..addUI
权限方案:
用户 *----*
角色 *----*
权限
与权限相关的功能具体有哪些:
l 初始化数据就做一次,通过写一个安装文件,利用hibernate实现跨数据库安装)
• 权限数据。权限数据是不能增删改的,由你的系统决定,有哪些功能就有哪些权限,在安装的时候就确定。
• 超级管理员。超级管理员担负最初为别人分配权限的职责。一般有权限的系统都有超级管理员,他拥有所有的权限,并且别人不能删除他的权限。
l 分配权限
• 给角色分配权限。
• 用户的权限就是用户所有角色的权限。
l 使用权限
• 1,登录、注销、主页面。
• 2,左侧的菜单是根据权限显示的。
• 3,右侧页面中的链接是根据权限显示的。
• 4,拦截每一个action请求,验证用户是否有权限访问。
权限的分类
权限类设计
public class Privilege implementsjava.io.Serializable{
private Long id;
private String url;
private String name; //
权限名称
private Set<Role>roles = new HashSet<Role>();//与角色(岗位)的关系
private Privilege parent;//
上级权限
privateSet<Privilege> children = new HashSet<Privilege>(); //
下级权限
public Privilege() {
}
public Privilege(Stringname, String url, Privilege parent) {
this.name =name;
this.url = url;
this.parent =parent;
}
。。。
}
权限是根据系统的功能确定的,你有什么样的功能,需要怎么样控制,在你的系统确定之后就被定死了,权限数据也就确定了。可以通过一个安装文件一键写入数据。当然也可以通过写脚本的方式。
/**
*本文件是用于系统初始化数据的,在安装的时候执行一遍
*/
@Component
public class Installer {
@Resource
private SessionFactorysessionFactory;
/**
*
执行安装
*/
@Transactional
public void install() {
Session session= sessionFactory.getCurrentSession();
System.out.println("开始安装系统数据");
//==============================================================
//
保存超级管理员用户
User user = newUser();
user.setLoginName("admin");
user.setName("超级管理员");
user.setPassword(DigestUtils.md5Hex("admin"));
session.save(user);//
保存
System.out.println("超级管理员安装完毕");
//==============================================================
//
保存权限数据
Privilege menu,menu1, menu2, menu3, menu4, menu5;
//--------------------
menu = newPrivilege("系统管理", null,null);
menu1 = new Privilege("岗位管理","/role_list", menu);
menu2 = newPrivilege("部门管理","/department_list", menu);
menu3 = newPrivilege("用户管理","/user_list", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(newPrivilege("岗位列表","/role_list", menu1));
session.save(newPrivilege("岗位删除","/role_delete", menu1));
session.save(newPrivilege("岗位添加","/role_add", menu1));
session.save(newPrivilege("岗位修改","/role_edit", menu1));
session.save(newPrivilege("部门列表","/department_list", menu2));
session.save(newPrivilege("部门删除","/department_delete", menu2));
session.save(newPrivilege("部门添加","/department_add", menu2));
session.save(newPrivilege("部门修改","/department_edit", menu2));
session.save(newPrivilege("用户列表","/user_list", menu3));
session.save(newPrivilege("用户删除","/user_delete", menu3));
session.save(newPrivilege("用户添加","/user_add", menu3));
session.save(newPrivilege("用户修改","/user_edit", menu3));
session.save(newPrivilege("初始化密码","/user_initPassword", menu3));
//--------------------
menu = newPrivilege("网上交流", null,null);
menu1 = newPrivilege("论坛管理","/forumManage_list", menu);
menu2 = newPrivilege("论坛","/forum_list", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
//--------------------
menu = newPrivilege("审批流转", null,null);
menu1 = newPrivilege("审批流程管理","/processDefinition_list", menu);
menu2 = newPrivilege("申请模板管理","/template_list", menu);
menu3 = new Privilege("起草申请","/flow_templateList", menu);
menu4 = newPrivilege("待我审批","/flow_myTaskList", menu);
menu5 = newPrivilege("我的申请查询","/flow_myApplicationList", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(menu4);
session.save(menu5);
System.out.println("权限数据安装完毕");
}
public static voidmain(String[] args) {
ApplicationContextac = new ClassPathXmlApplicationContext("applicationContext.xml");
Installerinstaller = (Installer) ac.getBean("installer");
installer.install();
}
}
User中添加判断权限的方法
/**
*
判断本用户是否有指定URL的权限
*
* @param privUrl
* @return
*/
public booleanhasPrivilegeByUrl(String privUrl) {
//
超级管理有所有的权限
if (isAdmin()) {
returntrue;
}
// >>
去掉后面的参数
int pos =privUrl.indexOf("?");
if (pos > -1){
privUrl= privUrl.substring(0, pos);
}
// >>
去掉UI后缀
if(privUrl.endsWith("UI")) {
privUrl= privUrl.substring(0, privUrl.length() - 2);
}
//
如果本URL不需要控制,则登录用户就可以使用
Collection<String>allPrivilegeUrls = (Collection<String>)ActionContext.getContext().getApplication().get("allPrivilegeUrls");
if(!allPrivilegeUrls.contains(privUrl)) {//本地址不在所有要控制的地址中(就是要控制的功能),不控制那么我登陆之后就能使用
returntrue;
} else {
//
普通用户要判断是否含有这个权限
for(Role role : roles) {
for(Privilege priv : role.getPrivileges()) {
if(privUrl.equals(priv.getUrl())) {
returntrue;
}
}
}
returnfalse;
}
}
/**
*
判断本用户是否有指定名称的权限
*
* @param name
* @return
*/
public booleanhasPrivilegeByName(String name) {
//
超级管理有所有的权限
if (isAdmin()) {
returntrue;
}
//
普通用户要判断是否含有这个权限
for (Role role :roles) {
for(Privilege priv : role.getPrivileges()) {
if(priv.getName().equals(name)) {
returntrue;
}
}
}
return false;
}
/**
*
判断本用户是否是超级管理员
*
* @return
*/
public boolean isAdmin() {
return"admin".equals(loginName);
}
左边的菜单是根据用户的权限显示的
<ul id="MenuUl">
<%-- 显示一级菜单 --%>
<s:iteratorvalue="#application.topPrivilegeList">
<!--循环所有的权限,我有这个权限那就显示:在用户中增加一个判断是否有顶级权限,name就是权限的名字 -->
<s:iftest="#session.user.hasPrivilegeByName(name)">
<liclass="level1">
<divonClick="menuClick(this);" class="level1Style">
<!-- 通过id和图片的名字结合起来这个技巧简单的实现不同的菜单不同的图片
-->
<imgsrc="style/images/MenuIcon/${id}.gif" class="Icon" />
${name}
</div>
<ulstyle="" class="MenuLevel2" id="aa">
<%--显示二级菜单 --%>
<s:iteratorvalue="children">
<!-- 在用户中增加一个判断是否有二级权限,name就是权限的名字 -->
<s:iftest="#session.user.hasPrivilegeByName(name)">
<liclass="level2">
<divclass="level2Style">
<imgsrc="style/images/MenuIcon/menu_arrow_single.gif" />
<atarget="right" href="${pageContext.request.contextPath}${url}.action"> ${name}</a>
</div>
</li>
</s:if>
</s:iterator>
</ul>
</li>
</s:if>
</s:iterator>
</ul>
添加ServletContextListener在Tomcat启动的时候就执行一次,把需要准备的权限准备好。
/**
*
这个监听器是由tomcat通过反射生成的实例
*
与spring的容器无关,所以通过注解是不能注入对象给这个容器的,
*
加上component注解之后,spring也会生成实例,但是与这个实例没关系
*
所以要通过WebApplicationContextUtils获取spring的容器对象+
* @author
熊诗言
*
*/
public class InitListener implements ServletContextListener {
public voidcontextInitialized(ServletContextEvent sce) {
//
获取容器与相关的Service对象
ApplicationContextac =
WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
PrivilegeServiceprivilegeService = (PrivilegeService)ac.getBean("privilegeServiceImpl");
//
准备数据:topPrivilegeList,用于显示左边的菜单(有权限才显示)
/***
*
这里由于在页面中需要访问privilege的children属性,如果用了懒加载特性,
*
即是使用了Spring的OpensessionInViewFilter,也不好使。因为这个对象是在监听器中而非请求中获取到的,
*
获取到之后session就关闭了。比如容器启动后很久才有人访问,访问的时候jsp中获取children属性就会出现懒加载问题。
*
所以在这里必须把懒加载的特性关闭。
*
*
过滤器只能解决同一个请求的懒加载问题,懒加载异常的根本就是session关闭
*/
List<Privilege>topPrivilegeList = privilegeService.findTopList();
sce.getServletContext().setAttribute("topPrivilegeList",topPrivilegeList);
System.out.println("------------>已准备好顶级菜单topPrivilegeList<------------");
//
准备数据:allPrivilegeUrls,这是所有需要控制的url,在这个集合中的所有都需要控制,你的权限中有这个url,那么你能访问,否则不能访问,没在这个集合中的你都能访问,比如主页、注销。
Collection<String>allPrivilegeUrls = privilegeService.getAllPrivilegeUrls();
sce.getServletContext().setAttribute("allPrivilegeUrls",allPrivilegeUrls);
System.out.println("------------>已准备菜单超链接allPrivilegeUrls<------------");
}
public voidcontextDestroyed(ServletContextEvent arg0) {
}
}
在web.xml中注明listner
<!-- spring的初始化容器的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<!--
用于做初始化工作的监听器,一定要配置到Spring的ContextLoaderListener之后,因为要用到Spring的容器对象
-->
<listener>
<listener-class>com.xsy.oa.utils.InitListener</listener-class>
</listener>
右边的链接是根据是否有这个权限显示的
packageorg.apache.struts2.views.jsp.ui;
。。。
/**
*这个自定义标签用于覆盖struts2的a标签(因为包名类名都一样),
*会先在classpath下找到这个类,然后就不会再在jar包中找。
*从tld文件中找到标签的声明定位到这个类。
*
*其实更保险的做法就是生成jar之后考入jar包覆盖原来的文件
*或者完全自定义标签(用新的prefix)
* @see Anchor
*/
public class AnchorTag extends AbstractClosingTag {
。。。
@Override
public int doEndTag()throws JspException {
//
当前登录用户
User user = (User)pageContext.getSession().getAttribute("user");
//
当前准备显示的链接对应的权限URL
// >>
在开头加上'/'
String privUrl ="/" + action;
if (user.hasPrivilegeByUrl(privUrl)){
returnsuper.doEndTag(); //
正常的生成并显示超链接标签,并继续执行页面中后面的代码
} else {
returnEVAL_PAGE; //
不生成与显示超链接标签,只是继续执行页面中后面的代码
}
}
。。。
}
根据权限显示并不是终极目标,因为我还是可以通过直接访问地址的方式访问你的功能,最重要的就是通过拦截器拦截所有的action,判断权限。
public class CheckPrivilegeInterceptor extends AbstractInterceptor {
public Stringintercept(ActionInvocation invocation) throws Exception {
//System.out.println("--------->
之前");
// String result= invocation.invoke(); //
放行
//System.out.println("--------->
之后");
// returnresult;
//
获取信息
User user =(User) ActionContext.getContext().getSession().get("user"); //
当前登录用户
String namespace= invocation.getProxy().getNamespace();
StringactionName = invocation.getProxy().getActionName();
String privUrl =namespace + actionName; //
对应的权限URL
//
如果未登录
if (user ==null) {
if(privUrl.startsWith("/user_login")) { // "/user_loginUI","/user_login"
//如果是去登录,就放行
returninvocation.invoke();
} else{
//如果不是去登录,就转到登录页面
return"loginUI";
}
}else {//
如果已登录,就判断权限
if(user.hasPrivilegeByUrl(privUrl)) {
//如果有权限,就放行
returninvocation.invoke();
} else{
//如果没有权限,就转到提示页面
return"noPrivilegeError";
}
}
}
}
分配权限的权限树
<%@ page language="java" import="java.util.*"pageEncoding="utf-8"%>
<html>
<head>
<title>配置权限</title>
<%@ includefile="/WEB-INF/jsp/public/commons.jspf" %>
<scriptlanguage="javascript"src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script>
<linktype="text/css" rel="stylesheet"href="${pageContext.request.contextPath}/style/blue/file.css" />
<linktype="text/css" rel="stylesheet"href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css"/>
<script type="text/javascript">
$(function(){
//
指定事件处理函数
$("[name=privilegeIds]").click(function(){
//当选中或取消一个权限时,也同时选中或取消所有的下级权限
$(this).siblings("ul").find("input").attr("checked",this.checked);
//当选中一个权限时,也要选中所有的直接上级权限
if(this.checked== true){
$(this).parents("li").children("input").attr("checked",true);
}
});
});
</script>
</head>
<body>
<!-- 标题显示 -->
<div id="Title_bar">
<divid="Title_bar_Head">
<divid="Title_Head"></div>
<divid="Title"><!--页面标题-->
<imgborder="0" width="13" height="13"src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/>配置权限
</div>
<divid="Title_End"></div>
</div>
</div>
<!--显示表单内容-->
<div id=MainArea>
<s:formaction="role_setPrivilege">
<s:hidden name="id"></s:hidden>
<divclass="ItemBlock_Title1"><!--
信息说明 --><divclass="ItemBlock_Title1">
<img border="0" width="4"height="7"src="${pageContext.request.contextPath}/style/blue/images/item_point.gif"/>
正在为【${name}】配置权限 </div>
</div>
<!--
表单内容显示 -->
<divclass="ItemBlockBorder">
<divclass="ItemBlock">
<tablecellpadding="0" cellspacing="0"class="mainForm">
<!--表头-->
<thead>
<tralign="LEFT" valign="MIDDLE" id="TableTitle">
<tdwidth="300px" style="padding-left: 7px;">
<!--如果把全选元素的id指定为selectAll,并且有函数selectAll(),就会有错。因为有一种用法:可以直接用id引用元素
-->
<inputtype="checkbox" id="cbSelectAll"onClick="$('[name=privilegeIds]').attr('checked', this.checked)"/>
<labelfor="cbSelectAll">全选</label>
</td>
</tr>
</thead>
<!--显示数据列表-->
<tbodyid="TableData">
<trclass="TableDetail1">
<!--显示权限树 -->
<td>
<!-- 使用它的目的是为了回显,但是换行都做不了
<s:checkboxlistname="privilegeIds" list="#privilegeList"listKey="id" listValue="name"></s:checkboxlist>
-->
<%-- 自己实现回显和换行
<s:iteratorvalue="#privilegeList">
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}"
<s:propertyvalue="%{id in privilegeIds ? 'checked' : ''}"/>
/>
<labelfor="cb_${id}">${name}</label>
<br/>
</s:iterator>
--%>
<!—通过treeview控件显示树状结构内容
-->
<ul id="tree">
<s:iteratorvalue="#application.topPrivilegeList">
<li>
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />
<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>
<ul>
<s:iteratorvalue="children">
<li>
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />
<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>
<ul>
<s:iteratorvalue="children">
<li>
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />
<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>
</li>
</s:iterator>
</ul>
</li>
</s:iterator>
</ul>
</li>
</s:iterator>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!--
表单操作 -->
<divid="InputDetailBar">
<inputtype="image"src="${pageContext.request.contextPath}/style/images/save.png"/>
<ahref="javascript:history.go(-1);"><imgsrc="${pageContext.request.contextPath}/style/images/goBack.png"/></a>
</div>
</s:form>
</div>
</body>
</html>
控制功能的使用
Web应用中的权限:
l 权限就是控制功能的使用(功能对应着URL)。
l 对功能的控制就是对URL的访问控制。
l 在我们的程序中,一个功能对应一个或两个URL:
• 1,例如列表或删除功能,只对应一个URL.
• 2,例如添加或修改功能,对应两个URL:..add, ..addUI
权限方案:
用户 *----*
角色 *----*
权限
与权限相关的功能具体有哪些:
l 初始化数据就做一次,通过写一个安装文件,利用hibernate实现跨数据库安装)
• 权限数据。权限数据是不能增删改的,由你的系统决定,有哪些功能就有哪些权限,在安装的时候就确定。
• 超级管理员。超级管理员担负最初为别人分配权限的职责。一般有权限的系统都有超级管理员,他拥有所有的权限,并且别人不能删除他的权限。
l 分配权限
• 给角色分配权限。
• 用户的权限就是用户所有角色的权限。
l 使用权限
• 1,登录、注销、主页面。
• 2,左侧的菜单是根据权限显示的。
• 3,右侧页面中的链接是根据权限显示的。
• 4,拦截每一个action请求,验证用户是否有权限访问。
权限的分类
权限类设计
public class Privilege implementsjava.io.Serializable{
private Long id;
private String url;
private String name; //
权限名称
private Set<Role>roles = new HashSet<Role>();//与角色(岗位)的关系
private Privilege parent;//
上级权限
privateSet<Privilege> children = new HashSet<Privilege>(); //
下级权限
public Privilege() {
}
public Privilege(Stringname, String url, Privilege parent) {
this.name =name;
this.url = url;
this.parent =parent;
}
。。。
}
权限是根据系统的功能确定的,你有什么样的功能,需要怎么样控制,在你的系统确定之后就被定死了,权限数据也就确定了。可以通过一个安装文件一键写入数据。当然也可以通过写脚本的方式。
/**
*本文件是用于系统初始化数据的,在安装的时候执行一遍
*/
@Component
public class Installer {
@Resource
private SessionFactorysessionFactory;
/**
*
执行安装
*/
@Transactional
public void install() {
Session session= sessionFactory.getCurrentSession();
System.out.println("开始安装系统数据");
//==============================================================
//
保存超级管理员用户
User user = newUser();
user.setLoginName("admin");
user.setName("超级管理员");
user.setPassword(DigestUtils.md5Hex("admin"));
session.save(user);//
保存
System.out.println("超级管理员安装完毕");
//==============================================================
//
保存权限数据
Privilege menu,menu1, menu2, menu3, menu4, menu5;
//--------------------
menu = newPrivilege("系统管理", null,null);
menu1 = new Privilege("岗位管理","/role_list", menu);
menu2 = newPrivilege("部门管理","/department_list", menu);
menu3 = newPrivilege("用户管理","/user_list", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(newPrivilege("岗位列表","/role_list", menu1));
session.save(newPrivilege("岗位删除","/role_delete", menu1));
session.save(newPrivilege("岗位添加","/role_add", menu1));
session.save(newPrivilege("岗位修改","/role_edit", menu1));
session.save(newPrivilege("部门列表","/department_list", menu2));
session.save(newPrivilege("部门删除","/department_delete", menu2));
session.save(newPrivilege("部门添加","/department_add", menu2));
session.save(newPrivilege("部门修改","/department_edit", menu2));
session.save(newPrivilege("用户列表","/user_list", menu3));
session.save(newPrivilege("用户删除","/user_delete", menu3));
session.save(newPrivilege("用户添加","/user_add", menu3));
session.save(newPrivilege("用户修改","/user_edit", menu3));
session.save(newPrivilege("初始化密码","/user_initPassword", menu3));
//--------------------
menu = newPrivilege("网上交流", null,null);
menu1 = newPrivilege("论坛管理","/forumManage_list", menu);
menu2 = newPrivilege("论坛","/forum_list", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
//--------------------
menu = newPrivilege("审批流转", null,null);
menu1 = newPrivilege("审批流程管理","/processDefinition_list", menu);
menu2 = newPrivilege("申请模板管理","/template_list", menu);
menu3 = new Privilege("起草申请","/flow_templateList", menu);
menu4 = newPrivilege("待我审批","/flow_myTaskList", menu);
menu5 = newPrivilege("我的申请查询","/flow_myApplicationList", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(menu4);
session.save(menu5);
System.out.println("权限数据安装完毕");
}
public static voidmain(String[] args) {
ApplicationContextac = new ClassPathXmlApplicationContext("applicationContext.xml");
Installerinstaller = (Installer) ac.getBean("installer");
installer.install();
}
}
User中添加判断权限的方法
/**
*
判断本用户是否有指定URL的权限
*
* @param privUrl
* @return
*/
public booleanhasPrivilegeByUrl(String privUrl) {
//
超级管理有所有的权限
if (isAdmin()) {
returntrue;
}
// >>
去掉后面的参数
int pos =privUrl.indexOf("?");
if (pos > -1){
privUrl= privUrl.substring(0, pos);
}
// >>
去掉UI后缀
if(privUrl.endsWith("UI")) {
privUrl= privUrl.substring(0, privUrl.length() - 2);
}
//
如果本URL不需要控制,则登录用户就可以使用
Collection<String>allPrivilegeUrls = (Collection<String>)ActionContext.getContext().getApplication().get("allPrivilegeUrls");
if(!allPrivilegeUrls.contains(privUrl)) {//本地址不在所有要控制的地址中(就是要控制的功能),不控制那么我登陆之后就能使用
returntrue;
} else {
//
普通用户要判断是否含有这个权限
for(Role role : roles) {
for(Privilege priv : role.getPrivileges()) {
if(privUrl.equals(priv.getUrl())) {
returntrue;
}
}
}
returnfalse;
}
}
/**
*
判断本用户是否有指定名称的权限
*
* @param name
* @return
*/
public booleanhasPrivilegeByName(String name) {
//
超级管理有所有的权限
if (isAdmin()) {
returntrue;
}
//
普通用户要判断是否含有这个权限
for (Role role :roles) {
for(Privilege priv : role.getPrivileges()) {
if(priv.getName().equals(name)) {
returntrue;
}
}
}
return false;
}
/**
*
判断本用户是否是超级管理员
*
* @return
*/
public boolean isAdmin() {
return"admin".equals(loginName);
}
左边的菜单是根据用户的权限显示的
<ul id="MenuUl">
<%-- 显示一级菜单 --%>
<s:iteratorvalue="#application.topPrivilegeList">
<!--循环所有的权限,我有这个权限那就显示:在用户中增加一个判断是否有顶级权限,name就是权限的名字 -->
<s:iftest="#session.user.hasPrivilegeByName(name)">
<liclass="level1">
<divonClick="menuClick(this);" class="level1Style">
<!-- 通过id和图片的名字结合起来这个技巧简单的实现不同的菜单不同的图片
-->
<imgsrc="style/images/MenuIcon/${id}.gif" class="Icon" />
${name}
</div>
<ulstyle="" class="MenuLevel2" id="aa">
<%--显示二级菜单 --%>
<s:iteratorvalue="children">
<!-- 在用户中增加一个判断是否有二级权限,name就是权限的名字 -->
<s:iftest="#session.user.hasPrivilegeByName(name)">
<liclass="level2">
<divclass="level2Style">
<imgsrc="style/images/MenuIcon/menu_arrow_single.gif" />
<atarget="right" href="${pageContext.request.contextPath}${url}.action"> ${name}</a>
</div>
</li>
</s:if>
</s:iterator>
</ul>
</li>
</s:if>
</s:iterator>
</ul>
添加ServletContextListener在Tomcat启动的时候就执行一次,把需要准备的权限准备好。
/**
*
这个监听器是由tomcat通过反射生成的实例
*
与spring的容器无关,所以通过注解是不能注入对象给这个容器的,
*
加上component注解之后,spring也会生成实例,但是与这个实例没关系
*
所以要通过WebApplicationContextUtils获取spring的容器对象+
* @author
熊诗言
*
*/
public class InitListener implements ServletContextListener {
public voidcontextInitialized(ServletContextEvent sce) {
//
获取容器与相关的Service对象
ApplicationContextac =
WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
PrivilegeServiceprivilegeService = (PrivilegeService)ac.getBean("privilegeServiceImpl");
//
准备数据:topPrivilegeList,用于显示左边的菜单(有权限才显示)
/***
*
这里由于在页面中需要访问privilege的children属性,如果用了懒加载特性,
*
即是使用了Spring的OpensessionInViewFilter,也不好使。因为这个对象是在监听器中而非请求中获取到的,
*
获取到之后session就关闭了。比如容器启动后很久才有人访问,访问的时候jsp中获取children属性就会出现懒加载问题。
*
所以在这里必须把懒加载的特性关闭。
*
*
过滤器只能解决同一个请求的懒加载问题,懒加载异常的根本就是session关闭
*/
List<Privilege>topPrivilegeList = privilegeService.findTopList();
sce.getServletContext().setAttribute("topPrivilegeList",topPrivilegeList);
System.out.println("------------>已准备好顶级菜单topPrivilegeList<------------");
//
准备数据:allPrivilegeUrls,这是所有需要控制的url,在这个集合中的所有都需要控制,你的权限中有这个url,那么你能访问,否则不能访问,没在这个集合中的你都能访问,比如主页、注销。
Collection<String>allPrivilegeUrls = privilegeService.getAllPrivilegeUrls();
sce.getServletContext().setAttribute("allPrivilegeUrls",allPrivilegeUrls);
System.out.println("------------>已准备菜单超链接allPrivilegeUrls<------------");
}
public voidcontextDestroyed(ServletContextEvent arg0) {
}
}
在web.xml中注明listner
<!-- spring的初始化容器的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<!--
用于做初始化工作的监听器,一定要配置到Spring的ContextLoaderListener之后,因为要用到Spring的容器对象
-->
<listener>
<listener-class>com.xsy.oa.utils.InitListener</listener-class>
</listener>
右边的链接是根据是否有这个权限显示的
packageorg.apache.struts2.views.jsp.ui;
。。。
/**
*这个自定义标签用于覆盖struts2的a标签(因为包名类名都一样),
*会先在classpath下找到这个类,然后就不会再在jar包中找。
*从tld文件中找到标签的声明定位到这个类。
*
*其实更保险的做法就是生成jar之后考入jar包覆盖原来的文件
*或者完全自定义标签(用新的prefix)
* @see Anchor
*/
public class AnchorTag extends AbstractClosingTag {
。。。
@Override
public int doEndTag()throws JspException {
//
当前登录用户
User user = (User)pageContext.getSession().getAttribute("user");
//
当前准备显示的链接对应的权限URL
// >>
在开头加上'/'
String privUrl ="/" + action;
if (user.hasPrivilegeByUrl(privUrl)){
returnsuper.doEndTag(); //
正常的生成并显示超链接标签,并继续执行页面中后面的代码
} else {
returnEVAL_PAGE; //
不生成与显示超链接标签,只是继续执行页面中后面的代码
}
}
。。。
}
根据权限显示并不是终极目标,因为我还是可以通过直接访问地址的方式访问你的功能,最重要的就是通过拦截器拦截所有的action,判断权限。
public class CheckPrivilegeInterceptor extends AbstractInterceptor {
public Stringintercept(ActionInvocation invocation) throws Exception {
//System.out.println("--------->
之前");
// String result= invocation.invoke(); //
放行
//System.out.println("--------->
之后");
// returnresult;
//
获取信息
User user =(User) ActionContext.getContext().getSession().get("user"); //
当前登录用户
String namespace= invocation.getProxy().getNamespace();
StringactionName = invocation.getProxy().getActionName();
String privUrl =namespace + actionName; //
对应的权限URL
//
如果未登录
if (user ==null) {
if(privUrl.startsWith("/user_login")) { // "/user_loginUI","/user_login"
//如果是去登录,就放行
returninvocation.invoke();
} else{
//如果不是去登录,就转到登录页面
return"loginUI";
}
}else {//
如果已登录,就判断权限
if(user.hasPrivilegeByUrl(privUrl)) {
//如果有权限,就放行
returninvocation.invoke();
} else{
//如果没有权限,就转到提示页面
return"noPrivilegeError";
}
}
}
}
分配权限的权限树
<%@ page language="java" import="java.util.*"pageEncoding="utf-8"%>
<html>
<head>
<title>配置权限</title>
<%@ includefile="/WEB-INF/jsp/public/commons.jspf" %>
<scriptlanguage="javascript"src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script>
<linktype="text/css" rel="stylesheet"href="${pageContext.request.contextPath}/style/blue/file.css" />
<linktype="text/css" rel="stylesheet"href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css"/>
<script type="text/javascript">
$(function(){
//
指定事件处理函数
$("[name=privilegeIds]").click(function(){
//当选中或取消一个权限时,也同时选中或取消所有的下级权限
$(this).siblings("ul").find("input").attr("checked",this.checked);
//当选中一个权限时,也要选中所有的直接上级权限
if(this.checked== true){
$(this).parents("li").children("input").attr("checked",true);
}
});
});
</script>
</head>
<body>
<!-- 标题显示 -->
<div id="Title_bar">
<divid="Title_bar_Head">
<divid="Title_Head"></div>
<divid="Title"><!--页面标题-->
<imgborder="0" width="13" height="13"src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/>配置权限
</div>
<divid="Title_End"></div>
</div>
</div>
<!--显示表单内容-->
<div id=MainArea>
<s:formaction="role_setPrivilege">
<s:hidden name="id"></s:hidden>
<divclass="ItemBlock_Title1"><!--
信息说明 --><divclass="ItemBlock_Title1">
<img border="0" width="4"height="7"src="${pageContext.request.contextPath}/style/blue/images/item_point.gif"/>
正在为【${name}】配置权限 </div>
</div>
<!--
表单内容显示 -->
<divclass="ItemBlockBorder">
<divclass="ItemBlock">
<tablecellpadding="0" cellspacing="0"class="mainForm">
<!--表头-->
<thead>
<tralign="LEFT" valign="MIDDLE" id="TableTitle">
<tdwidth="300px" style="padding-left: 7px;">
<!--如果把全选元素的id指定为selectAll,并且有函数selectAll(),就会有错。因为有一种用法:可以直接用id引用元素
-->
<inputtype="checkbox" id="cbSelectAll"onClick="$('[name=privilegeIds]').attr('checked', this.checked)"/>
<labelfor="cbSelectAll">全选</label>
</td>
</tr>
</thead>
<!--显示数据列表-->
<tbodyid="TableData">
<trclass="TableDetail1">
<!--显示权限树 -->
<td>
<!-- 使用它的目的是为了回显,但是换行都做不了
<s:checkboxlistname="privilegeIds" list="#privilegeList"listKey="id" listValue="name"></s:checkboxlist>
-->
<%-- 自己实现回显和换行
<s:iteratorvalue="#privilegeList">
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}"
<s:propertyvalue="%{id in privilegeIds ? 'checked' : ''}"/>
/>
<labelfor="cb_${id}">${name}</label>
<br/>
</s:iterator>
--%>
<!—通过treeview控件显示树状结构内容
-->
<ul id="tree">
<s:iteratorvalue="#application.topPrivilegeList">
<li>
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />
<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>
<ul>
<s:iteratorvalue="children">
<li>
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />
<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>
<ul>
<s:iteratorvalue="children">
<li>
<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />
<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>
</li>
</s:iterator>
</ul>
</li>
</s:iterator>
</ul>
</li>
</s:iterator>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!--
表单操作 -->
<divid="InputDetailBar">
<inputtype="image"src="${pageContext.request.contextPath}/style/images/save.png"/>
<ahref="javascript:history.go(-1);"><imgsrc="${pageContext.request.contextPath}/style/images/goBack.png"/></a>
</div>
</s:form>
</div>
</body>
</html>
相关文章推荐
- JavaScript入门
- 跟着汤阳光同志做一个OA系统(八):抽取页面公共部分、提取BaseAction、ModelDriven支持、Service和DAO合并、BaseAction中Service声明、非常好的增删改查流程
- leetcode Reverse Bits
- SAP存货分析报表
- SAP存货分析报表
- Linux同步目录 保留文件修改时间和权限 rsync
- SAP存货分析报表
- 高并发唯一ID解决方案
- #读书笔记#Illustrated C# 2012第17章 Generics泛型(1)
- Linux基本命令
- 跟着汤阳光同志做一个OA系统(七):树形处理(递归)
- 跟着汤阳光同志做一个OA系统(六):系统管理、实体映射、类图设计
- 2015年win10共发布135个安全补丁 创历年之最
- 嵌入式audio基础(一)接口
- 面向对象 代码
- Android 快速开发框架xUtils
- LeetCode(102) Binary Tree Level Order Traversal解题报告
- 跟着汤阳光同志做一个OA系统(五):Struts2的整体回顾
- POJ-2871
- C# 如何实现带消息数的App图标