最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot通用分支處理超級(jí)管理員權(quán)限邏輯

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

前言

當(dāng)引入登錄模塊后我們需要做菜單。而菜單自然需要權(quán)限的參與,我們?cè)趕pringboot中設(shè)計(jì)的權(quán)限細(xì)粒度還算是比較細(xì)的。當(dāng)我們查詢菜單是需要根據(jù)權(quán)限查找對(duì)應(yīng)的菜單。但是在springboot中我設(shè)計(jì)了一個(gè)底層超級(jí)管理員

  • 先來(lái)看看我一開(kāi)始實(shí)現(xiàn)這個(gè)超級(jí)管理員菜單獲取的部分代碼
 if (SecurityUtils.getSubject().hasRole(RoleList.SUPERADMIN)) {
     listemp = customMapper.selectRootMenusByRoleIdList(null,null, null, null);
 } else {
     listemp = customMapper.selectRootMenusByRoleIdList(roleList, oauthClientId,null, moduleCodes);
 }

這樣實(shí)現(xiàn)是很正常的思路,通過(guò)判斷角色是否是超級(jí)管理員來(lái)做分支執(zhí)行思路,但是超級(jí)管理員可能涉及到多個(gè)地方如果在每個(gè)地方都這樣if else執(zhí)行的,我覺(jué)得有點(diǎn)low, 所以我決定改造一下。不夠最終執(zhí)行的思路依然是if else判斷 。 只不過(guò)讓我們?cè)诖a層面上功能間不在那么雜糅在一起

自定義注解

首先我需要兩個(gè)注解,SuperDirectionSuperDirectionHandler分別表示需要判斷超級(jí)管理員分支和具體管理員分支的目標(biāo)函數(shù) 。 這句話說(shuō)的還是有點(diǎn)抽象的,容我慢慢道來(lái)!

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是用于表明該方法需要進(jìn)行判斷超級(jí)管理員,而value值存儲(chǔ)的就是判斷的表達(dá)式。關(guān)于這個(gè)表達(dá)式我們后面介紹

SuperDirectionHandler我們不難發(fā)現(xiàn)他沒(méi)有實(shí)際屬性但是多了一個(gè)@Component注解。目的是方便Spring管理該注解;這樣我們就可以通過(guò)Spring來(lái)獲取被該注解標(biāo)注的類(lèi)了。

位置

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

切面

  • 我們想在方法執(zhí)行前進(jìn)行條件判斷,可選方案有很多我們可以在filter中攔截方法進(jìn)行判斷選擇執(zhí)行哪一個(gè),但是過(guò)濾器中我們無(wú)法直接獲取到方法的相關(guān)信息,注意這里說(shuō)的是無(wú)法直接獲取,如果你想在filter中實(shí)現(xiàn)也不是不行,這種方案感興趣的可以試試
  • spring的另外一個(gè)特性切面正好符合我們的需求,我們只需要在aroud環(huán)繞方法中實(shí)現(xiàn)我們的需要。
  • 首先我們定義一個(gè)切點(diǎn),切點(diǎn)攔截所有被SuperDirection注解標(biāo)注的類(lèi)或者方法。
 /**定義一個(gè)切點(diǎn); 攔截所有帶有SuperDirection注解的類(lèi)和方法*/
 @Pointcut("@annotation(com.github.zxhtom.core.annotaion.SuperDirection) || @within(com.github.zxhtom.core.annotaion.SuperDirection)")
 public void direction() {
 }
  • 這里稍作一下解釋 @annotation用于標(biāo)識(shí)方法上的SuperDirection@within用于標(biāo)識(shí)在類(lèi)上的SuperDirection 。
  • 正常我們的一個(gè)業(yè)務(wù)處理都是放在service層的,spring中的三層架構(gòu)的service正常是實(shí)現(xiàn)一個(gè)接口然后實(shí)現(xiàn)。所以我們這里在切面中先獲取被攔截對(duì)象實(shí)現(xiàn)的接口。獲取到接口信息我們通過(guò)接口信息獲取該接口在spring中的其它實(shí)現(xiàn)類(lèi)
  • 在spring容器中提供了獲取bean集合的方法,加上我們maltcloud中實(shí)現(xiàn)了獲取ApplicationContext的工具類(lèi),所以我們通過(guò)如下來(lái)獲取bean集合
 Map<String, ?> beansOfType = ApplicationContextUtil.getApplicationContext().getBeansOfType(接口class);
  • 獲取到集合了,此時(shí)我們還是無(wú)法確定哪一個(gè)實(shí)現(xiàn)類(lèi)使我們替補(bǔ)執(zhí)行超級(jí)管理員的bean 。 這就需要我們SuperDirectionHandler注解了。
  • 這個(gè)時(shí)候我們?cè)谕ㄟ^(guò)Spring獲取被該注解標(biāo)識(shí)的類(lèi)。這個(gè)時(shí)候獲取到很多不想關(guān)類(lèi),我們?cè)诤蜕厦娴?code>beansOfType進(jìn)行比對(duì)。就可以確定哪一個(gè)實(shí)現(xiàn)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();
 }
  • 當(dāng)確定執(zhí)行類(lèi)之后,我們只需要攜帶著該bean ,在根據(jù)SuperDirection上的表達(dá)式進(jìn)行判斷是執(zhí)行超級(jí)管理員實(shí)現(xiàn)類(lèi)還是原有實(shí)現(xiàn)類(lèi)的方法了。

條件判斷

  • 在Aspect執(zhí)行中原有方法的執(zhí)行很簡(jiǎn)單,只需要pjp.proceed()就可以了。所以這里我們先獲取一下上面獲取到的超級(jí)管理員實(shí)現(xiàn)bean的對(duì)應(yīng)方法吧。
 MethodSignature msig = (MethodSignature) pjp.getSignature();
 Method targetMethod = value.getClass().getDeclaredMethod(msig.getName(),msig.getParameterTypes());
  • 然后我們?cè)讷@取SuperDirection注解信息,因?yàn)樵撟⒔饪赡茉陬?lèi)上,也可能在方法上,所以這里我們需要處理下
 SuperDirection superDirection = null;
 superDirection = targetMethod.getAnnotation(SuperDirection.class);
 if (superDirection == null) {
     superDirection = pjp.getTarget().getClass().getAnnotation(SuperDirection.class);
 }
  • 最終我們通過(guò)注解表達(dá)式判斷執(zhí)行情況
 if(selectAnnotationChoiceDo(superDirection)){
     //如果表達(dá)式驗(yàn)證通過(guò),則執(zhí)行替補(bǔ)bean實(shí)現(xiàn)類(lèi)
     return targetMethod.invoke(value,pjp.getArgs());
 }
 //否則執(zhí)行原有bean實(shí)現(xiàn)類(lèi)
 return pjp.proceed();

表達(dá)式解析

  • 表達(dá)式解析涉及兩個(gè)模塊,一個(gè)是登錄模塊中獲取當(dāng)前登錄用戶的角色,另外一個(gè)是我們上面提到的表達(dá)式解析
  • 獲取當(dāng)前登錄用戶信息類(lèi)我在org.framework.web中提供了bean 。 具體的實(shí)現(xiàn)由各個(gè)登錄子模塊負(fù)責(zé)去實(shí)現(xiàn),這里我們只需要引入spirng bean使用就要可以了。這里充分體現(xiàn)了模塊拆分的好處了。
  • 至于表達(dá)式解析,我選擇放在本模塊中org.framework.commons 。 這里目前簡(jiǎn)單提供了幾個(gè)表達(dá)式解析。
 public interface RootChoiceExpression {
     public boolean haslogined();
     public boolean hasRole(String role);
     public boolean hasAnyRole(String... roles);
 }
  • 他們分別是驗(yàn)證是否登錄、是否擁有角色和角色組。關(guān)于他的視線最終也還是依賴上面提到的org.framework.web模塊中的登錄用戶的信息類(lèi)
 @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);
     }
 }
  • 這里也算是流出擴(kuò)展吧,后面根據(jù)項(xiàng)目需求我們可以重寫(xiě)該表達(dá)式解析,在根據(jù)自己的業(yè)務(wù)進(jìn)行表達(dá)式新增。這里僅作為基礎(chǔ)功能
 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;
 }
  • 首先根據(jù)正則解析出方法名和參數(shù)。然后根據(jù)反射調(diào)用我們spring中表達(dá)式bean去執(zhí)行我們?cè)?code>SuperDirection配置的表達(dá)式。通過(guò)上面我們又能發(fā)現(xiàn)目前表達(dá)式僅支持String傳參。因?yàn)樵?code>SuperDireciton傳遞過(guò)來(lái)的已經(jīng)是String了,所以在這里目前我還沒(méi)想到如何支持更多類(lèi)型的數(shù)據(jù)。先埋坑吧!
  • 該方法最終決定執(zhí)行原生方法還是替補(bǔ)方法。

演示使用

  • 上面說(shuō)的那么枯燥主要是因?yàn)槭俏业囊粋€(gè)設(shè)計(jì)思路,下面我們來(lái)實(shí)操感受一下吧。

controller

  • 首先我在controller中開(kāi)發(fā)一個(gè)接口 。這里需要注意下因?yàn)槲覀兩厦鏁?huì)出現(xiàn)多個(gè)實(shí)現(xiàn)bean在spring中,所以我們?cè)谑褂眠@些接口的時(shí)候就不能單純的使用@Autowired了, 而需要通過(guò)beanName來(lái)使用了。這里名叫commonTestServiceImplCommonTestService接口的普通實(shí)現(xiàn)類(lèi),用于實(shí)現(xiàn)我們正常的操作。
 @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

  • 這里有兩個(gè)實(shí)現(xiàn)類(lèi)分別是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用來(lái)實(shí)現(xiàn)正常的邏輯。而CommonTest2ServiceImpl是針對(duì)超級(jí)管理員做的操作。我們就可以進(jìn)行如上的配置。在SuperDirection中配置空值標(biāo)識(shí)判斷超級(jí)管理員進(jìn)行分支執(zhí)行。你也可以配置目前支持的表達(dá)式,我這里簡(jiǎn)單點(diǎn)了。
  • 然后通過(guò)SuperDirectionHandler標(biāo)識(shí)ConmmonTest2ServiceImpl是替補(bǔ)執(zhí)行。

測(cè)試

  • 由于為了簡(jiǎn)單測(cè)試,我在org.framework.demo.common模塊中還沒(méi)有引入login模塊,所以此時(shí)登錄用戶獲取類(lèi)還是我們默認(rèn)的OnlineSecurityImpl

  • 通過(guò)上面代碼我們可以看出來(lái)我們當(dāng)前是沒(méi)有角色的,所以我們可以理解成調(diào)用接口是沒(méi)有超級(jí)管理員接口。那么就會(huì)執(zhí)行我們CommonTestServiceImpl中的方法。然后我們?cè)趯⑦@里的hasAnyRole改成true , 會(huì)發(fā)現(xiàn)就會(huì)執(zhí)行CommonTest2ServiceImpl里的方法。

總結(jié)

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

以上就是springboot通用分支處理超級(jí)管理員權(quán)限邏輯的詳細(xì)內(nèi)容,更多關(guān)于springboot通用分支處理權(quán)限的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java CRM系統(tǒng)用戶登錄功能實(shí)現(xiàn)代碼實(shí)例

    Java CRM系統(tǒng)用戶登錄功能實(shí)現(xiàn)代碼實(shí)例

    這篇文章主要介紹了Java CRM系統(tǒng)用戶登錄功能實(shí)現(xiàn)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 解答為什么 Java 線程沒(méi)有Running狀態(tài)

    解答為什么 Java 線程沒(méi)有Running狀態(tài)

    Java 線程沒(méi)有Running狀態(tài)指的是一個(gè)在 JVM 中執(zhí)行 的線程處于的狀態(tài),本文小編將為大家詳解一二,需要的朋友可以參考下面文章具體內(nèi)容
    2021-09-09
  • Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié)

    Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié)

    在并發(fā)編程中,合理使用線程中斷機(jī)制可以提高程序的魯棒性和可維護(hù)性,本文主要介紹了Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Java中MapStruct對(duì)象映射的實(shí)現(xiàn)

    Java中MapStruct對(duì)象映射的實(shí)現(xiàn)

    MapStruct是一種Java實(shí)體類(lèi)映射框架,本文就來(lái)介紹一下Java中MapStruct對(duì)象映射的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-12-12
  • SpringCloud基本Rest微服務(wù)工程搭建過(guò)程

    SpringCloud基本Rest微服務(wù)工程搭建過(guò)程

    這篇文章主要介紹了SpringCloud基本Rest微服務(wù)工程搭建,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Java如何獲取接口所有的實(shí)現(xiàn)類(lèi)

    Java如何獲取接口所有的實(shí)現(xiàn)類(lèi)

    這篇文章主要介紹了Java如何獲取接口所有的實(shí)現(xiàn)類(lèi),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • java?使用BeanFactory實(shí)現(xiàn)service與dao層解耦合詳解

    java?使用BeanFactory實(shí)現(xiàn)service與dao層解耦合詳解

    這篇文章主要介紹了java?使用BeanFactory實(shí)現(xiàn)service與dao層解耦合詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 關(guān)于SpringBoot靜態(tài)資源路徑管理問(wèn)題

    關(guān)于SpringBoot靜態(tài)資源路徑管理問(wèn)題

    這篇文章主要介紹了SpringBoot靜態(tài)資源路徑管理,主要包括默認(rèn)靜態(tài)資源路徑,增加靜態(tài)資源路徑前綴的相關(guān)操作,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • 一文帶你了解Java中的Object類(lèi)及類(lèi)中方法

    一文帶你了解Java中的Object類(lèi)及類(lèi)中方法

    Object是Java默認(rèn)提供的一個(gè)類(lèi)。Java里面除了Object類(lèi),所有的類(lèi)都是存在繼承關(guān)系的。默認(rèn)會(huì)繼承Object父?類(lèi)。即所有類(lèi)的對(duì)象都可以使用Object的引用進(jìn)行接收。本文就來(lái)為大家詳細(xì)講講Object類(lèi)及類(lèi)中方法,感興趣的可以了解一下
    2022-08-08
  • java文件讀寫(xiě)工具類(lèi)分享

    java文件讀寫(xiě)工具類(lèi)分享

    這篇文章主要為大家詳細(xì)介紹了java文件讀寫(xiě)工具類(lèi),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02

最新評(píng)論

耒阳市| 乳源| 寿光市| 洮南市| 白山市| 漯河市| 英德市| 子洲县| 吉林省| 江西省| 苍溪县| 思南县| 弥勒县| 拉孜县| 岳池县| 定州市| 襄垣县| 保定市| 安岳县| 金华市| 葫芦岛市| 四子王旗| 延吉市| 乾安县| 盈江县| 鹤山市| 宁海县| 肃北| 镇康县| 禹城市| 赣榆县| 耿马| 东山县| 道真| 台前县| 武山县| 马鞍山市| 威信县| 阿拉善右旗| 新丰县| 黄大仙区|