1. 程式人生 > >Spring Boot系列-使用自定義註解校驗使用者是否登入

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、分散式、高併發等架構技術