SpringBoot系列之使用自定义注解校验用户是否登录

Stella981
• 阅读 698

记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。

1、到底是什么是AOP?

所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。

2、AOP相关术语

在Spring的AOP中有很多的术语,而且容易混淆,大家一定要先搞清楚这几个概念:

  • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后;

  • 切点(Pointcut:所谓切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点;

  • 增强(Advice:增强是织入到连接点上的一段程序,另外它还拥有连接点的相关信息;

  • 目标对象(Target):增强逻辑的织入目标类,就是我的增强逻辑植入到什么位置;

  • 引介(Introduction:一种特殊的增强,它可以为类添加一些属性喝方法;

  • 织入(Weaving:织入就是讲增强逻辑添加到目标对象的过程;

  • 代理(Proxy:一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;

  • 切面(Aspect:切面由切点和增强组成,他是横切逻辑定义和连接点定义的组成;

3、AOP功能实践

我们这里主要是学习SpringBoot中的一些功能,所以我们这里用的是SpringBoot工程,版本也是最新的2.0.5版本。

创建SpringBoot工程就不说了,我们直接引入Maven的依赖:

<parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.0.5.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
       <java.version>1.8</java.version>
   </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
           <exclusions>
               <exclusion>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-starter-tomcat</artifactId>
               </exclusion>
           </exclusions>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-jetty</artifactId>
       </dependency>

       <!-- 引入AOP -->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-aop</artifactId>
       </dependency>
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.6.1</version>
               <configuration>
                   <source>1.8</source>
                   <target>1.8</target>
               </configuration>
           </plugin>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-surefire-plugin</artifactId>
               <version>2.20</version>
               <configuration>
                   <skip>true</skip>
               </configuration>
           </plugin>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
               <executions>
               </executions>
           </plugin>
       </plugins>
   </build>

首先我们来创建一个Controller类:

@RestController
public class LoginController {

   @GetMapping(value = "/username")
   public String getLoginUserName(String userName, Integer age) {
       
       return userName + " --- " + age;
   }
}

创建切面:

@Aspect
@Component
public class LogAspect {

   /**
    * 功能描述: 拦截对这个包下所有方法的访问
    *
    * @param:[]
    * @return:void
    **/
   @Pointcut("execution(* com.example.springbootaop.controller.*.*(..))")
   public void loginLog() {
   }

   // 前置通知
   @Before("loginLog()")
   public void loginBefore(JoinPoint joinPoint) {

       // 我们从请求的上下文中获取request,记录请求的内容
       ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

       HttpServletRequest request = attributes.getRequest();

       System.out.println("请求路径 : " + request.getRequestURL());
       System.out.println("请求方式 : " + request.getMethod());
       System.out.println("方法名 : " + joinPoint.getSignature().getName());
       System.out.println("类路径 : " + joinPoint.getSignature().getDeclaringTypeName());
       System.out.println("参数 : " + Arrays.toString(joinPoint.getArgs()));
   }

   @AfterReturning(returning = "object", pointcut = "loginLog()")
   public void doAfterReturning(Object object) {

       System.out.println("方法的返回值 : " + object);
   }

   // 方法发生异常时执行该方法
   @AfterThrowing(throwing = "e",pointcut = "loginLog()")
   public void throwsExecute(JoinPoint joinPoint, Exception e) {

       System.err.println("方法执行异常 : " + e.getMessage());
   }

   // 后置通知
   @After("loginLog()")
   public void afterInform() {

       System.out.println("后置通知结束");
   }

   // 环绕通知
   @Around("loginLog()")
   public Object surroundInform(ProceedingJoinPoint proceedingJoinPoint) {

       System.out.println("环绕通知开始...");

       try {
           Object o =  proceedingJoinPoint.proceed();
           System.out.println("方法环绕proceed,结果是 :" + o);
           return o;
       } catch (Throwable e) {
           e.printStackTrace();
           return null;
       }
   }
}

注解概述:

  • @Apsect:将当前类标识为一个切面;

  • @Pointcut:定义切点,这里使用的是条件表达式;

  • **@Before**:前置增强,就是在目标方法执行之前执行;

  • @AfterReturning:后置增强,方法退出时执行;

  • @AfterThrowing:有异常时该方法执行;

  • @After:最终增强,无论什么情况都会执行;

  • @Afround:环绕增强;

测试:

SpringBoot系列之使用自定义注解校验用户是否登录

异常测试:

SpringBoot系列之使用自定义注解校验用户是否登录

4、定义自定义注解

应用场景:在我之前上个项目的时候,有这样一个注解,就是在访问其他接口的时候必须要登录,那么这个时候我们就定义一个注解,让它去对用户是否登录进行校验,那么基于这样的一个场景,我们来定义一个校验登录的注解。

创建一个注解:

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

   String desc() default "验证是否登录";
}

创建一个AOP切面:

@Aspect
@Component
public class LoginAspect {

   @Pointcut(value = "@annotation(com.example.springbootaop.annotation.Auth)")
   public void access() {
   }

   @Before("access()")
   public void before() {

       System.out.println("开始验证用户是否登录...");
   }

   @Around("@annotation(auth)")
   public Object around(ProceedingJoinPoint pj, Auth auth) {

       // 获取注解中的值
       System.out.println("注解中的值 : " + auth.desc());
       try {

           // 检验是否登录 true 已经登录  false 未登录
           Boolean flag = false;

           if (flag == true) {
               return "登录成功";
           } else {
               return "未登录";
           }
       } catch (Throwable throwable) {
           return null;
       }
   }
}

测试未登录:

SpringBoot系列之使用自定义注解校验用户是否登录

测试登录:

SpringBoot系列之使用自定义注解校验用户是否登录

这样我们就可以简单的实现了一个登录校验的注解。

通过今天的分享你会使用AOP和自定义注解了吗?我把源码的地址放在下面,有兴趣的朋友可以看看。

GitHub地址https://github.com/liangbintao/SpringBootIntegration.git

原创不易,如果感觉不错,给个顺便扩散一下吧!

点赞
收藏
评论区
推荐文章
kenx kenx
3年前
SpringBoot Aop 详解和多种使用场景
前言aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例什么是aopAOP(AspectOrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻
推荐学java 推荐学java
2年前
推荐学java——Spring之AOP
tips:本文首发在公众号逆锋起笔,本文源代码在公众号回复aop即可查看。什么是AOP?AOP(AspectOrientProgramming),直译过来就是面向切面编程。AOP是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。为什么需要AOP?实际开发中我们应
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
AOP 你想干什么 IOC 你服务什么
前言:记得N年前,就听过AOP,曾扫过几篇文章,不过看不懂,还是N年前,面试被问到AOP的切面,还是不懂!中秋之假,有点闲,在博客园里搜了下AOP看了看,试图看懂些许文章,可惜文章都说的太中规中矩,没发现一篇能浅显看的易懂的。AOP,全称AspectOrientedProgramming,中文名称叫面向方面编程,也叫面向切面编
Wesley13 Wesley13
3年前
AOP系列
AOP(AspectOrientProgramming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以SpringAOP为代表。本文
Easter79 Easter79
3年前
Spring简介,搭建Spring环境——轻量级容器框架(一)
Spring是什么?      Spring是一个集成了许多第三方框架的大杂烩,其核心技术是IOC(控制反转,也称依赖注入)和AOP(面向切面编程),所以spring既是一个IoC容器,也是一个AOP框架。知道了什么是Spring是学习的开端,下面说一下为什么使用Spring。为什么使用Spring?
Easter79 Easter79
3年前
Spring的AOP逐层深入——AOP的基本原理(六)
什么是AOP    AOP(AspectOrientedProgramming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP基于IoC基础,是对OOP(ObjectOrientedProgramming,面向对象)的延续。同时,AOP实际是GOF设计模式的延续,设计模式孜孜不倦
Easter79 Easter79
3年前
SpringBoot系列之使用自定义注解校验用户是否登录
记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。1、到底是什么是AOP?所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。
Easter79 Easter79
3年前
Spring概念和Bean管理(配置文件)
Spring概念1.spring是开源的轻量级框架(免费,依赖少,可以直接使用)2.spring核心主要两部分:  (1)aop:面向切面编程,扩展功能不是修改源代码实现  (2)ioc:控制反转,  比如有个类,在类里面有个方法(不是静态方法),调用类里面的方法,需要创建类的对象,使用对象调用方法,创
Wesley13 Wesley13
3年前
AOP概念详解笔记
切面(Aspect)一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是一个很好的横切关注点例子。切面用Spring的Advisor或拦截器实现, 然后可以通过@Aspect标注或在applictionContext.xml中进行配置: <aop:aspect id"fourAdviceAspect" r