相逢即是 緣 ,路過點個 贊 ^.^java
源碼:https://github.com/yulc-coding/java-note/tree/master/aopgit
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- AOP 切面-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
複製代碼
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VisitPermission {
/**
* 用於配置具體接口的權限值
* 在數據庫中添加對應的記錄
* 用戶登陸時,將用戶全部的權限列表放入redis中
* 用戶訪問接口時,將對應接口的值和redis中的匹配看是否有訪問權限
* 用戶退出登陸時,清空redis中對應的權限緩存
*/
String value() default "";
}
複製代碼
@RestController
@RequestMapping("/permission")
public class PermissionController {
/**
* 配置權限註解 @VisitPermission("permission-test")
* 只用擁有該權限的用戶才能訪問,不然提示非法操做
*/
@VisitPermission("permission-test")
@GetMapping("/test")
public String test() {
System.out.println("================== step 3: doing ==================");
return "success";
}
}
複製代碼
設置切入點爲@annotation(VisitPermission)
獲取請求中的token,校驗是否token是否過時或合法
獲取註解中的權限值,校驗當前用戶是否有訪問權限
MongoDB 記錄訪問日誌(IP、參數、接口、耗時等)github
@Aspect
@Component
public class PermissionAspect {
/**
* 切入點
* 切入點爲包路徑下的:execution(public * org.ylc.note.aop.controller..*(..)):
* org.ylc.note.aop.Controller包下任意類任意返回值的 public 的方法
* <p>
* 切入點爲註解的: @annotation(VisitPermission)
* 存在 VisitPermission 註解的方法
*/
@Pointcut("@annotation(org.ylc.note.aop.annotation.VisitPermission)")
private void permission() {
}
/**
* 目標方法調用以前執行
*/
@Before("permission()")
public void doBefore() {
System.out.println("================== step 2: before ==================");
}
/**
* 目標方法調用以後執行
*/
@After("permission()")
public void doAfter() {
System.out.println("================== step 4: after ==================");
}
/**
* 環繞
* 會將目標方法封裝起來
* 具體驗證業務數據
*/
@Around("permission()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("================== step 1: around ==================");
long startTime = System.currentTimeMillis();
/*
* 獲取當前http請求中的token
* 解析token :
* 一、token是否存在
* 二、token格式是否正確
* 三、token是否已過時(解析信息或者redis中是否存在)
* */
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
throw new RuntimeException("非法請求,無效token");
}
// 校驗token的業務邏輯
// ...
/*
* 獲取註解的值,並進行權限驗證:
* redis 中是否存在對應的權限
* redis 中沒有則從數據庫中獲取權限
* 數據空中沒有,拋異常,非法請求,沒有權限
* */
Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
VisitPermission visitPermission = method.getAnnotation(VisitPermission.class);
String value = visitPermission.value();
// 校驗權限的業務邏輯
// List<Object> permissions = redis.get(permission)
// db.getPermission
// permissions.contains(value)
// ...
System.out.println(value);
// 執行具體方法
Object result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
/*
* 記錄相關執行結果
* 能夠存入MongoDB 後期作數據分析
* */
// 打印請求 url
System.out.println("URL : " + request.getRequestURL().toString());
// 打印 Http method
System.out.println("HTTP Method : " + request.getMethod());
// 打印調用 controller 的全路徑以及執行方法
System.out.println("controller : " + proceedingJoinPoint.getSignature().getDeclaringTypeName());
// 調用方法
System.out.println("Method : " + proceedingJoinPoint.getSignature().getName());
// 執行耗時
System.out.println("cost-time : " + (endTime - startTime) + " ms");
return result;
}
}
複製代碼
package org.ylc.note.aop;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.ylc.note.aop.controller.PermissionController;
@SpringBootTest
class AopApplicationTests {
@Autowired
private PermissionController permissionController;
private MockMvc mvc;
@BeforeEach
void setupMockMvc() {
mvc = MockMvcBuilders.standaloneSetup(permissionController).build();
}
@Test
void apiTest() throws Exception {
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/permission/test")
.accept(MediaType.APPLICATION_JSON)
.header("token", "9527"))
.andReturn();
System.out.println("api test result : " + result.getResponse().getContentAsString());
}
}
複製代碼