java責任鏈模式及項目實際運用


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
 
這就是我們在設計時候,所需要學習的地方。利用注解將我們與業務代碼進行解耦合,在使用責任鏈模式更加具有水平拓展性,以后隨着業務的發展,可以添加黑名單或者白天校驗,以及添加風控系統的對接。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM