程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> SSH集成框架下真正實現Spring AOP攔截功能

SSH集成框架下真正實現Spring AOP攔截功能

編輯:關於JAVA

問題的提出:

在Struts1框架下,有三種類型的Action控制器,分別是MappingDispatchAction、DispatchAction和Action,他們是依次繼承,最終執行的execute方法。但MappingDispatchAction、DispatchAction的子類中沒有execute方法,只有參數指定的具體方法,而這些方法是被MappingDispatchAction、DispatchAction本類的execute方法調用執行,特別注意的是它是通過反射機制來做的(大家可以看看DispatchAction類的源代碼),所以這些被反射調用的方法是不能被Spring AOP攔截的,因此也就無法利用切面編程實現權限控制了。

解決方法:

巴巴運動網通過覆蓋DelegatingRequestProcessor控制器的processActionPerform方法,是一種理想的解決方案,但嚴格來說並不是AOP切面編程方法。因此筆者僅從學習AOP切面編程的角度來提出本文章,對於實用性筆者極力推薦巴巴運動網的方案。

本方法解決思想:

1.覆蓋execute方法,再模仿DispatchAction反射調用具體的方法;

2.實現Spring AOP攔截點,開始攔截配置描述的范圍內的程序;

3.在切入點程序中再次實現反射機制,獲取執行方法上的權限配置信息;

4.根據權限信息決定放行還是返回。

最終既可以攔截到execute方法,也可以得到具體方法中的權限注解配置信息。以本BBS系統為例:

第一步:凡繼承於DispatchAction的類都覆蓋execute方法:

  @Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
return super.execute(mapping, form, request, response);
}
//假如這個action中有一個具體的方法:
@Privilege(userType=PrivilegeType.Admin,message="需管理員權限!")
public ActionForward addUI(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
CategoryForm categoryForm = (CategoryForm)form;
categoryForm.setTitle("新增分類");
return mapping.findForward("addUI");
}

第二步:做自己的權限配置:

看上面addUI方法上的注解應該可以理解這些配置

  @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Privilege {
String message() default "您沒有權限執行該操作,請登錄後重試!";
PrivilegeType userType();
}

配置中有個字字段是枚舉,源碼如下:

public enum PrivilegeType {
LoginUser{
public String getName(){
return "所有登錄用戶";
}
public int getValue(){
return 1;
}
},
LoginUserSelf{
public String getName(){
return "登錄用戶自己";
}
public int getValue(){
return 2;
}
},
Moderator{
public String getName(){
return "版主";
}
public int getValue(){
return 3;
}
},
Admin{
public String getName(){
return "管理員";
}
public int getValue(){
return 4;
}
};
public abstract String getName();
public abstract int getValue();
}

第三步:實現AOP切入編程:

  @Aspect
@Component()
public class PrivilegeAction {
//攔截com.zjh包下(含子包)所有類能返回ActionForward類型的方法
@Around("execution(org.apache.struts.action.ActionForward com.zjh..*.*(..))")
public Object validatePrivilege(ProceedingJoinPoint pjp) throws Throwable{
// 從攔截的方法中參數中得到四個對象
ActionMapping mapping = (ActionMapping) pjp.getArgs()[0];
ActionForm form = (ActionForm) pjp.getArgs()[1];
HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[2];
HttpServletResponse response = (HttpServletResponse) pjp.getArgs()[3];
//從攔截點處獲取它所處的類名,並經過反射取得權限配置信息
Class dispatchAction = Class.forName(pjp.getSignature().getDeclaringTypeName()); Object obj = dispatchAction.newInstance(); String mappingParament = mapping.getParameter()==null ? "execute" : request.getParameter(mapping.getParameter()); Method method = obj.getClass().getDeclaredMethod(mappingParament,
ActionMapping.class,
ActionForm.class,
HttpServletRequest.class,
HttpServletResponse.class); Privilege privilege = method.getAnnotation(Privilege.class);
//如果方法上沒有配置權限信息,直接放行
if(privilege==null)
return (ActionForward)pjp.proceed();
//否則必須是登錄用戶,進行第一關粗粒度攔截
User user = WebUtil.getUserInSession(request);
if(user==null){
request.setAttribute("message", privilege.message());
return mapping.findForward("message");
} //再根據用戶類型進行細粒度攔截
switch(privilege.userType().getValue()){
//當權限為PrivilegeType.LoginUserSelf(登錄用戶自己,例如更新文章必須是自
//己的文章才有權限更新)時,須從數據庫裡取得用戶對象再和session中用
//戶匹配,這個沒有實現。
case 2:
if(!user.getUsername().equals("數據庫裡取得某文章的用戶名")){
request.setAttribute("message", privilege.message());
return mapping.findForward("message");
}
break;
//版主權限攔截,這個沒有實現
case 3:
request.setAttribute("message", privilege.message());
return mapping.findForward("message");
//管理員權限,從application取得管理員用戶名,再匹配session登錄用戶是否相等
case 4:
String admin = ((SystemProperty)request.getSession().getServletContext().getAttribute("config"))
.getAdminUsername();
if(!user.getUsername().equals(admin)){
request.setAttribute("message", privilege.message());
return mapping.findForward("message");
}
break;
}
//當上面沒有攔住,表示權限允許,放行
return (ActionForward)pjp.proceed();
}
}

以上細粒度攔截屬業務邏輯,不妨礙本文所述的AOP切面編程。筆者僅僅是為學習AOP,真正用在真實項目的權限攔截,方案不太成熟。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved