要點說明
l 權限就是控制功能的使用(功能對應着URL)。
l 對功能的控制就是對URL的通路控制。
l 在我們的程式中,一個功能對應一個或兩個URL:
• 1,例如清單或删除功能,隻對應一個URL.
• 2,例如添加或修改功能,對應兩個URL:..add, ..addUI
•
public class Privilege implements Serializable{
private Long id;
private String url;
private String name;
private String icon;
private Set<Role> roles=new HashSet<Role>();
private Privilege parent;
private Set<Privilege> children=new HashSet<Privilege>();
public Privilege(){
}
public Privilege( String name,String url, String icon, Privilege parent) {
super();
this.name= name;
this.url= url;
this.icon= icon;
this.parent= parent;
}
//省略setter、getter方法…
}
具體有哪些功能
l 初始化資料
• 權限資料。
• 超級管理者。
l 配置設定權限
• 給角色配置設定權限。
• 使用者的權限就是使用者所有角色的權限。
l 使用權限
• 1,登入、登出。
• 2,左側的菜單是根據權限顯示的。
• 3,右側頁面中的連結是根據權限顯示的。
• 4,攔截每一個action請求,驗證使用者是否有權限通路。
一.初始化資料
@Component
public classInstaller {
@Resource
private SessionFactorysessionFactory;
@Transactional
public void install(){
Sessionsession=sessionFactory.getCurrentSession();
//一、超級管理者
Useruser=newUser();
user.setName("超級管理者");
user.setLoginName("admin");
user.setPassword(DigestUtils.md5Hex("666666"));
session.save(user);
//權限資料
Privilegemenu, menu1,menu2,menu3,menu4,menu5;
menu=new Privilege("系統管理",null,"FUNC20082.gif",null);
menu1=new Privilege("崗位管理","roleAction_list",null,menu);
menu2=new Privilege("部門管理","departmentAction_list",null,menu);
menu3=new Privilege("使用者管理","userAction_list",null,menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
session.save(menu3);
session.save(new Privilege("崗位清單","roleAction_list",null,menu1));
session.save(new Privilege("崗位删除","roleAction_delete",null,menu1));
session.save(new Privilege("崗位添加","roleAction_add",null,menu1));
session.save(new Privilege("崗位修改","roleAction_edit",null,menu1));
session.save(new Privilege("部門清單","departmentAction_list",null,menu2));
session.save(new Privilege("部門删除","departmentAction_delete",null,menu2));
session.save(new Privilege("部門添加","departmentAction_add",null,menu2));
session.save(new Privilege("部門修改","departmentAction_edit",null,menu2));
session.save(new Privilege("使用者清單","userAction_list",null,menu3));
session.save(new Privilege("使用者删除","userAction_delete",null,menu3));
session.save(new Privilege("使用者添加","userAction_add",null,menu3));
session.save(new Privilege("使用者修改","userAction_edit",null,menu3));
session.save(new Privilege("使用者初始化密碼","userAction_initPassword",null,menu3));
//----------------------------------------
menu= newPrivilege("網上交流",null, "FUNC20064.gif", null);
menu1= newPrivilege("論壇管理","forumManageAction_list","FUNC20064.gif", menu);
menu2= newPrivilege("論壇","forumAction_list", "FUNC20064.gif", menu);
session.save(menu);
session.save(menu1);
session.save(menu2);
menu= newPrivilege("審批流轉",null, "FUNC20057.gif", null);
menu1= newPrivilege("審批流程管理","processDefinitionAction_list", null,menu);
menu2= newPrivilege("申請模闆管理","applicationTemplateAction_list", null,menu);
menu3= newPrivilege("起草申請","flowAction_applicationTemplateList", null,menu);
menu4= newPrivilege("待我審批","flowAction_myTaskList", null,menu);
menu5= newPrivilege("我的申請查詢","flowAction_myApplicationList", null,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("正在執行安裝...");
ApplicationContextac = newClassPathXmlApplicationContext("applicationContext.xml");
Installerinstaller = (Installer) ac.getBean("installer");
installer.install();
System.out.println("==安裝完畢 ==");
}
}
二、 配置設定權限
點選設定權限後:
roleAction_setPrivilegeUI.action中準備資料:
public String setPrivilegeUI()throws Exception {
//為角色名準備資料
Role role=roleService.getById(model.getId());
ActionContext.getContext().put("role",role);
//準備資料
List<Privilege> topPrivilegeList=privilegeService.findTopList();
ActionContext.getContext().put("topPrivilegeList", topPrivilegeList);
//準備回顯資料
privilegeIds=new Long[role.getPrivileges().size()];
int index=0;
for(Privilege privilege:role.getPrivileges()){
privilegeIds[index++]=privilege.getId();
}
return "setPrivilegeUI";
}
進入配置權限頁面
Jsp頁面:
<ul id="root">
<%--第一級 --%>
<s:iteratorvalue="#topPrivilegeList">
<li>
<input type="checkbox" name="privilegeIds" value="${id}" id="sb_${id }" <s:propertyvalue="%{id inprivilegeIds?'checked':''}"/>>
<label for="sb_${id}"><spanclass="folder">${name}</span></label><br>
<ul>
<%--第二級 --%>
<s:iterator value="children">
<li>
<inputtype="checkbox"name="privilegeIds"value="${id}"id="sb_${id }" <s:propertyvalue="%{id inprivilegeIds?'checked':''}"/>>
<labelfor="sb_${id}"><spanclass="folder">${name}</span></label><br>
<ul>
<%--第三級 --%>
<s:iterator value="children">
<li>
<inputtype="checkbox"name="privilegeIds"value="${id}"id="sb_${id }" <s:propertyvalue="%{id inprivilegeIds?'checked':''}"/>>
<labelfor="sb_${id}"><spanclass="folder">${name}</span></label><br>
</li>
</s:iterator>
</ul>
</li>
</s:iterator>
</ul>
</li>
</s:iterator>
</ul>
實作js效果:
$(function(){
//給所有的權限複選框添加點選事件
$("[name=privilegeIds]").click(function(){
//自己選中或取消時,把所有的下級權限也都同時選中或取消
$(this).siblings("ul").find("input").attr("checked",this.checked);
//當選中一個權限時,也要同時選中所有的上級權限
if(this.checked){
$(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);
var start=$(this).parent().parent();
if(start.parent().siblings("li").children("input:checked").size() ==0){
start.parent().parent().siblings("input").attr("checked",false);
}
}
}
});
});
樹狀結構顯示:
依次引入檔案:
jquery.js
jquery_treeview/jquery.treeview.js
jquery_treeview/jquery.treeview.css
在 jsp頁面中插入
<script type="text/javascript">
$(function(){
$("#root").treeview();
});
</script>
即可實作樹狀結構顯示。
點選儲存後:
選中的資訊封裝在privilegeIds[]數組中,交由roleAction_setPrivilege方法處理
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";
}
三、使用權限
• 1,登入、登出。
• 2,左側的菜單是根據權限顯示的。
• 3,右側頁面中的連結是根據權限顯示的。
• 4,攔截每一個action請求,驗證使用者是否有權限通路。
1, 登入。
public String loginUI()throws Exception {
return "loginUI";
}
public String login()throws Exception {
//根據使用者名和密碼查詢使用者
User user=userService.getByLoginNameAndPassword(model.getLoginName(),model.getPassword());
if(user==null){
addFieldError("login","使用者名或密碼不正确");
return"loginUI";
}else{
ActionContext.getContext().getSession().put("user", user);
System.out.println("==已将使用者放入session中 ==");
return"toIndex";
}
}
Service中代碼:
public User getByLoginNameAndPassword(String loginName, String password){
return (User) getSession().createQuery(//
"FROM User u WHERE u.loginName=? ANDu.password=?")//
.setParameter(0, loginName)
.setParameter(1, DigestUtils.md5Hex(password))
.uniqueResult();
}
登出
public String logout()throws Exception {
ActionContext.getContext().getSession().remove("user");
System.out.println("==已将使用者從session中移除 ==");
return "logout";
}
2, 左側的菜單是根據權限顯示的
在伺服器啟動時,初始化權限資料
InitServletContextListener用于監聽WEB 應用啟動和銷毀的事件
public class InitServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
//得到application對象
ServletContext application=sce.getServletContext();
//得到容器對象
ApplicationContext ac=WebApplicationContextUtils.getWebApplicationContext(application);
//得到service執行個體對象
PrivilegeService privilegeService=(PrivilegeService) ac.getBean("privilegeServiceImpl");
//準備所有頂級權限的集合
List<Privilege> topPrivilegeList=privilegeService.findTopList();
application.setAttribute("topPrivilegeList",topPrivilegeList);
System.out.println("--已準備好頂級權限的資料 --");
//準備所有有權限的url集合
List<String> allPrivilegeUrls=privilegeService.getAllPrivilegeUrls();
application.setAttribute("allPrivilegeUrls",allPrivilegeUrls);
}
public void contextDestroyed(ServletContextEvent arg0){
// TODO Auto-generated method stub
}
}
在web.xml中
添加(位于Spring容器監聽器之後)
<!-- 初始化資料的監聽器 -->
<listener>
<listener-class> cn.itcast.oa.base.InitServletContextListener</listener-class>
</listener>
homeAction/ left.jsp中
<div id="Menu">
<ul id="MenuUl">
<%--頂級菜單 --%>
<s:iteratorvalue="#application.topPrivilegeList">
<s:if test="#session.user.hasPrivilegeByName(name)">
<li class="level1">
<divonClick="menuClick(this);"class="level1Style">
<imgsrc="style/images/MenuIcon/${icon}"class="Icon"/> ${name}
</div>
<%--二級菜單 style="display: none;"--%>
<ul style="display:none;" class="MenuLevel2">
<s:iterator value="children">
<s:iftest="#session.user.hasPrivilegeByName(name)">
<liclass="level2">
<divclass="level2Style"><imgsrc="style/images/MenuIcon/menu_arrow_single.gif"/>
<ahref="${pageContext.request.contextPath}/${url}.action"target="right"> ${name } </a>
</div>
</li>
</s:if>
</s:iterator>
</ul>
</li>
</s:if>
</s:iterator>
</ul>
</div>
實作點選隐藏顯示的效果
<script type="text/javascript">
function menuClick(menuDiv){
$(".MenuLevel2").not($(menuDiv).next()).hide();
$(menuDiv).next().toggle();
};
</script>
三、右側頁面中的連結是根據權限顯示的(自定義标簽)
通用做法:
缺點:每個連結都需要進行權限判斷
改進:自定義标簽,覆寫<s:a></s:a>的處理類
在src下建立一個與<s:a></s:a>的處理類同包同名的類
org.apache.struts2.views.jsp.ui. AnchorTag
@Override
public int doEndTag() throws JspException {
// 目前使用者
// User user = (User)pageContext.getSession().getAttribute("user");
User user=(User) pageContext.getSession().getAttribute("user");
// 目前的URL,如果有參數就要去掉後面的參數字元串
String privilegeUrl = action;
int pos = privilegeUrl.indexOf("?");
if (pos > -1){
privilegeUrl = privilegeUrl.substring(0, pos);
}
if (user.hasPrivilegeByUrl(privilegeUrl)){
return super.doEndTag();// 如果有權限,就正常的生成與輸出<a>标簽
} else {
return EVAL_PAGE;// 如果沒有權限,就不顯示目前<a>标簽,隻是繼續執行頁面中後面的代碼
}
}
四、攔截每一個action請求,驗證使用者是否有權限通路。
public class CheckPrivilegeInterceptor extends AbstractInterceptor{
public String intercept(ActionInvocationinvocation)throws Exception {
//擷取使用者
User user=(User) ActionContext.getContext().getSession().get("user");
//擷取目前通路的url,并去掉應用程式的字首(namespace+actionName)
String namespace=invocation.getProxy().getNamespace();
String actionName=invocation.getProxy().getActionName();
StringprivilegeUrl=null;
if(namespace.endsWith("/")){
privilegeUrl=namespace+actionName;
}else{
privilegeUrl=privilegeUrl.substring(1);
}
//未登陸使用者(session中不存在)
if(user==null){
//如果是在使用登陸功能,就放行
if(privilegeUrl.endsWith("userAction_login")){
return invocation.invoke();
}
//如果不是在使用登陸功能就轉到登陸頁面
else{
return"loginUI";
}
}
//已登陸使用者(判斷權限)
else{
//如果有權限,就放行
if(user.hasPrivilegeByUrl(privilegeUrl)){
return invocation.invoke();
}
//如果沒有權限,就轉到錯誤頁面
else{
return"noPrivilegeError";
}
}
}
}
在Struts.xml配置定義好的攔截器
頁面嵌套問題處理
在loginUI.jsp中,添加下面一段js代碼即可解決
ript type="text/javascript">
if(window.parent!=window){
window.parent.location.reload(true);
}
</script>