Day04系统权限
-
介绍
在Web应用中,控制权限就是控制URL的访问。
- 实现步骤:
超级管理员:登录名为admin,有所有的权限,他的权限不需要分配,也不能取消。
二.初始化数据
- 创建JavaBean:
实体类图:
Privilege.java:
package cn.itcast.oa.domain; import java.util.HashSet; import java.util.Set; /* * 实体:权限 */ public class Privilege {
private Long id; private String url; private String name;
private Set<Role> roles = new HashSet<Role>(); //权限与角色 多对多
private Privilege parent; //子权限与父权限 多对一 private Set<Privilege> children = new HashSet<Privilege>(); //父权限与子权限 一对多
public Privilege(String name, String url, Privilege parent) { this.name = name; this.url = url; this.parent = parent; }
public Privilege() { }
public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } public Privilege getParent() { return parent; } public void setParent(Privilege parent) { this.parent = parent; } public Set<Privilege> getChildren() { return children; } public void setChildren(Set<Privilege> children) { this.children = children; } } |
Tips:
set集合要new,因为他的getRoles方法要返回一个空的集合而不是null,这样可以避免很多空指针异常.而parent对象不能new,关联一个对象,你要new一个对象的话,就只有一个关联的,而集合不同.关联的不是集合而是集合中的多个元素,集合只是一个容器所以集合这个容器可以有,但里面不能有对象.
Role.java:(要新增下面这条代码,还要加上get,set方法)
private Set<Privilege> privileges = new HashSet<Privilege>(); //角色与权限 多对多 |
Privilege.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.itcast.oa.domain"> <class name="Privilege" table="itcast_privilege"> <id name="id"> <generator class="native"></generator> </id>
<property name="url" column="url"></property> <property name="name" column="name"></property>
<!-- parent属性,表达的是本对象与Privilege(parent)的多对一关系 --> <many-to-one name="parent" class="Privilege" column="parentId"></many-to-one>
<!-- children属性,表达的是本对象与Privilege(children)的一对多关系 --> <set name="children"> <key column="parentId"></key> <one-to-many class="Privilege"/> </set>
<!-- roles属性,表达的是本对象与Role的多对多关系 --> <set name="roles" table="itcast_role_privilege"> <key column="privilegeId"></key> <many-to-many class="Role" column="roleId"></many-to-many> </set>
</class> </hibernate-mapping> |
Role.hbm.xml:(要新增以下这些代码)
<!-- privileges属性,表达的是本对象与Privilege的多对多关系 --> <set name="privileges" table="itcast_role_privilege"> <key column="roleId"></key> <many-to-many class="Privilege" column="privilegeId"></many-to-many> </set> |
Hibernate.cfg.xml:
<mapping resource="cn/itcast/oa/domain/Privilege.hbm.xml"/> |
最后测试一下即可:
TestSpring:
package cn.itcast.oa.test;
import org.hibernate.SessionFactory; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
private ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//测试SessionFactory @Test public void testSessionFactory() throws Exception{ SessionFactory sf = (SessionFactory) ac.getBean("sessionFactory"); System.out.println(sf.openSession()); }
//测试事务管理 @Test public void testTx() throws Exception{ TestService testService = (TestService) ac.getBean("testService"); testService.saveTwoUsers(); }
//测试Action对象的管理 @Test public void testAction() throws Exception{ TestAction testAction = (TestAction) ac.getBean("testAction"); System.out.println(testAction); } } |
-
初始化类:
Installer:
package cn.itcast.oa.installer;
import javax.annotation.Resource;
import org.apache.commons.codec.digest.DigestUtils;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import cn.itcast.oa.domain.Privilege;
import cn.itcast.oa.domain.User;
@Component
@SuppressWarnings("unused")
public class Installer {
@Resource
private SessionFactory sessionFactory;
@Transactional
public void install() {
Session session = sessionFactory.getCurrentSession();
// ================================
// 1.超级管理员
User user = new User();
user.setLoginName("admin");
user.setName("超级管理员");
user.setPassword(DigestUtils.md5Hex("admin")); // 密码要使用MD5摘要
session.save(user); // 保存
// 2.权限数据
Privilege menu, menu1, menu2, menu3, menu4, menu5;
menu = new Privilege("系统管理", null, null);
menu1 = new Privilege("岗位管理", "/role_list", menu);
menu2 = new Privilege("部门管理", "/department_list", menu);
menu3 = new Privilege("用户管理", "/user_list", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(new Privilege("岗位列表", "/role_list", menu1));
session.save(new Privilege("岗位删除", "/role_delete", menu1));
session.save(new Privilege("岗位添加", "/role_add", menu1));
session.save(new Privilege("岗位修改", "/role_edit", menu1));
session.save(new Privilege("部门列表", "/department_list", menu2));
session.save(new Privilege("部门删除", "/department_delete", menu2));
session.save(new Privilege("部门添加", "/department_add", menu2));
session.save(new Privilege("部门修改", "/department_edit", menu2));
session.save(new Privilege("用户列表", "/user_list", menu3));
session.save(new Privilege("用户删除", "/user_delete", menu3));
session.save(new Privilege("用户添加", "/user_add", menu3));
session.save(new Privilege("用户修改", "/user_edit", menu3));
session.save(new Privilege("用户初始化密码", "/user_initPassword", menu3));
// ------
menu = new Privilege("网上交流", null, null);
menu1 = new Privilege("论坛管理", "/forumManage_list", menu);
menu2 = new Privilege("论坛", "/forum_list", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
// ------
menu = new Privilege("审批流转", null, null);
menu1 = new Privilege("审批流程管理", "/processDefinition_List", menu);
menu2 = new Privilege("申请模板管理", "/template_List", menu);
menu3 = new Privilege("起草申请", "/flow_templateList", menu);
menu4 = new Privilege("待我审批", "/flow_myTaskList", menu);
menu5 = new Privilege("我的申请查询", "/flow_myApplicationList", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(menu4);
session.save(menu5);
}
public static void main(String[] args) {
System.out.println("正在初始化数据...");
// 一定要从spring容器中取出对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Installer installer = (Installer) ac.getBean("installer");
// 执行安装
installer.install();
System.out.println("数据初始化完成!");
}
}
Tips:运行main方法即可初始化数据,运行一次即可.之前已经在Privilege.java中添加了无参和有参构造.这里有参构造的参数没写id和children,是因为,不写id也会自动生成.这里初始化的目的是为了将这些权限数据存入数据库中,而parent和children有关联,存了其中一个,另一个也相当于存进去了.
public Privilege() { } public Privilege(String name, String url, Privilege parent) { this.name = name; this.url = url; this.parent = parent; } |
三.分配权限
1.先把所有权限展示出来,并实现回显功能,还未实现树状结构效果.
权限是在岗位列表页面的:
所以关于权限的代码要加到RoleAction中,
RoleAction:
@Controller @Scope("prototype") public class RoleAction extends BaseAction<Role>{
Long[] privilegeIds;
/** * 设置权限页面 */ public String setPrivilegeUI() throws Exception { //准备要回显的数据 Role role = roleService.getById(model.getId()); ActionContext.getContext().getValueStack().push(role);
privilegeIds = new Long[ role.getPrivileges().size() ]; int index = 0; for (Privilege p : role.getPrivileges()) { privilegeIds[ index++ ] = p.getId(); }
//准备数据 List<Privilege> privilegeList = privilegeService.findAll(); ActionContext.getContext().put("privilegeList", privilegeList);
return "setPrivilegeUI"; }
/** * 设置权限 */ public String setPrivilege() throws Exception { //从数据库中获取要修改的原始数据 Role role = roleService.getById(model.getId());
//设置要修改的属性 List<Privilege> privilegeList = privilegeService.getByIds(privilegeIds); role.setPrivileges(new HashSet<Privilege>(privilegeList));
//保存到数据库 roleService.update(role);
return "toList"; }
public Long[] getPrivilegeIds() { return privilegeIds; }
public void setPrivilegeIds(Long[] privilegeIds) { this.privilegeIds = privilegeIds; }
} |
Strurs.xml:
<!-- 岗位管理 --> <action name="role_*" class="roleAction" method="{1}"> <result name="setPrivilegeUI">/WEB-INF/jsp/roleAction/setPrivilegeUI.jsp</result> …… </action> |
修改list中设置权限的链接:
<s:a action="role_setPrivilegeUI?id=%{id}">设置权限</s:a> |
setPrivilegeUI.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <title>配置权限</title> <%@include file="/WEB-INF/jsp/public/header.jspf" %> <script language="javascript" src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/style/blue/file.css" /> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css" />
</head> <body>
<!-- 标题显示 --> <div id="Title_bar"> <div id="Title_bar_Head"> <div id="Title_Head"></div> <div id="Title"><!--页面标题--> <img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/>配置权限 </div> <div id="Title_End"></div> </div> </div>
<!--显示表单内容--> <div id=MainArea> <s:form action="role_setPrivilege"> <s:hidden name="id"></s:hidden> <div class="ItemBlock_Title1"><!-- 信息说明 --><div class="ItemBlock_Title1"> <img border="0" width="4" height="7" src="${pageContext.request.contextPath}/style/blue/images/item_point.gif" />正在为${name }配置权限 </div> </div>
<!-- 表单内容显示 --> <div class="ItemBlockBorder"> <div class="ItemBlock"> <table cellpadding="0" cellspacing="0" class="mainForm"> <!--表头--> <thead> <tr align="LEFT" valign="MIDDLE" id="TableTitle"> <td width="300px" style="padding-left: 7px;"> <!-- 如果把全选元素的id指定为selectAll,并且有函数selectAll(),就会有错。因为有一种用法:可以直接用id引用元素 --> <input type="CHECKBOX" id="cbSelectAll" onClick="selectAll(this.checked)"/> <label for="cbSelectAll">全选</label> </td> </tr> </thead>
<!--显示数据列表--> <tbody id="TableData"> <tr class="TableDetail1"> <!-- 显示权限树 --> <td> <s:checkboxlist list="privilegeList" name="privilegeIds" listKey="id" listValue="name"> </s:checkboxlist> </td> </tr> </tbody> </table> </div> </div>
<!-- 表单操作 --> <div id="InputDetailBar"> <input type="image" src="${pageContext.request.contextPath}/style/images/save.png"/> <a href="javascript:history.go(-1);"><img src="${pageContext.request.contextPath}/style/images/goBack.png"/></a> </div> </s:form> </div>
<div class="Description"> 说明:<br /> 1,选中一个权限时:<br /> a,应该选中他的所有直系上级。<br /> b,应该选中他的所有直系下级。<br /> 2,取消选择一个权限时:<br /> a,应该取消选择他的所有直系下级。<br /> b,如果同级的权限都是未选择状态,就应该取消选中他的直接上级,并递归向上做这个操作。<br />
3,全选/取消全选。<br /> 4,默认选中当前岗位已有的权限。<br /> </div>
</body> </html> |
Tips:
- 还是回显的问题.不一定要求数据库表中有privilegeIds字段,只要action中以属性驱动封装的属性,其属性名与下拉选,复选框等中的name值对应即可.如:
RoleAction:
Long[] privilegeIds; public Long[] getPrivilegeIds() { return privilegeIds; }
public void setPrivilegeIds(Long[] privilegeIds) { this.privilegeIds = privilegeIds; } |
<s:checkboxlist list="privilegeList" name="privilegeIds" listKey="id" listValue="name"></s:checkboxlist>
- 接收从页面传过来的多个id值时,通用办法:
Long[] privilegeIds; public Long[] getPrivilegeIds() { return privilegeIds; }
public void setPrivilegeIds(Long[] privilegeIds) { this.privilegeIds = privilegeIds; }
|
这里接收privilegeIds是为了实现页面的回显效果.
3. Struts2的复选框标签(跟下拉选差不多):
<s:checkboxlist list="privilegeList" name="privilegeIds" listKey="id" listValue="name"></s:checkboxlist>
页面效果:
4. action中的setPrivilege()方法需要根据id查询对象,
而提交给他的表单是来自setPrivilegeUI.jsp,故其表单中必须要将id提交过去,
不然会报空指针异常.
其他操作:
创建service,不要忘了将service放入容器中.
PrivilegeServiceImpl:
@Service @Transactional public class PrivilegeServiceImpl extends DaoSupportImpl<Privilege> implements PrivilegeService{
} |
在BaseAction中注入PrivilegeService.
@Resource protected PrivilegeService privilegeService; |
2.实现页面中的树状结构展示:
-
实现简单的树状结构展示: (利用jquery_treeview (jquery中的某个文件夹) 完成)
自己写个简单的html文件(放到jquery_treeview文件夹中):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Blank</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!-- 1,导入js与css文件 -->
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="jquery.treeview.js"></script>
<link rel="stylesheet" type="text/css" href="jquery.treeview.css">
</head>
<body>
<!-- 2,使用UL显示数据 -->
<ul id="root">
<li>系统管理
<ul>
<li>岗位管理</li>
<li>部门管理
<ul>
<li>aaa</li>
<li>bbb</li>
</ul>
</li>
<li>用户管理</li>
</ul>
</li>
<li>网上交流</li>
</ul>
<!-- 3.显示为树状结构 -->
<script type="text/javascript">
$("#root").treeview();
</script>
</body>
</html>
效果如图:
总结:实现树状结构展示的步骤:
- 导入js与css文件
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="jquery.treeview.js"></script>
<link rel="stylesheet" type="text/css" href="jquery.treeview.css">
(路径可能不一样,但要导入的文件是一样的)
- 使用UL显示数据
…
3.显示为树状结构
<script type="text/javascript">
$("#root").treeview();
</script>
(root为ul的id)
-
之前在setPrivilegeUI.jsp中是利用Struts的复选框标签来展示所有权限的,
<s:checkboxlist list="privilegeList" name="privilegeIds" listKey="id" listValue="name"></s:checkboxlist>
使用Struts2的标签显示复选框,虽然有回显功能,但不方便修改显示效果。
所以我们选择使用循环来显示复选框,但需要自己实现回显功能.
setPrivilegeUI.jsp:
<tbody id="TableData"> <tr class="TableDetail1"> <!-- 显示权限树 --> <!-- 使用struts2的标签来显示复选框,虽然有回显功能,但不方便修改显示效果. --> <%--<td><s:checkboxlist list="privilegeList" name="privilegeIds" listKey="id" listValue="name"> </s:checkboxlist> </td> --%>
<!-- 所以我们选择使用循环来显示复选框,但要自己实现回显功能--> <s:iterator value="privilegeList"> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/>/> <label for="cb_${id }">${name}</label> <br/> </s:iterator> </tr> </tbody> |
<s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> 作用:实现回显效果
<label for="cb_${id }">${name}</label> 作用:当点击名字时,名字前的复选框就会被选中或取消.
注意: for="cb_${id }"引号前后不能有多余空格!!
-
实现树状结构展示:
setPrivilege.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <title>配置权限</title> <%@include file="/WEB-INF/jsp/public/header.jspf"%> <script language="javascript" src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/style/blue/file.css" /> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css" />
</head> <body> …
<!-- 显示为树状结构(使用<ul>标签) --> <ul id="tree"> <s:iterator value="privilegeList"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }">${name}</label> </li> </s:iterator> </ul>
<script type="text/javascript"> $("#tree").treeview(); </script> … </body> </html> |
%@include file="/WEB-INF/jsp/public/header.jspf"%
header.jspf中已经导入了
<script language="javascript" src="${pageContext.request.contextPath}/script/jquery.js"></script>
所以第一步导入js,cs文件(总共三个文件)的工作已经完成.
相应的action中:
List<Privilege> privilegeList = privilegeService.findAll(); ActionContext.getContext().put("privilegeList", privilegeList); |
所以页面效果如图:
原本的action是将所有权限查出来,并没有体现出层次关系.而我们要做的是从顶级权限开始,一层一层往下…,所以要修改action中的代码:
//准备数据 List<Privilege> topPrivilegeList = privilegeService.findtopPrivilegeList(); ActionContext.getContext().put("topPrivilegeList", topPrivilegeList); |
PrivilegeServiceImpl:
/** * 查询所有顶级权限 */ public List<Privilege> findtopPrivilegeList() { return getSession().createQuery(// "from Privilege p where p.parent is null")// .list(); } |
setPrivilegeUI.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <title>配置权限</title> <%@include file="/WEB-INF/jsp/public/header.jspf"%> <script language="javascript" src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/style/blue/file.css" /> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css" />
</head> <body> …… <!-- 表单内容显示 --> <div class="ItemBlockBorder"> <div class="ItemBlock"> <table cellpadding="0" cellspacing="0" class="mainForm"> <!--表头--> <thead> <tr align="LEFT" valign="MIDDLE" id="TableTitle"> <td width="300px" style="padding-left: 7px;">
<input type="CHECKBOX" id="cbSelectAll" onclick="$('input[name=privilegeIds]').attr('checked', this.checked)" /> <label for="cbSelectAll">全选</label>
</td> </tr> </thead>
<!--显示数据列表--> <tbody id="TableData"> <tr class="TableDetail1"> <!-- 显示权限树 -->
<!-- 显示为树状结构(使用<ul>标签) --> <ul id="tree"> <!-- 第一层 --> <s:iterator value="topPrivilegeList"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }"><span class="folder">${name}</span></label> <ul> <!-- 第二层 --> <s:iterator value="children"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }"><span class="folder">${name}</span></label> <ul> <!-- 第三层 --> <s:iterator value="children"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }"><span class="folder">${name}</span></label> </li> </s:iterator> </ul> </li> </s:iterator> </ul> </li> </s:iterator> </ul>
<script type="text/javascript"> $("#tree").treeview(); </script> …… </body> </html> |
解析:
1.从需求页面来看:
最多有三层结构,而这层次结构在初始化权限数据之后是不能改变的了.想改变层次结构就得改动源码,所以层次结构比较固定,所以在权限设置页面上,我们可以通过做三层循环来体现层次关系.
2. <span class="folder">${name}</span>
实现的是文件夹效果:
(这是jquery写好的,可以直接使用)
3.除了第一层循环,第二第三层的循环value值都是children属性,children是Privilige对象中的一个set集合,因为set集合无序,所以每次刷新页面时,除了第一层的系统管理位置不变,其他的排序都会变化.
解决办法,在Privilege.hbm.xml中加上:
<!-- children属性,表达的是本对象与Privilege(children)的一对多关系 --> <set name="children" order-by="id ASC"> <key column="parentId"></key> <one-to-many class="Privilege"/> </set> |
4.全选/全不选功能:
<input type="CHECKBOX" id="cbSelectAll" onclick="$('input[name=privilegeIds]').attr('checked', this.checked)" />
<label for="cbSelectAll">全选</label>
意思是点击后,将全选框的状态(选中或未选中)赋值给name为privilegeIds的input框.(即checked = this.checked)
5.导入jquery的js,cs文件之后,
Images的位置不能随便乱挪,因为他下面的css文件已经将images的路径写成绝对路径,乱挪的话,会导致css找不到图片.
- 树状结构中,选中或取消的效果
|
根据需求页面的源码来判断关系,如:
setPrivilegeUI:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <title>配置权限</title> <%@include file="/WEB-INF/jsp/public/header.jspf"%> <script language="javascript" src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/style/blue/file.css" /> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css" />
<script type="text/javascript"> $(function(){ //增加onclick处理函数 $("input[name=privilegeIds]").click(function(){ //当选中或取消某个权限时,同时也选中或取消所有的下级权限 $(this).siblings("ul").find("input").attr("checked" , this.checked);
//当选中某个权限时,应同时选中他的直系上级权限 if(this.checked == true){// 可以直接写为 if(this.checked) 因为checked为布尔值 $(this).parent().parent().siblings("input").attr("checked" , true); /* 或者$(this).parents("li").children("input").attr("checked" , true); */ } //当取消掉某个权限时,如果同级的也没有勾选,那也取消上级权限 else{ if($(this).parent().siblings("li").children("input:checked").size() == 0){ $(this).parent().parent().siblings("input").attr("checked" , false); } } }) }) </script> </head> <body>
<!-- 标题显示 --> <div id="Title_bar"> <div id="Title_bar_Head"> <div id="Title_Head"></div> <div id="Title"> <!--页面标题--> <img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif" /> 配置权限 </div> <div id="Title_End"></div> </div> </div>
<!--显示表单内容--> <div id=MainArea> <s:form action="role_setPrivilege"> <s:hidden name="id"></s:hidden> <div class="ItemBlock_Title1"> <!-- 信息说明 --> <div class="ItemBlock_Title1"> <img border="0" width="4" height="7" src="${pageContext.request.contextPath}/style/blue/images/item_point.gif" /> 正在为${name }配置权限 </div> </div>
<!-- 表单内容显示 --> <div class="ItemBlockBorder"> <div class="ItemBlock"> <table cellpadding="0" cellspacing="0" class="mainForm"> <!--表头--> <thead> <tr align="LEFT" valign="MIDDLE" id="TableTitle"> <td width="300px" style="padding-left: 7px;">
<input type="CHECKBOX" id="cbSelectAll" onclick="$('input[name=privilegeIds]').attr('checked', this.checked)" /> <label for="cbSelectAll">全选</label>
</td> </tr> </thead>
<!--显示数据列表--> <tbody id="TableData"> <tr class="TableDetail1"> <!-- 显示权限树 --> <!-- 使用struts2的标签来显示复选框,虽然有回显功能,但不方便修改显示效果. --> <%--<td><s:checkboxlist list="privilegeList" name="privilegeIds" listKey="id" listValue="name"> </s:checkboxlist> </td> --%>
<!-- 所以我们选择使用循环来显示复选框,但要自己实现回显功能--> <%-- <s:iterator value="privilegeList"> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }">${name}</label> <br /> </s:iterator> --%>
<!-- 显示为树状结构(使用<ul>标签) --> <ul id="tree"> <!-- 第一层 --> <s:iterator value="topPrivilegeList"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }"><span class="folder">${name}</span></label> <ul> <!-- 第二层 --> <s:iterator value="children"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }"><span class="folder">${name}</span></label> <ul> <!-- 第三层 --> <s:iterator value="children"> <li> <input type="checkbox" name="privilegeIds" value="${id }" id="cb_${id}" <s:property value="%{ id in privilegeIds ? 'checked' : '' }"/> /> <label for="cb_${id }"><span class="folder">${name}</span></label> </li> </s:iterator> </ul> </li> </s:iterator> </ul> </li> </s:iterator> </ul>
<script type="text/javascript"> $("#tree").treeview(); </script>
</tr> </tbody> </table> </div> </div>
<!-- 表单操作 --> <div id="InputDetailBar"> <input type="image" src="${pageContext.request.contextPath}/style/images/save.png" /> <a href="javascript:history.go(-1);"><img src="${pageContext.request.contextPath}/style/images/goBack.png" /></a> </div> </s:form> </div>
<div class="Description"> 说明:<br /> 1,选中一个权限时:<br /> a,应该选中他的所有直系上级。<br /> b,应该选中他的所有直系下级。<br /> 2,取消选择一个权限时:<br /> a,应该取消选择他的所有直系下级。<br /> b,如果同级的权限都是未选择状态,就应该取消选中他的直接上级,并递归向上做这个操作。<br />
3,全选/取消全选。<br /> 4,默认选中当前岗位已有的权限。<br /> </div>
</body> </html> |
<script type="text/javascript">
$(function(){
……
})
})
</script>
这样写的效果是:等页面加载完成之后才有效果.
四.使用权限
系统权限---登陆注销
新建个登陆注销专用的action
loginoutAction:
@Controller @Scope("prototype") public class LoginoutAction extends BaseAction<User>{
/** 登录页面 */ public String loginUI() throws Exception { return "loginUI"; }
/** 登录 */ public String login() throws Exception { //验证登录名和密码,如果正确就返回这个用户,不正确就返回null User user = userService.findByLoginNameAndPassword(model.getLoginName(), model.getPassword());
// 如果登录名或密码不正确,就转回到登录页面并提示错误消息 if(user == null){ addFieldError("login", "对不起,您的账号密码输入错误!"); return "loginUI"; //如果用户名和密码都正确,就登录用户. }else{ ActionContext.getContext().getSession().put("user", user); return "toHome"; }
}
/** 注销 */ public String logout() throws Exception { ActionContext.getContext().getSession().remove("user"); return "logout"; } } |
ActionContext.getContext().getSession().put("user", user);
这是struts2提供的解耦和的方式,不依赖原生Servlet的API的方式.采用第二种方式的话不方便测试,因为原生API方式依赖servlet的环境,得放到tomcat容器中,启动服务器才能拿到session.
不用再新建service,直接用原来的userService就好
UserServiceImpl:
/** * 验证登录名和密码,如果正确就返回这个用户,不正确就返回null */ public User findByLoginNameAndPassword(String loginName, String password) { String md5 = DigestUtils.md5Hex(password); return (User) getSession().createQuery(// "from User u where u.loginName = ? and u.password = ?")// .setParameter(0, loginName)// .setParameter(1, md5)//密码要用md5摘要 .uniqueResult(); } |
uniqueResult()
这个方法确保只返回一个user对象,如果有多个返回值,则提示错误.
Struts.xml:
<!-- 用户登录注销功能 --> <action name="loginout_*" class="loginoutAction" method="{1}"> <result name="loginUI">/WEB-INF/jsp/loginoutAction/loginUI.jsp</result> <result name="logout">/WEB-INF/jsp/loginoutAction/logout.jsp</result> <result name="toHome" type="redirect">/index.jsp</result> </action> |
Index.jsp(这里只是测试页面):
Welcome, ${user.name} ! |
LoginUI.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <HTML> <HEAD> <META http-equiv=Content-Type CONTENT="text/html; charset=gbk" /> <TITLE>Itcast OA</TITLE> <%@ include file="/WEB-INF/jsp/public/header.jspf" %> <LINK HREF="${pageContext.request.contextPath}/style/blue/login.css" type=text/css rel=stylesheet /> </HEAD> <BODY LEFTMARGIN=0 TOPMARGIN=0 MARGINWIDTH=0 MARGINHEIGHT=0 CLASS=PageBody >
<s:form action="loginout_login"> <DIV ID="CenterAreaBg"> <DIV ID="CenterArea"> <DIV ID="LogoImg"><IMG BORDER="0" SRC="${pageContext.request.contextPath}/style/blue/images/logo.png" /></DIV> <DIV ID="LoginInfo"> <TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 width=100%> <TR> <tr> <div style="color:red"><s:fielderror></s:fielderror></div> </tr> <TD width=45 CLASS="Subject"><IMG BORDER="0" SRC="${pageContext.request.contextPath}/style/blue/images/login/userId.gif" /></TD> <TD> <%-- 用户名 --%> <%-- <s:textfield SIZE="20" cssClass="TextField" NAME="loginName" /> --%> <s:textfield size="20" cssClass="TextField" name="loginName" /> </TD> <TD ROWSPAN="2" STYLE="padding-left:10px;"><INPUT TYPE="image" SRC="${pageContext.request.contextPath}/style/blue/images/login/userLogin_button.gif"/></TD> </TR> <TR> <TD CLASS="Subject"><IMG BORDER="0" SRC="${pageContext.request.contextPath}/style/blue/images/login/password.gif" /></TD> <TD> <%-- 密码,不需要回显 --%> <%-- <s:password showPassword="false" SIZE="20" cssClass="TextField" NAME="password" /> --%> <s:password size="20" cssClass="TextField" showPassword="false" name="password" /> </TD> </TR> </TABLE> </DIV> <DIV ID="CopyRight"><A HREF="javascript:void(0)">© 2010 版权所有 itcast</A></DIV> </DIV> </DIV> </s:form>
</BODY> </HTML> |
Tips:之前没注意name的大小写问题,一种用大写,这么低级的错误却浪费了我很多时间!!!细心!!!!如果用大写,会报空指针异常:
<s:fielderror name="login"></s:fielderror>这样写的话是将name为login的错误消息显示出来.
<s:fielderror></s:fielderror>这样写的话是将所有错误消息显示出来.
Logout.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html>
<head> <%@ include file="/WEB-INF/jsp/public/header.jspf" %> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>您已退出Itcast OA系统</title> <link href="${pageContext.request.contextPath }/style/blue/logout.css" rel="stylesheet" type="text/css" /> </head>
<body> <table border=0 cellspacing=0 cellpadding=0 width=100% height=100%> <tr> <td align=center> <div id=Logout> <div id=AwokeMsg><img id=LogoutImg src="${pageContext.request.contextPath }/style/blue/images/logout/logout.gif" border=0 /><img id=LogoutTitle src="${pageContext.request.contextPath }/style/blue/images/logout/logout1.gif" border=0 /></div> <div id=LogoutOperate> <img src="${pageContext.request.contextPath }/style/blue/images/logout/logout2.gif" border=0 /> <!-- 这里不适用s:a标签!!! --> <a href="${pageContext.request.contextPath }/loginout_loginUI.do">重新进入系统</a>
<img src="${pageContext.request.contextPath }/style/blue/images/logout/logout3.gif" border=0 /> <a href="javascript: window.close();">关闭当前窗口</a> </div> </div> </td> </tr> </table> </body> </html> |
效果图:
(快捷键:home跳到当前行的开头,end跳到当前行的结尾)