• spring boot 使用AOP实现是否已登录检测


            前后端分离的开发中,用户http请求应用服务的接口时, 如果要求检测该用户是否已登录。可以实现的方法有多种, 本示例是通过aop 的方式实现,简单有效。

            约定:前端http的post 请求

    1. export async function request(url,data) {
    2. const config = {
    3. method: 'POST',
    4. headers: {'Content-Type': 'application/json'},
    5. }
    6. //每个请求的参数要求附加sessionid, 该sessionid 是登录时生成的
    7. const paramsData = Object.assign(data,{sessionid:globalData.sessionID || ''})
    8. config.body = JSON.stringify(paramsData)
    9. try {
    10. const res = await window.fetch(url, config)
    11. if(res.status!==200){
    12. return {
    13. status: res.status,
    14. data:{},
    15. headers: res.headers,
    16. url: res.url,
    17. statusText:res.statusText
    18. }
    19. }
    20. return {
    21. status: res.status,
    22. data:await res.json(),
    23. headers: res.headers,
    24. url: res.url,
    25. }
    26. } catch (err) {
    27. return {
    28. status: 404,
    29. data:{},
    30. headers: res.headers,
    31. url: res.url,
    32. statusText:'fetch error:'+err.toString()
    33. }
    34. }
    35. }

    1、在pom.xml 引用

    1. org.springframework.boot
    2. spring-boot-starter-aop

    2、创建插入标记

    1. @Target({ElementType.METHOD}) // 只在对象方法上标记
    2. @Retention(RetentionPolicy.RUNTIME) //运行时反射
    3. public @interface Interceptor {
    4. String additionalMessage() default "";
    5. }

    3、实现切入类

    1. @Aspect
    2. @Component
    3. @Slf4j
    4. public class LoggingAspect {
    5. @Autowired
    6. public StringRedisTemplate redisTemplatelocate;
    7. private T getSessionID(Object postData,Class clazz){
    8. return (T)postData;
    9. }
    10. @Around("@annotation(Interceptor)") //有标记的地方将实现以下和切入
    11. public Object logExecutionTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    12. //获取切入方法的参数,就是前部请求的json数据
    13. Object[] args = proceedingJoinPoint.getArgs();
    14. //获取其中的sessionid
    15. // requestBase 实体类只有一个参sessionid , 做为其它实体类的父类,用于接收接口上传的参数。
    16. RequestBase requestBase=getSessionID(args[0],RequestBase.class);
    17. log.info("sessionid:{}",requestBase.getSessionid());
    18. //检测该sessionid 是否存在(redis)
    19. if (requestBase.getSessionid()==null || !redisTemplatelocate.hasKey(requestBase.getSessionid())) {
    20. //用户未登陆
    21. throw new Exception("用户未登陆");
    22. }
    23. //获取 request 和 response
    24. ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
    25. log.info("request:{}",servletRequestAttributes.getRequest());
    26. log.info("response:{}",servletRequestAttributes.getResponse());
    27. MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
    28. String className = methodSignature.getDeclaringType().getSimpleName();
    29. String methodName = methodSignature.getMethod().getName();
    30. Instant startTime = Instant.now();
    31. //实行被切入的方法
    32. Object result = proceedingJoinPoint.proceed();
    33. String additionalMessage = methodSignature.getMethod().getAnnotation(Interceptor.class).additionalMessage();
    34. long elapsedTime = Duration.between(startTime, Instant.now()).toMillis();
    35. log.info("Class Name: {}, Method Name: {}, Additional Message: {}, Elapsed Time: {}ms",
    36. className, methodName, additionalMessage, elapsedTime);
    37. log.info("Result: {}", result);
    38. return result;
    39. }
    40. }

    4 建立api接口,在需要检测的方法上加入@Interceptor 就完成切入的检测。

    1. @RestController
    2. @Slf4j
    3. public class ExampleController {
    4. @PostMapping("/t1")
    5. @Interceptor(additionalMessage = "要求检测登录")
    6. @ResponseBody
    7. public ResponseEntity getData(@RequestBody DataRequest req) {
    8. try {
    9. return new ResponseEntity<>(req, HttpStatus.OK);
    10. } catch (Exception e) {
    11. return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
    12. }
    13. }
    14. }

    5 实体类

    1. @Data
    2. public class DataRequest extends RequestBase {
    3. private String name;
    4. }
    5. @Data
    6. public class RequestBase{
    7. private String sessionid;
    8. }

       该方法只适用于少部分需要检测,而大部份不需要检测的情况下,如果整个包都需要检测的,利用execution方 法实现

     @Pointcut("execution(public * com.example.myapp..*.*(..))")
    1. @Aspect
    2. @Component
    3. @Slf4j
    4. public class LoginExecution {
    5. @Autowired
    6. public StringRedisTemplate redisTemplatelocate;
    7. private T getSessionID(Object postData,Class clazz){
    8. return (T)postData;
    9. }
    10. //切入点: com.aop.ttt 下的所有public 方法
    11. @Pointcut("execution(public * com.aop.ttt..*.*(..))")
    12. public void publicMethods() {}
    13. @Around("publicMethods()")
    14. public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
    15. //获取切入方法的参数,就是前部请求的json数据
    16. Object[] args = joinPoint.getArgs();
    17. //获取其中的sessionid
    18. // requestBase 实体类只有一个参sessionid , 做为其它实体类的父类,用于接收接口上传的参数。
    19. RequestBase requestBase=getSessionID(args[0],RequestBase.class);
    20. log.info("sessionid:{}",requestBase.getSessionid());
    21. //检测该sessionid 是否存在(redis)
    22. if (requestBase.getSessionid()==null || !redisTemplatelocate.hasKey(requestBase.getSessionid())) {
    23. //用户未登陆
    24. throw new Exception("用户未登陆");
    25. }
    26. //获取 request 和 response
    27. ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
    28. log.info("request:{}",servletRequestAttributes.getRequest());
    29. log.info("response:{}",servletRequestAttributes.getResponse());
    30. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    31. String className = methodSignature.getDeclaringType().getSimpleName();
    32. String methodName = methodSignature.getMethod().getName();
    33. Instant startTime = Instant.now();
    34. //实行被切入的方法
    35. Object result = joinPoint.proceed();
    36. long elapsedTime = Duration.between(startTime, Instant.now()).toMillis();
    37. log.info("Class Name: {}, Method Name: {}, Elapsed Time: {}ms",
    38. className, methodName, elapsedTime);
    39. log.info("Result: {}", result);
    40. return result;
    41. }
    42. }

  • 相关阅读:
    100行代码教你写个卡牌翻翻乐小游戏
    项目管理工具DHTMLX Gantt灯箱元素配置教程:文本区域控件设置
    【c++学习笔记】-1 基础
    Nacos-SpringBoot-配置中心
    Helm扩展
    C++类详解
    MySQL 数据库 基础(一)
    linux 配置 NTP 服务器
    SAP ABAP——数据类型(四)【TYPE系列关键字】
    中国数据中台未来会怎样?三个趋势预测为您指明方向
  • 原文地址:https://blog.csdn.net/ganyuanmen/article/details/136129364