Spring Boot系列-使用自定义注解校验用户是否登录

摘要: 记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。 1、到底是什么是AOP? 所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。

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

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的QQ群架构华山论剑:836442475,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

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:环绕增强;

测试:

fa7a52d0f144fe970d037c599d04fd540aae0ff7

异常测试:

336c61d568cddca2e9eded9d7aa16ef081e08f47

4、定义自定义注解

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

创建一个注解:


@Target({ElementType.METHODElementType.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;

}

}

}

测试未登录:

975601262099724420753547b98e2ca5a6a9a791

测试登录:

c43c4e49812c0f063c8cf5b6061859456feb82ea

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

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

欢迎加入QQ群架构华山论剑:836442475

我们提供免费的架构资料 以及免费的解答

不懂得问题都可以来问我们老师,之后还会有职业生涯规划,以及面试指导

我们每天晚上八点也有公开课免费学习:

10年架构师分享经验,Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

猜你喜欢

转载自blog.csdn.net/Java__moon/article/details/83349031
今日推荐