1.前言 上次我們認識了java責任鏈模式的設計,那麼接下來將給大家展示責任鏈模式項目中的實際運用。如何快速搭建責任鏈模式的項目中運用。 2.簡單技術準備 我們要在項目中使用藉助這樣的幾個知識的組合運用,才能更好的詮釋。必備技能:簡單註解的定義;Spring攔截器的使用;簡答的責任鏈模式的定義;擁有 ...
1.前言
上次我們認識了java責任鏈模式的設計,那麼接下來將給大家展示責任鏈模式項目中的實際運用。如何快速搭建責任鏈模式的項目中運用。
2.簡單技術準備
我們要在項目中使用藉助這樣的幾個知識的組合運用,才能更好的詮釋。
必備技能:
簡單註解的定義;
Spring攔截器的使用;
簡答的責任鏈模式的定義;
擁有以前的準備的知識點的,我們就可以快速搭建責任鏈來做安全校驗了。
3. 場景模擬
場景:
系統中我們需要一些安全校驗結構,如登陸校驗與角色校驗。接下來我們使用責任鏈模式來開發這個流程化校驗。
4. 設計模式
我們將設計一個web項目,採用springmvc
框架。開發語言使用JAVA。
執行過程執行過程:
SpringMVC攔截器 --- > 攔截指定註解 --- >
進入責任鏈處理
5編碼實戰
5.1 註解定義
定義一個Permission註解
/** * 許可權 攔截 * @author MR.YongGan.Zhang * */ @Inherited @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Permission { VerifyType verifyType() default VerifyType.LOGIN; String[] verifyValue () default ""; } |
其中 是枚舉類型的校驗類型
/** * 校驗的種類 * * NONE 不校驗 * LOGIN 登陸校驗 * ROLE 角色校驗 * * @author MR.YongGan.Zhang * */ public enum VerifyType { NONE, LOGIN, ROLE; } |
5.2攔截器定義
我們定義攔截器PermissionInterceptor,實際上也是註解解析器。我們將藉助於springMVC來做攔截器。
我們使用springMVC
攔截器可以實現 org.springframework.web.servlet.HandlerInterceptor
重寫介面的三個方法即可。
我們一起看看是如何實現的。
import
java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.shsxt.framework.Permission.Permission; import com.shsxt.framework.Permission.handlerchain.PermissionHandlerChainStaticFactory; import com.shsxt.framework.Permission.handlerchain.PermissionWithNone; import com.shsxt.framework.constant.VerifyType; /** * 安全校驗 * * 1. 攔截 用戶是否登陸 * 2. 許可權攔截 * * * @author MR.YongGan.Zhang * @version 1.0.1 * * 備註: 1.0.0 實現用戶登陸攔截 1.0.1 增加實現許可權 * */ public class PermissionInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println(" 進入 PermissionInterceptor 。。。 "); System.err.println(handler.getClass().getName()); if (handler instanceof HandlerMethod) { HandlerMethod hm = (HandlerMethod) handler; Method method = hm.getMethod(); // 如果包含了 Permission 註解 if (method.isAnnotationPresent(Permission.class)) { // Permission permission = method.getAnnotation(Permission.class); // 獲取 註解 中的屬性 VerifyType verifyType = permission.verifyType(); // 獲取許可權校驗值 String[] verifyValue = permission.verifyValue(); // 責任鏈模式 校驗 PermissionWithNone permissionWithNone = PermissionHandlerChainStaticFactory.createPermissionWithNone(); // 執行結果 boolean bool = permissionWithNone.handleChain(verifyType,request,verifyValue); System.err.println(bool); return bool; } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } } |
我們定義好了攔截器,下一步需要將我們攔截器配置給我們springMVC容器中管理
在servlet-context.xml
上配置定義好的攔截器。
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**" /> <mvc:exclude-mapping path="/user/userLogin" /> <mvc:exclude-mapping path="/index" /> <mvc:exclude-mapping path="/css/**" /> <mvc:exclude-mapping path="/images/**" /> <mvc:exclude-mapping path="/jquery-easyui-1.3.3/**" /> <mvc:exclude-mapping path="/js/**" /> <mvc:exclude-mapping path="/zTree_v3/**" /> <bean class="com.shsxt.framework.interceptor.PermissionInterceptor" /> </mvc:interceptor> </mvc:interceptors> |
這樣我們就將攔截器配置給springMVC容器了。
5.3 責任鏈的設計
5.3.1 抽象責任鏈
PermissionAbstractHandlerChain:定義責任鏈處理規則。
/** * 許可權控制 責任鏈 * @author MR.YongGan.Zhang * */ public abstract class PermissionAbstractHandlerChain { // 控制鏈 protected PermissionAbstractHandlerChain successor; public abstract boolean handleChain(VerifyType verifyType, HttpServletRequest request, String[] verifyValue ); public PermissionAbstractHandlerChain getHandlerChain () { return this.successor; } public void setSuccessor (PermissionAbstractHandlerChain successor) { this.successor = successor; } } |
5.3.2 具體業務處理對象
PermissionWithNone PermissionWithLogin
PermissionWithRole 都需要繼承抽象處理鏈。
5.3.2.1. PermissionWithNone 不做校驗
/** * * @author MR.YongGan.Zhang * */ public class PermissionWithNone extends PermissionAbstractHandlerChain { @Override public boolean handleChain(VerifyType verifyType ,HttpServletRequest request ,String[] verifyValue ) { if (verifyType == VerifyType.NONE) { return true; } else { setSuccessor(PermissionHandlerChainStaticFactory.createPermissionWithLogin()); return getHandlerChain().handleChain(verifyType,request,verifyValue); } } } |
5.3.2.2. PermissionWithLogin 登陸校驗
/** * * @author MR.YongGan.Zhang * */ public class PermissionWithLogin extends PermissionAbstractHandlerChain { @Override public boolean handleChain(VerifyType verifyType ,HttpServletRequest request,String[] verifyValue) { if (verifyType == VerifyType.LOGIN) { /** * 實現登陸攔截校驗 */ boolean status = VerificationLoginUtil.isLoginedStatus(request); return status; }else { setSuccessor(PermissionHandlerChainStaticFactory.createPermissionWithRole()); return getHandlerChain().handleChain(verifyType, request, verifyValue); } } } |
備註
boolean status =
VerificationLoginUtil.isLoginedStatus(request);
此處的登陸校驗需要結合實際的業務來做。
5.3.2.3.PermissionWithRole 許可權校驗
/** * @author MR.YongGan.Zhang */ public class PermissionWithRole extends PermissionAbstractHandlerChain { @Override public boolean handleChain(VerifyType verifyType, HttpServletRequest request, String[] verifyValue) { // 角色校驗 實現登陸 if (verifyType == VerifyType.ROLE) { boolean status = VerificationLoginUtil.isLoginedStatus(request); System.out.println(status); if (!status) { return false; } /** * 實現登陸攔截校驗 */ List<String> verify = Arrays.asList(verifyValue); // 用戶包含的許可權【結合實際業務來設計】 List<String> userPermission = (List<String>) request.getSession() .getAttribute(CrmConstant.USER_PERMISSIONS); if (verify != null && verify.size() > 0) { for (String cherck : verify) { boolean flag = userPermission.contains(cherck);// 檢測許可權是否包含 if (!flag) { return flag;// 不包含則返回 false } } } return true; } else { throw new YgException("PS001", "安全校驗 未能識別"); } } } |
5.3.3 處理鏈的靜態工廠設計
/** * 責任鏈 對象的靜態工廠 模式 * @author MR.YongGan.Zhang */ public class PermissionHandlerChainStaticFactory { public static PermissionWithNone createPermissionWithNone(){ return new PermissionWithNone(); } public static PermissionWithLogin createPermissionWithLogin(){ return new PermissionWithLogin(); } public static PermissionWithRole createPermissionWithRole(){ return new PermissionWithRole(); } } |
5.4 如何使用
當我們設計的結構需要進行安全校驗時候,則添加註解
@Permission(
verifyType = VerifyType.ROLE ,verifyValue = {"101011"} )
表示進行角色校驗
需要校驗的值為101011
這就是我們在設計時候,所需要學習的地方。利用註解將我們與業務代碼進行解耦合,在使用責任鏈模式更加具有水平拓展性,以後隨著業務的發展,可以添加黑名單或者白天校驗,以及添加風控系統的對接。