欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot通用分支處理超級管理員權限邏輯

 更新時間:2022年07月25日 14:29:12   作者:zxhtom  
這篇文章主要為大家介紹了springboot通用分支處理超級管理員的權限邏輯,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

當引入登錄模塊后我們需要做菜單。而菜單自然需要權限的參與,我們在springboot中設計的權限細粒度還算是比較細的。當我們查詢菜單是需要根據權限查找對應的菜單。但是在springboot中我設計了一個底層超級管理員

  • 先來看看我一開始實現這個超級管理員菜單獲取的部分代碼
 if (SecurityUtils.getSubject().hasRole(RoleList.SUPERADMIN)) {
     listemp = customMapper.selectRootMenusByRoleIdList(null,null, null, null);
 } else {
     listemp = customMapper.selectRootMenusByRoleIdList(roleList, oauthClientId,null, moduleCodes);
 }

這樣實現是很正常的思路,通過判斷角色是否是超級管理員來做分支執(zhí)行思路,但是超級管理員可能涉及到多個地方如果在每個地方都這樣if else執(zhí)行的,我覺得有點low, 所以我決定改造一下。不夠最終執(zhí)行的思路依然是if else判斷 。 只不過讓我們在代碼層面上功能間不在那么雜糅在一起

自定義注解

首先我需要兩個注解,SuperDirectionSuperDirectionHandler分別表示需要判斷超級管理員分支和具體管理員分支的目標函數 。 這句話說的還是有點抽象的,容我慢慢道來!

SuperDirection

 @Target({ElementType.TYPE, ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface SuperDirection {
     String value() default StringUtils.EMPTY;
 }

SuperDirectionHandler

 @Target({ElementType.TYPE, ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @Component
 public @interface SuperDirectionHandler {
 }

作用

SuperDirection是用于表明該方法需要進行判斷超級管理員,而value值存儲的就是判斷的表達式。關于這個表達式我們后面介紹

SuperDirectionHandler我們不難發(fā)現他沒有實際屬性但是多了一個@Component注解。目的是方便Spring管理該注解;這樣我們就可以通過Spring來獲取被該注解標注的類了。

位置

該注解釋放給全局使用的,在maltcloud結構介紹中我們知道org.framework.core模塊是所有模塊的基石,所以這兩個注解我選擇在org.framework.core模塊中

切面

  • 我們想在方法執(zhí)行前進行條件判斷,可選方案有很多我們可以在filter中攔截方法進行判斷選擇執(zhí)行哪一個,但是過濾器中我們無法直接獲取到方法的相關信息,注意這里說的是無法直接獲取,如果你想在filter中實現也不是不行,這種方案感興趣的可以試試
  • spring的另外一個特性切面正好符合我們的需求,我們只需要在aroud環(huán)繞方法中實現我們的需要。
  • 首先我們定義一個切點,切點攔截所有被SuperDirection注解標注的類或者方法。
 /**定義一個切點; 攔截所有帶有SuperDirection注解的類和方法*/
 @Pointcut("@annotation(com.github.zxhtom.core.annotaion.SuperDirection) || @within(com.github.zxhtom.core.annotaion.SuperDirection)")
 public void direction() {
 }
  • 這里稍作一下解釋 @annotation用于標識方法上的SuperDirection , @within用于標識在類上的SuperDirection 。
  • 正常我們的一個業(yè)務處理都是放在service層的,spring中的三層架構的service正常是實現一個接口然后實現。所以我們這里在切面中先獲取被攔截對象實現的接口。獲取到接口信息我們通過接口信息獲取該接口在spring中的其它實現類
  • 在spring容器中提供了獲取bean集合的方法,加上我們maltcloud中實現了獲取ApplicationContext的工具類,所以我們通過如下來獲取bean集合
 Map<String, ?> beansOfType = ApplicationContextUtil.getApplicationContext().getBeansOfType(接口class);
  • 獲取到集合了,此時我們還是無法確定哪一個實現類使我們替補執(zhí)行超級管理員的bean 。 這就需要我們SuperDirectionHandler注解了。
  • 這個時候我們在通過Spring獲取被該注解標識的類。這個時候獲取到很多不想關類,我們在和上面的beansOfType進行比對。就可以確定哪一個實現bean是我們需要的。
 @Around("direction()")
 public Object aroud(ProceedingJoinPoint pjp) throws Throwable {
     Class<?>[] inters = pjp.getTarget().getClass().getInterfaces();
     for (Class<?> inter : inters) {
         Map<String, ?> beansOfType = ApplicationContextUtil.getApplicationContext().getBeansOfType(inter);
         Map<String, Object> beansWithAnnotation = ApplicationContextUtil.getApplicationContext().getBeansWithAnnotation(SuperDirectionHandler.class);
         for (Map.Entry<String, ?> entry : beansOfType.entrySet()) {
             if (beansWithAnnotation.containsKey(entry.getKey())) {
                 try {
                     return doOthersHandler(entry.getValue(), pjp);
                 } catch (Exception e) {
                     log.error("分支執(zhí)行失敗,系統(tǒng)判定執(zhí)行原有分支....");
                 }
             }
         }
     }
     return pjp.proceed();
 }
  • 當確定執(zhí)行類之后,我們只需要攜帶著該bean ,在根據SuperDirection上的表達式進行判斷是執(zhí)行超級管理員實現類還是原有實現類的方法了。

條件判斷

  • 在Aspect執(zhí)行中原有方法的執(zhí)行很簡單,只需要pjp.proceed()就可以了。所以這里我們先獲取一下上面獲取到的超級管理員實現bean的對應方法吧。
 MethodSignature msig = (MethodSignature) pjp.getSignature();
 Method targetMethod = value.getClass().getDeclaredMethod(msig.getName(),msig.getParameterTypes());
  • 然后我們在獲取SuperDirection注解信息,因為該注解可能在類上,也可能在方法上,所以這里我們需要處理下
 SuperDirection superDirection = null;
 superDirection = targetMethod.getAnnotation(SuperDirection.class);
 if (superDirection == null) {
     superDirection = pjp.getTarget().getClass().getAnnotation(SuperDirection.class);
 }
  • 最終我們通過注解表達式判斷執(zhí)行情況
 if(selectAnnotationChoiceDo(superDirection)){
     //如果表達式驗證通過,則執(zhí)行替補bean實現類
     return targetMethod.invoke(value,pjp.getArgs());
 }
 //否則執(zhí)行原有bean實現類
 return pjp.proceed();

表達式解析

  • 表達式解析涉及兩個模塊,一個是登錄模塊中獲取當前登錄用戶的角色,另外一個是我們上面提到的表達式解析
  • 獲取當前登錄用戶信息類我在org.framework.web中提供了bean 。 具體的實現由各個登錄子模塊負責去實現,這里我們只需要引入spirng bean使用就要可以了。這里充分體現了模塊拆分的好處了。
  • 至于表達式解析,我選擇放在本模塊中org.framework.commons 。 這里目前簡單提供了幾個表達式解析。
 public interface RootChoiceExpression {
     public boolean haslogined();
     public boolean hasRole(String role);
     public boolean hasAnyRole(String... roles);
 }
  • 他們分別是驗證是否登錄、是否擁有角色和角色組。關于他的視線最終也還是依賴上面提到的org.framework.web模塊中的登錄用戶的信息類
 @Service
 public class DefaultChoiceExpression implements RootChoiceExpression {
     @Autowired
     OnlineSecurity onlineSecurity;
     @Override
     public boolean haslogined() {
         return onlineSecurity.getOnlinePrincipal()!=null;
     }
     @Override
     public boolean hasRole(String role) {
         return onlineSecurity.hasAnyRole(role);
     }
     @Override
     public boolean hasAnyRole(String... roles) {
         return onlineSecurity.hasAnyRole(roles);
     }
 }
  • 這里也算是流出擴展吧,后面根據項目需求我們可以重寫該表達式解析,在根據自己的業(yè)務進行表達式新增。這里僅作為基礎功能
 private boolean selectAnnotationChoiceDo(SuperDirection superDirection) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
     String value = superDirection.value();
     if (StringUtils.isEmpty(value)) {
         return onlineSecurity.getRoleNames().contains(MaltcloudConstant.SUPERADMIN);
     }
     MethodInfo info = selectInfoFromExpression(value);
     Method declaredMethod = expression.getClass().getDeclaredMethod(info.getMethodName(), String.class);
     Object invoke = declaredMethod.invoke(expression, info.getArgs());
     if (invoke != null && invoke.toString().equals("true")) {
         return true;
     }
     return false;
 }
  • 首先根據正則解析出方法名和參數。然后根據反射調用我們spring中表達式bean去執(zhí)行我們在SuperDirection配置的表達式。通過上面我們又能發(fā)現目前表達式僅支持String傳參。因為在SuperDireciton傳遞過來的已經是String了,所以在這里目前我還沒想到如何支持更多類型的數據。先埋坑吧!
  • 該方法最終決定執(zhí)行原生方法還是替補方法。

演示使用

  • 上面說的那么枯燥主要是因為是我的一個設計思路,下面我們來實操感受一下吧。

controller

  • 首先我在controller中開發(fā)一個接口 。這里需要注意下因為我們上面會出現多個實現bean在spring中,所以我們在使用這些接口的時候就不能單純的使用@Autowired了, 而需要通過beanName來使用了。這里名叫commonTestServiceImplCommonTestService接口的普通實現類,用于實現我們正常的操作。
 @RestController
 @RequestMapping(value = "/demo/common")
 public class CommonController {
     @Qualifier(value = "commonTestServiceImpl")
     @Autowired
     CommonTestService commonTestService;
     @RequestMapping(value = "/test",method = RequestMethod.GET)
     public void test() {
         commonTestService.test();
     }
 }

service

  • 這里有兩個實現類分別是CommonTestServiceImpl、CommonTest2ServiceImpl
 @Service
 @SuperDirectionHandler
 public class CommonTest2ServiceImpl implements CommonTestService {
     @Override
     public void test() {
         System.out.println("hello test 2");
     }
 }
 @Service
 @SuperDirection(value = "")
 public class CommonTestServiceImpl implements CommonTestService {
     @Override
     public void test() {
         System.out.println("hello i am test ing ...");
     }
 }
  • 在controller層我們使用的是CommonTestServiceImpl用來實現正常的邏輯。而CommonTest2ServiceImpl是針對超級管理員做的操作。我們就可以進行如上的配置。在SuperDirection中配置空值標識判斷超級管理員進行分支執(zhí)行。你也可以配置目前支持的表達式,我這里簡單點了。
  • 然后通過SuperDirectionHandler標識ConmmonTest2ServiceImpl是替補執(zhí)行。

測試

  • 由于為了簡單測試,我在org.framework.demo.common模塊中還沒有引入login模塊,所以此時登錄用戶獲取類還是我們默認的OnlineSecurityImpl

  • 通過上面代碼我們可以看出來我們當前是沒有角色的,所以我們可以理解成調用接口是沒有超級管理員接口。那么就會執(zhí)行我們CommonTestServiceImpl中的方法。然后我們在將這里的hasAnyRole改成true , 會發(fā)現就會執(zhí)行CommonTest2ServiceImpl里的方法。

總結

  • 經過上面這么折騰,我們就可以在涉及到超級管理員的地方重新實現一下,然后再原有的實現類中只需要專注我們權限架構中的規(guī)則進行數據庫查詢等操作了,而不需要向我一開始那樣為超級管理員進行特殊操作。如果后續(xù)我們需要為特殊用戶進行特殊開發(fā)。我們就可以擴展我們的表達式解析然后再開發(fā)我們備用接口就可以了。
  • 這個思路主要來自于Spring Cloud 中的OpenFeign 的容災降級的思路。

以上就是springboot通用分支處理超級管理員權限邏輯的詳細內容,更多關于springboot通用分支處理權限的資料請關注腳本之家其它相關文章!

相關文章

  • 利用java反射機制調用類的私有方法(推薦)

    利用java反射機制調用類的私有方法(推薦)

    下面小編就為大家?guī)硪黄胘ava反射機制調用類的私有方法(推薦)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • 關于在IDEA中SpringBoot項目中activiti工作流的使用詳解

    關于在IDEA中SpringBoot項目中activiti工作流的使用詳解

    這篇文章主要介紹了關于在IDEA中SpringBoot項目中activiti工作流的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • 8個Spring事務失效場景詳解

    8個Spring事務失效場景詳解

    相信大家對Spring種事務的使用并不陌生,但是你可能只是停留在基礎的使用層面上。今天,我們就簡單來說下Spring事務的原理,然后總結一下spring事務失敗的場景,并提出對應的解決方案,需要的可以參考一下
    2022-12-12
  • 詳解Java環(huán)境變量配置方法(Windows)

    詳解Java環(huán)境變量配置方法(Windows)

    這篇文章主要介紹了Java環(huán)境變量配置方法(Windows),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Java 在PPT中添加混合圖表過程詳解

    Java 在PPT中添加混合圖表過程詳解

    這篇文章主要介紹了Java 在PPT中添加混合圖表過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • 詳解Java的Struts框架以及相關的MVC設計理念

    詳解Java的Struts框架以及相關的MVC設計理念

    這篇文章主要介紹了詳解Java的Struts框架以及相關的MVC設計理念,Struts是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • Java SSM框架(Spring+SpringMVC+MyBatis)搭建過程

    Java SSM框架(Spring+SpringMVC+MyBatis)搭建過程

    最近一段時間搭建了ssm環(huán)境,并測試了幾個小項目,下面小編通過圖文并茂的形式給大家分享Java SSM框架(Spring+SpringMVC+MyBatis)搭建過程,需要的朋友參考下吧
    2017-11-11
  • Java?NIO實現聊天功能

    Java?NIO實現聊天功能

    這篇文章主要為大家詳細介紹了Java?NIO實現聊天功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • java中如何反射獲取一個類

    java中如何反射獲取一個類

    大家說說對java反射的理解,使用反射如何獲取一個類,下面小編給大家整理一些資料,關于java中如何反射獲取一個類,有需要的朋友可以參考下
    2015-08-08
  • IntelliJ IDEA 使用經驗總結(推薦)

    IntelliJ IDEA 使用經驗總結(推薦)

    這篇文章主要介紹了IntelliJ IDEA 使用經驗總結,非常不錯,具有參考價值,需要的朋友可以參考下
    2018-02-02

最新評論