問題的提出:
在Struts1框架下,有三種類型的Action控制器,分別是MappingDispatchAction、DispatchAction和Action,他們是依次繼承,最終執(zhí)行的execute方法。但MappingDispatchAction、DispatchAction的子類中沒有execute方法,只有參數(shù)指定的具體方法,而這些方法是被MappingDispatchAction、DispatchAction本類的execute方法調(diào)用執(zhí)行,特別注意的是它是通過反射機制來做的(大家可以看看DispatchAction類的源代碼),所以這些被反射調(diào)用的方法是不能被Spring AOP攔截的,因此也就無法利用切面編程實現(xiàn)權(quán)限控制了。
解決方法:
巴巴運動網(wǎng)通過覆蓋DelegatingRequestProcessor控制器的processActionPerform方法,是一種理想的解決方案,但嚴(yán)格來說并不是AOP切面編程方法。因此筆者僅從學(xué)習(xí)AOP切面編程的角度來提出本文章,對于實用性筆者極力推薦巴巴運動網(wǎng)的方案。
本方法解決思想:
1.覆蓋execute方法,再模仿DispatchAction反射調(diào)用具體的方法;
2.實現(xiàn)Spring AOP攔截點,開始攔截配置描述的范圍內(nèi)的程序;
3.在切入點程序中再次實現(xiàn)反射機制,獲取執(zhí)行方法上的權(quán)限配置信息;
4.根據(jù)權(quán)限信息決定放行還是返回。
最終既可以攔截到execute方法,也可以得到具體方法中的權(quán)限注解配置信息。以本BBS系統(tǒng)為例:
第一步:凡繼承于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="需管理員權(quán)限!")
public ActionForward addUI(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
CategoryForm categoryForm = (CategoryForm)form;
categoryForm.setTitle("新增分類");
return mapping.findForward("addUI");
}
第二步:做自己的權(quán)限配置:
看上面addUI方法上的注解應(yīng)該可以理解這些配置
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Privilege {
String message() default "您沒有權(quán)限執(zhí)行該操作,請登錄后重試!";
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();
}
在Struts1框架下,有三種類型的Action控制器,分別是MappingDispatchAction、DispatchAction和Action,他們是依次繼承,最終執(zhí)行的execute方法。但MappingDispatchAction、DispatchAction的子類中沒有execute方法,只有參數(shù)指定的具體方法,而這些方法是被MappingDispatchAction、DispatchAction本類的execute方法調(diào)用執(zhí)行,特別注意的是它是通過反射機制來做的(大家可以看看DispatchAction類的源代碼),所以這些被反射調(diào)用的方法是不能被Spring AOP攔截的,因此也就無法利用切面編程實現(xiàn)權(quán)限控制了。
解決方法:
巴巴運動網(wǎng)通過覆蓋DelegatingRequestProcessor控制器的processActionPerform方法,是一種理想的解決方案,但嚴(yán)格來說并不是AOP切面編程方法。因此筆者僅從學(xué)習(xí)AOP切面編程的角度來提出本文章,對于實用性筆者極力推薦巴巴運動網(wǎng)的方案。
本方法解決思想:
1.覆蓋execute方法,再模仿DispatchAction反射調(diào)用具體的方法;
2.實現(xiàn)Spring AOP攔截點,開始攔截配置描述的范圍內(nèi)的程序;
3.在切入點程序中再次實現(xiàn)反射機制,獲取執(zhí)行方法上的權(quán)限配置信息;
4.根據(jù)權(quán)限信息決定放行還是返回。
最終既可以攔截到execute方法,也可以得到具體方法中的權(quán)限注解配置信息。以本BBS系統(tǒng)為例:
第一步:凡繼承于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="需管理員權(quán)限!")
public ActionForward addUI(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
CategoryForm categoryForm = (CategoryForm)form;
categoryForm.setTitle("新增分類");
return mapping.findForward("addUI");
}
第二步:做自己的權(quán)限配置:
看上面addUI方法上的注解應(yīng)該可以理解這些配置
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Privilege {
String message() default "您沒有權(quán)限執(zhí)行該操作,請登錄后重試!";
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();
}