ruoyi的spring cloud项目详解(一)

找不到之前的Github项目了,我把它放在Gitcode上了,这个是别人大佬的项目

GitCode - 全球开发者的开源社区,开源代码托管平台

这是一个微服务项目

我们先看ruoyi-common

ruoyi-common-auth

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.ruoyi.cloud</groupId>
		<artifactId>ruoyi-common</artifactId>
		<version>1.1.0-SNAPSHOT</version>
	</parent>
	<artifactId>ruoyi-common-auth</artifactId>
	<dependencies>
		<!-- 系统模块 -->
		<dependency>
			<groupId>com.ruoyi.cloud</groupId>
			<artifactId>ruoyi-system-api</artifactId>
			<version>${ruoyi.version}</version>
		</dependency>
	</dependencies>
</project>

以下是对这个 `pom.xml` 文件的解释:

1. `<project>` 标签:这是 Maven 项目配置的根标签。 - `xmlns` 和 `xsi:schemaLocation` 属性定义了 Maven POM 模型的命名空间和模式位置。

2. `<modelVersion>` 标签:指定了使用的 Maven 项目对象模型(POM)的版本,这里是 `4.0.0` 。

3. `<parent>` 标签:定义了父项目的坐标,包括组 ID(`com.ruoyi.cloud`)、项目 ID(`ruoyi-common`)和版本(`1.1.0-SNAPSHOT`)。这意味着当前项目继承自这个父项目的配置。

4. `<artifactId>` 标签:指定当前项目的 ID 为 `ruoyi-common-auth` 。

5. `<dependencies>` 标签:用于定义项目的依赖。 - 这里有一个依赖项: - `<groupId>`、`<artifactId>` 和 `<version>` 一起确定了依赖的具体模块。组 ID 为 `com.ruoyi.cloud`,项目 ID 为 `ruoyi-system-api`,版本通过 `${ruoyi.version}` 来引用一个可能在其他地方定义的变量。

回忆一下在pom.xml中parent的作用

在 Maven 的 `pom.xml` 文件中,`<parent>` 元素的主要作用是实现项目配置的继承。 通过指定父项目的坐标(`<groupId>`、`<artifactId>` 和 `<version>`),当前项目可以继承父项目中的以下配置:

1. 依赖管理(`<dependencyManagement>`):父项目中声明的依赖管理配置,子项目可以直接引用,无需重复指定版本等信息。

2. 插件配置(`<pluginManagement>`):父项目中对插件的配置,子项目可以继承和选择性地覆盖。

3. 通用属性:例如项目的编码方式、构建配置等通用属性。 这样可以减少子项目中重复的配置,保持配置的一致性和可维护性。

当多个子项目具有相似的配置需求时,通过一个共同的父项目来定义这些配置可以提高效率和减少错误。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.ruoyi.cloud</groupId>
        <artifactId>ruoyi-cloud</artifactId>
        <version>1.1.0-SNAPSHOT</version>
    </parent>
    <artifactId>ruoyi-common</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>ruoyi-common-core</module>
        <module>ruoyi-common-redis</module>
        <module>ruoyi-common-log</module>
        <module>ruoyi-common-auth</module>
        <module>ruoyi-common-swagger</module>
    </modules>
</project>

那么看父聚合型pom.xml

以下是对这段 `pom.xml` 配置的解析:

1. 根元素 `<project>` 定义了整个 Maven 项目的配置。
    - `xmlns` 和 `xsi:schemaLocation` 定义了 Maven POM 的命名空间和模式位置。
2. `<modelVersion>` 指定了使用的 Maven 项目对象模型版本为 `4.0.0` 。
3. `<parent>` 定义了父项目的信息:
    - `groupId` 为 `com.ruoyi.cloud` 。
    - `artifactId` 为 `ruoyi-cloud` 。
    - `version` 为 `1.1.0-SNAPSHOT` 。当前项目将继承父项目的一些配置。
4. `<artifactId>` 定义当前项目的 ID 为 `ruoyi-common` 。
5. `<packaging>` 被设置为 `pom` ,表示这是一个多模块项目的聚合 POM 。
6. `<modules>` 元素下包含了一系列子模块:
    - `ruoyi-common-core`
    - `ruoyi-common-redis`
    - `ruoyi-common-log`
    - `ruoyi-common-auth`
    - `ruoyi-common-swagger`

总的来说,这是一个多模块 Maven 项目的聚合 POM 配置,定义了父项目以及包含的子模块。

问题:在pom.xml中<modules> 元素的作用

那么我们接着看

com/ruoyi/common/auth/annotation/HasPermissions.java

package com.ruoyi.common.auth.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <p>File:HasPermissions.java</p>
 * <p>Title: 权限注解</p>
 * <p>Description:</p>
 * <p>Copyright: Copyright (c) 2019 2019年6月4日 上午10:43:54</p>
 * <p>Company: </p>
 * @author zmr
 * @version 1.0
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HasPermissions
{
    String value();
}

还记得之前我写过一篇文章说用自定义注解和AOP实现权限控制吗

这段 Java 代码定义了一个自定义的注解 `HasPermissions`

以下是对代码的详细解释:

- `@interface` 关键字用于定义注解。

- `@Target({ElementType.TYPE, ElementType.METHOD})` 表示该注解可以应用于类和方法。

- `@Retention(RetentionPolicy.RUNTIME)` 表示该注解在运行时是可获取的

- 注解中有一个元素 `value` ,使用该注解时需要为其提供一个字符串值。

package com.ruoyi.common.auth.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

这段 Java 代码是在定义一个自定义的注解。

以下是对每行代码的详细解释:

package com.ruoyi.common.auth.annotation;

这行代码指定了该注解所在的包路径为 com.ruoyi.common.auth.annotation 。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

这些是导入了与注解相关的一些类和枚举

  • ElementType :用于指定注解可以应用的元素类型,例如类、方法、变量等。
  • Retention :用于指定注解的保留策略。
  • RetentionPolicy :定义了不同的保留级别,如 SOURCE(在源代码中有效)、CLASS(在编译后的字节码中有效)、RUNTIME(在运行时通过反射可获取)。
  • Target :用于指定注解可以应用的目标元素。

总体来说,这段代码是为后续定义具体的注解属性和行为做准备的。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HasPermissions
{
    String value();
}

这段代码定义了一个名为 `HasPermissions` 的自定义注解。

- `@Target({ElementType.TYPE, ElementType.METHOD})` :表示这个注解可以应用于类(`TYPE`)和方法(`METHOD`)。

- `@Retention(RetentionPolicy.RUNTIME)` :表示该注解在运行时仍然是可获取的,这意味着在程序运行时可以通过反射机制来获取这个注解的信息。

- 注解定义了一个名为 `value` 的属性,类型为 `String` 。在使用这个注解时,必须为 `value` 属性提供一个字符串值。

问题:在java中自定义注解是怎么样的,自定义注解的方法

在 Java 中自定义注解的一般步骤如下:

  1. 使用 @interface 关键字来定义注解:
   public @interface MyAnnotation {
       // 定义注解的属性
   }
  1. 为注解定义属性:

    属性可以是各种基本数据类型、字符串、枚举、其他注解或它们的数组。

    例如:

   public @interface MyAnnotation {
       int number();
       String name();
       MyEnum myEnum();
   }

其中 MyEnum 是一个自定义的枚举类型。

  1. 为属性指定默认值(可选):
   public @interface MyAnnotation {
       int number() default 0;
       String name() default "defaultName";
       MyEnum myEnum() default MyEnum.VALUE1;
   }

4.可以设置属性的访问修饰符,通常为 public 

  1. 应用注解:

    在需要的类、方法、变量等元素上使用自定义的注解。

    例如:

   @MyAnnotation(number = 10, name = "John")
   public class MyClass {
       // 类的内容
   }
  1. 在运行时通过反射机制获取和处理注解信息:

    可以使用 Java 的反射 API 来获取被注解元素上的注解,并获取注解的属性值,从而实现相应的逻辑处理。

自定义注解可以用于实现各种自定义的元数据标记和处理逻辑,增强代码的灵活性和可扩展性。

我们接着看其他代码

com/ruoyi/common/auth/aspect/PreAuthorizeAspect.java

package com.ruoyi.common.auth.aspect;

import java.lang.reflect.Method;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ruoyi.common.auth.annotation.HasPermissions;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ForbiddenException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.system.feign.RemoteMenuService;

import lombok.extern.slf4j.Slf4j;

@Aspect
@Component
@Slf4j
public class PreAuthorizeAspect
{
    @Autowired
    private RemoteMenuService sysMenuClient;

    @Around("@annotation(com.ruoyi.common.auth.annotation.HasPermissions)")
    public Object around(ProceedingJoinPoint point) throws Throwable
    {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        HasPermissions annotation = method.getAnnotation(HasPermissions.class);
        if (annotation == null)
        {
            return point.proceed();
        }
        String authority = new StringBuilder(annotation.value()).toString();
        if (has(authority))
        {
            return point.proceed();
        }
        else
        {
            throw new ForbiddenException();
        }
    }

    private boolean has(String authority)
    {
        // 用超管帐号方便测试,拥有所有权限
        HttpServletRequest request = ServletUtils.getRequest();
        String tmpUserKey = request.getHeader(Constants.CURRENT_ID);
        if (Optional.ofNullable(tmpUserKey).isPresent())
        {
            Long userId = Long.valueOf(tmpUserKey);
            log.debug("userid:{}", userId);
            if (userId == 1L)
            {
                return true;
            }
            return sysMenuClient.selectPermsByUserId(userId).stream().anyMatch(authority::equals);
        }
        return false;
    }
}

这段 Java 代码定义了一个切面(`Aspect`)类 `PreAuthorizeAspect` ,用于进行权限控制的前置处理。 以下是对代码的详细解释:

- `@Aspect` :表明这是一个切面类。

- `@Component` :将该类注册为 Spring 容器中的一个组件。

- `@Slf4j` :用于日志记录。

`@Around("@annotation(com.ruoyi.common.auth.annotation.HasPermissions)")` :定义了一个环绕通知,会在被 `@HasPermissions` 注解标注的方法执行前后进行处理。

`around(ProceedingJoinPoint point)` 方法: - 获取方法的签名和对应的方法对象。

- 尝试获取方法上的 `@HasPermissions` 注解,如果没有则直接执行原方法。

- 获取注解的 `value` 值作为权限标识。

- 通过 `has(String authority)` 方法判断当前用户是否具有该权限,如果有则执行原方法,没有则抛出 `ForbiddenException` 异常。 `has(String authority)` 方法:

- 获取当前的 `HttpServletRequest` 对象。 - 从请求头中获取用户标识。

- 如果用户标识为特定的超级管理员(`userId == 1L` ),则认为具有权限。

- 否则通过调用远程服务 `sysMenuClient.selectPermsByUserId(userId)` 来获取用户的权限列表,并判断是否包含指定的权限。 总的来说,这段代码实现了基于注解和用户权限的访问控制功能。

package com.ruoyi.common.auth.aspect;

import java.lang.reflect.Method;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ruoyi.common.auth.annotation.HasPermissions;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ForbiddenException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.system.feign.RemoteMenuService;

import lombok.extern.slf4j.Slf4j;

这段代码定义了一个基于 `AspectJ` 的切面类 `PreAuthorizeAspect` ,用于进行权限控制的相关处理。 具体来说:

1. 导入了一些必要的类和包,包括反射相关的类、`HttpServletRequest` 、`AspectJ` 的注解、异常类、工具类和远程服务等。

2. 使用 `@Aspect` 注解表明这是一个切面,`@Component` 注解使该类成为 Spring 管理的组件。 3. 定义了一个环绕通知 `around` ,它会在被 `@HasPermissions` 注解修饰的方法执行前后进行处理。 - 首先获取方法上的 `@HasPermissions` 注解信息。 - 然后判断当前用户是否具有指定的权限。如果具有权限,则让被拦截的方法正常执行(`point.proceed()`);如果没有权限,则抛出 `ForbiddenException` 异常。

4. 还有一个 `has` 方法用于具体判断用户是否具有给定的权限。判断逻辑包括如果是超级管理员(用户 ID 为 1)则认为具有权限,否则通过调用远程服务 `RemoteMenuService` 来根据用户 ID 获取权限列表,并检查是否包含给定的权限。 总的来说,这段代码的作用是在方法级别实现权限控制的切面逻辑。

@Aspect
@Component
@Slf4j

以下是对这几个注解的解释:

`@Component`:这是 Spring 框架中的一个注解,用于将类标记为 Spring 管理的组件。被 `@Component` 注解的类会被 Spring 容器自动扫描并实例化,以便在应用中使用。 `

@Aspect`:通常用于面向切面编程(AOP)。它标记一个类为切面类,在这个类中可以定义各种切面逻辑,如前置通知、后置通知、环绕通知等。

`@Slf4j`:这是 `lombok` 库提供的一个注解。它会为类自动生成一个 `Logger` 对象,名为 `log`,方便在类中进行日志记录。

总的来说,这几个注解结合使用,可能是在构建一个结合了 Spring 管理、AOP 切面逻辑以及日志记录功能的组件。

public class PreAuthorizeAspect
{
    @Autowired
    private RemoteMenuService sysMenuClient;

在这段代码中:

`public class PreAuthorizeAspect`:定义了一个名为 `PreAuthorizeAspect` 的公共类。 `@Autowired`:这是 Spring 框架中的注解,用于自动装配(注入)依赖。在这里

,它表示将 `RemoteMenuService` 类型的对象 `sysMenuClient` 自动注入到当前类中,使得在这个类中可以直接使用 `sysMenuClient` 来调用其方法和访问属性。

RemoteMenuService是个啥?选中RemoteMenuService按F4

package com.ruoyi.system.feign;

import java.util.Set;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import com.ruoyi.common.constant.ServiceNameConstants;
import com.ruoyi.system.feign.factory.RemoteMenuFallbackFactory;

/**
 * 菜单 Feign服务层
 * 
 * @author zmr
 * @date 2019-05-20
 */
@FeignClient(name = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteMenuFallbackFactory.class)
public interface RemoteMenuService
{
    @GetMapping("menu/perms/{userId}")
    public Set<String> selectPermsByUserId(@PathVariable("userId") Long userId);
}

这段代码定义了一个名为 `RemoteMenuService` 的 `Feign` 客户端接口,用于与名为 `ruoyi-system` 的服务进行通信,并定义了一个根据用户 ID 获取权限集合的接口方法。

为啥是ruoyi-system,选中ServiceNameConstants.SYSTEM_SERVICE按F4

package com.ruoyi.common.constant;

/**
 * 服务名称
 */
public interface ServiceNameConstants
{
    /**
     * system模块
     */
    String SYSTEM_SERVICE = "ruoyi-system";
}

`@FeignClient` 注解中的 `name` 属性指定了要调用的服务名称,即 `ruoyi-system` 。

我用Ctrl+Shift+r找到了ruoyi-system文件,那么除了找pom.xml还有其他办法找到ruoyi-system这个服务吗?

除了在 `pom.xml` 中,您还可能在以下几个地方找到与 `ruoyi-system` 相关的信息:

1. 项目的配置文件:例如 `application.properties` 或 `application.yml` ,可能会有关于服务的配置信息,包括服务的名称、地址等。

2. 项目的文档:如果项目有详细的文档,可能会在其中说明 `ruoyi-system` 的相关信息,例如其功能、依赖关系、配置方式等。

3. 项目的架构设计文档:如果存在,可能会描述各个模块和服务之间的关系,包括 `ruoyi-system` 。

4. 代码中的其他模块或类:可能在其他与服务调用或集成相关的代码部分会有关于 `ruoyi-system` 的更多信息或引用。

5. 项目的构建脚本或部署配置:比如 `Dockerfile` 、 `Kubernetes` 部署配置等,可能会提及相关服务。

当调用 `selectPermsByUserId` 方法时,`Feign` 会根据配置将请求发送到对应的服务,并处理返回结果。 如果调用过程中出现问题,会按照 `fallbackFactory` 指定的 `RemoteMenuFallbackFactory` 类中的逻辑进行处理,以提供回退机制,增强系统的稳定性和容错性。

我们继续解析这个@Fegin这个接口呗

@GetMapping("menu/perms/{userId}")
    public Set<String> selectPermsByUserId(@PathVariable("userId") Long userId);

使用 `Spring` 的 `@GetMapping` 注解定义的 `HTTP GET` 接口方法。 `@GetMapping("menu/perms/{userId}")` 表示当接收到 `GET` 请求,且请求路径为 `menu/perms/` 后跟一个用户 ID(路径变量)时,会调用这个方法。

`public Set<String> selectPermsByUserId(@PathVariable("userId") Long userId)` 定义了方法的签名。`@PathVariable("userId")` 用于从请求路径中提取出用户 ID,并将其作为一个 `Long` 类型的参数传递给方法。方法返回一个 `String` 类型的集合。

往下面走继续看

com/ruoyi/common/auth/aspect/PreAuthorizeAspect.java

     @Around("@annotation(com.ruoyi.common.auth.annotation.HasPermissions)")
    public Object around(ProceedingJoinPoint point) throws Throwable
    {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        HasPermissions annotation = method.getAnnotation(HasPermissions.class);
        if (annotation == null)
        {
            return point.proceed();
        }
        String authority = new StringBuilder(annotation.value()).toString();
        if (has(authority))
        {
            return point.proceed();
        }
        else
        {
            throw new ForbiddenException();
        }
    }

这段代码定义了一个 `@Around` 环绕通知的方法。 `@Around("@annotation(com.ruoyi.common.auth.annotation.HasPermissions)")` 表示该环绕通知会应用在被 `@HasPermissions` 注解标注的方法上。

这句话通俗来讲就是:如果有某个方法被 `com.ruoyi.common.auth.annotation.HasPermissions` 这个注解标注了,那么在这个方法执行的前后,我(这里指这个 `@Around` 注解所定义的逻辑)就会介入并执行一些额外的操作。

还记的AOP的五种通知吗

: 1. `@Before`(前置通知): - 作用:在目标方法执行之前执行自定义的增强逻辑。 - 特点:无法阻止目标方法的执行,也无法获取目标方法的返回值。

2. `@After`(后置通知): - 作用:在目标方法执行之后执行,无论目标方法是否正常完成或抛出异常。 - 特点:无法获取目标方法的返回值,也无法改变目标方法的执行结果。

3. `@AfterReturning`(返回通知): - 作用:在目标方法正常执行并返回结果之后执行,可以获取到目标方法的返回值,并基于返回值进行额外的处理。 - 特点:只有当目标方法正常完成(没有抛出异常)时才会执行。

4. `@AfterThrowing`(异常通知): - 作用:当目标方法抛出异常时执行,可以获取到抛出的异常对象,并进行异常处理相关的操作。 - 特点:仅在目标方法抛出异常时被触发。

5. `@Around`(环绕通知): - 作用:环绕目标方法的执行,可以在目标方法执行前后进行自定义的处理逻辑。它可以决定是否执行目标方法、修改输入参数、获取返回值、处理异常等。 - 特点:具有最强的控制能力,可以完全控制目标方法的执行流程。

通过合理使用这些通知类型,可以在不修改原有业务代码的情况下,为目标方法添加各种横切关注点的处理逻辑,如日志记录、权限检查、事务管理等。

然后接着解释代码:

public Object around(ProceedingJoinPoint point) throws Throwable
    {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        HasPermissions annotation = method.getAnnotation(HasPermissions.class);
        if (annotation == null)
        {
            return point.proceed();
        }
        String authority = new StringBuilder(annotation.value()).toString();
        if (has(authority))
        {
            return point.proceed();
        }
        else
        {
            throw new ForbiddenException();
        }
    }

 

在方法内部,首先获取方法的相关信息和 `@HasPermissions` 注解。

如果方法上没有这个注解,就直接执行原方法(`point.proceed()`)。 如果获取到了注解,并通过 `has(authority)` 方法验证当前具有指定的权限(`authority`),也执行原方法;

否则,抛出 `ForbiddenException` 异常,表示没有权限。 总的来说,这段代码实现了一个基于权限注解的权限检查逻辑。

说白了,在这个 `around` 方法里呀,它先从传进来的那个 `point` 里拿到方法的一些信息。比如说先拿到签名,然后从签名里搞到方法签名,再从方法签名里拿到具体的方法。接着看看这个方法有没有 `HasPermissions` 这个注解。 要是没有这个注解,那就直接让原来的方法正常运行(通过 `point.proceed()` )。 要是有这个注解,就把注解里设定的值弄出来放到 `authority` 里。然后再去检查有没有这个权限(通过 `has(authority)` 这个不知道具体是啥的检查)。 要是有权限,就让原来的方法正常运行;要是没权限,就抛出一个表示禁止访问的异常。

以上代码用到了has这个方法

   private boolean has(String authority)
    {
        // 用超管帐号方便测试,拥有所有权限
        HttpServletRequest request = ServletUtils.getRequest();
        String tmpUserKey = request.getHeader(Constants.CURRENT_ID);
        if (Optional.ofNullable(tmpUserKey).isPresent())
        {
            Long userId = Long.valueOf(tmpUserKey);
            log.debug("userid:{}", userId);
            if (userId == 1L)
            {
                return true;
            }
            return sysMenuClient.selectPermsByUserId(userId).stream().anyMatch(authority::equals);
        }
        return false;
    }

以下是对 `has` 方法的通俗解释: 这个 `has` 方法主要是用来判断是否具有某个指定的权限。 首先,它通过 `ServletUtils.getRequest` 拿到当前的 `HttpServletRequest` 对象。然后从请求头中获取一个叫 `Constants.CURRENT_ID` 的值,把它转换成 `Long` 类型的 `userId` 。 如果能成功获取到 `userId` ,并且这个 `userId` 是 1 ,就认为有权限,直接返回 `true` 。 如果 `userId` 不是 1 ,就调用 `sysMenuClient.selectPermsByUserId(userId)` 去获取这个用户拥有的权限列表,然后检查这个列表中是否存在当前要判断的 `authority` 权限,如果存在就返回 `true` ,不存在就返回 `false` 。 如果获取 `userId` 失败,就直接返回 `false` ,表示没有权限。

总之,本篇文章我们讲解了com/ruoyi/common/auth/annotation/HasPermissions.java和com/ruoyi/common/auth/aspect/PreAuthorizeAspect.java这两个说白了就是整合了一个注解,将来把这个注解作用在方法上,实现验证

在这个示例中:

- `PreAuthorizeAspect` 这个类整体被称为切面。 -

`@Around("@annotation(com.ruoyi.common.auth.annotation.HasPermissions)")` 标注的 `around` 方法是通知。通俗来讲,通知可以理解为一种 “信号” 或 “触发机制”。当满足通知设置的条件(比如遇到了特定的切点)时,就表示通知被触发了,然后会执行切面中定义的相应逻辑。

这个例子中,当遇到被 HasPermissions 注解修饰的方法(也就是切点)时,@Around 这个通知就被触发了,然后会执行 around 方法里定义的权限检查等逻辑。通知注解要实行切面里的逻辑了,通知触发了切面中定义的与该通知相关的逻辑的执行。

- 被 `@annotation(com.ruoyi.common.auth.annotation.HasPermissions)` 匹配到的、被 `HasPermissions` 注解修饰的方法就是切点。

连接点可以理解为程序执行过程中所有可能被 HasPermissions 注解修饰的方法的执行点。

例如,如果有多个方法都被 HasPermissions 注解修饰了,那么每一个这样的方法的执行时刻都可以被视为一个连接点。但在这个切面中,只有被切点匹配到的连接点(即被指定注解修饰的方法的执行点)才会触发通知(around 方法)的执行。

总结来说,切面是包含了通知逻辑的类,通知是具体的增强处理逻辑(在这个例子中就是 `around` 方法里的处理),切点是定义了在哪些具体位置应用通知的点。

在这个示例中,Spring AOP 会创建一个代理对象来代理被 `@HasPermissions` 注解修饰的方法所属的目标对象。

具体来说,当调用被注解修饰的方法(比如 `performAdminOperation` 方法)时,实际上是由 Spring 创建的代理对象来处理这个调用代理对象会在方法执行前后插入切面中定义的权限检查等增强逻辑。 所以可以说是代理对象代理了包含被注解修饰方法的目标对象。

我们下期再见!

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值