看到標題,不要以為看錯,沒錯,就是Struts1!
對於一個目前只能編碼的人來說,在公司做項目,技術框架基本不會是你自己決定的。唉,最近的一個項目,他們要求就是要用Struts1,對於我剛接觸Struts就是版本2的人來說,Struts1幾乎就沒再關注過,而且大家也應該都了解Struts1與Struts2的區別到底有多大。一把辛酸淚,就不多說了。
閒話不說,先說下需求。
由於項目規模不大,要求加入簡單的權限管理,要求是,
1.不同權限角色進入系統後,顯示對應權限的菜單項;
2.後台的Action請求加入權限控制
數據表有客戶提供,用戶表裡只是簡單的放入了role字段以區分用戶角色。取值為0-5。
前台的菜單項顯示與隱藏的控制使用js動態生成,這裡主要講後台的實現,所以前台就簡單描述一下。實現方式是定義一個多維數組,存入需要的一級和二級菜單信息,然後解析數組,生成自己想要的格式,利用js拼成html標簽。
重點說下後台的實現。後台的實現,一開始我也沒想到使用Java的注解,看到這個方法, http://www.linuxidc.com/Linux/2016-12/138293.htm 使用struts1+注解做權限管理。思路簡單來說就是,在調用每個Action之前判斷權限,有則放行,無則攔截。
對於Struts1來說,工作流程是:ActionSerlvet接收客戶Http請求,使用ActionForm Bean自動填充客戶送來的表單數據到ActionForm Bean對象中;根據配置信息(struts_config.xml)將請求分發給相應的Action對象,Action對象調用execute()方法處理請求(根據JavaBean和ActionForm取得業務邏輯和表單數據),並反回ActionForward對象給ActionSerlvet對象,根據ActionForward對象的信息(目標頁面),ActionServlet再次將Http請求導航到目標頁面,並發送到客戶端。
因此,判斷出請求處理器ActionSerlvet的哪個方法調了action,就是關鍵所在了。通過調試斷點放在ActionServlet的dopost方法上,發現是processActionPerform調用的action,剩下的就是重寫這個方法就好了。當然要記得在xml文件中配置controller標簽,指定用自己的請求處理器。
下面通過代碼具體實現來說明。
首先,定義Java注解類,Java注解的相關知識這裡不是重點,也不多提。
定義一個注解,即一個權限的數組。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 權限控制,注解類
* 生成策略:運行時
* 注解位置:方法
* @author wangxx
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface <span >SystemPrivilegeAnnotation </span>
{
String[] privilegeValue();// 權限值
}
然後,根據前面的分析,重寫RequestProcessor的processActionPerform方法。根據注釋應該也能看的明白。
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.RequestProcessor;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.actions.MappingDispatchAction;
/**
* 權限管理器
*
*
* 步驟:
* 1、要判斷調用的是action的哪個方法,通過反射
* 一般action有三種方式:
* 第一,直接繼承Action的action,那麼方法名就是“execute”;
* 第二,繼承DispatchAction的action,那麼方法名就是request域中對應的mapping中的parameter;
* 第三,繼承MappingDispatchAction的action,那麼方法名就是mapping中的parameter
* 通過反射得到調用action的哪個方法
* 2、判斷調用的方法上面有沒有注解,也就是調用這個方法需不需要權限,
* 不需要,調用超類的processActionPerform;
* 需要的話,檢查用戶的權限是否contains這個權限,是就放行,不是不放行
*
* @author wangxx
*
*/
public class PrivilegController extends RequestProcessor {
/*
* 斷點在ActionServlet的dopost方法上, 發現是processActionPerform調用的action
*
* @see
*/
@Override
protected ActionForward processActionPerform(HttpServletRequest request,
HttpServletResponse response, Action action, ActionForm form,
ActionMapping mapping) throws IOException, ServletException {
//判斷權限
if (!systemPrivilege(request, action, mapping)) {
ActionMessages messages = new ActionMessages();
messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
"error.no.permission"));
saveErrors(request, messages);
//request.setAttribute("org.apache.struts.action.ERROR", "您沒有權限進行當前操作!");
//重定向到login
// request.setAttribute("toUrl", SiteURL.getUrlByKey("logon"));
return mapping.findForward("nonpermission");
}
return super.processActionPerform(request, response, action, form,
mapping);
}
// 權限判斷方法,返回true說明當前用戶有權限調用當前方法
private boolean systemPrivilege(HttpServletRequest request, Action action,
ActionMapping mapping) {
// 拿到方法的名字
String currentMethodName = getCurrentMethodName(request, action,
mapping);
// 拿出方法中的注解信息
SystemPrivilegeAnnotation systemPrivilegeAnnotation = getMethodSystemPrivilegeAnnotation(
action, currentMethodName);
// 如果注解信息為空說明當前方法不需要任何權限
if (systemPrivilegeAnnotation == null) {
return true;
}
//有注解,即需要權限
// 根據注解信息建立權限對象,即當前方法所需權限
String[] privilegeValue = systemPrivilegeAnnotation.privilegeValue();
// 拿出當前用戶--也可以存在session,總之這一步是為了取得當前登錄者的信息
UserInfo userInfo = (UserInfo) request.getSession().getAttribute(
ConstApp.SESSION_USERINFO);
String userRole = userInfo.getUserRole();
//循環,將當前用戶的所有權限逐個與當前方法所需權限相比較
for (String role : privilegeValue) {
if(role.equals(userRole)){
return true;
}
}
return false;
}
/**
* 取得當前action方法的名字
*
* @param request
* @param action
* @param mapping
* @return
*/
private String getCurrentMethodName(HttpServletRequest request,
Action action, ActionMapping mapping) {
// 繼承DispatchAction的action,那麼方法名就是request域中對應的mapping中的parameter
if (DispatchAction.class.isAssignableFrom(action.getClass())) {
return request.getParameter(mapping.getParameter());
}
// 繼承MappingDispatchAction的action,那麼方法名就是mapping中的parameter
if (MappingDispatchAction.class.isAssignableFrom(action.getClass())) {
return mapping.getParameter();
}
// 直接繼承Action的action,那麼方法名就是“execute”;
return "execute";
}
/**
* 通過反射得到action方法的注解信息
* @param action
* @param methodName
* @return
*/
private SystemPrivilegeAnnotation getMethodSystemPrivilegeAnnotation(
Action action, String methodName) {
try {
// 第二個參數是所求方法的參數列表
Method method = action.getClass()
.getMethod(methodName,new Class[] { ActionMapping.class,
ActionForm.class, HttpServletRequest.class,HttpServletResponse.class });
if (method != null) {
if (method.isAnnotationPresent(SystemPrivilegeAnnotation.class)) {
return method.getAnnotation(SystemPrivilegeAnnotation.class);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 顯示錯誤消息
* @param request
* @param errors
*/
protected void saveErrors(HttpServletRequest request, ActionMessages errors)
{
if(errors == null || errors.isEmpty())
{
request.removeAttribute("org.apache.struts.action.ERROR");
return;
} else
{
request.setAttribute("org.apache.struts.action.ERROR", errors);
return;
}
}
}
第三,別忘了在配置文件struts-config.xml添加controller。
<controller processorClass="common.PrivilegController" contentType="text/html;chatset=utf-8">
</controller>
最後,在需要權限的Action中添加注解就可以。privilegeValue中設置權限值即可。
/**
* 用戶密碼修改初期化
*
* @author wang
*
*/
public class ChangePasswordAction extends Action{
/*
* 用戶密碼修改初期化
*
* @see
*/
@SystemPrivilegeAnnotation(privilegeValue = {"0","1","2","3","4"})
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
。。。。。
}
}
至此,Struts1利用Java注解進行權限控制就基本完成了,思路基本就是如此,方法不一定最好,但是實現需求就好!
最後,這只是在工作中遇到的一個小問題,不一定具有普遍性,自己能力也有限,目前實現的方式就是這樣,如果想到好的會做補充。