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

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

        约定:前端http的post 请求

export async function request(url,data) {
    const config = {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
    }
	//每个请求的参数要求附加sessionid, 该sessionid 是登录时生成的
	const paramsData = Object.assign(data,{sessionid:globalData.sessionID || ''})
    config.body = JSON.stringify(paramsData)

    try {
      const res = await window.fetch(url, config)
      if(res.status!==200){
        return {
          status: res.status,
          data:{},
          headers: res.headers,
          url: res.url,
          statusText:res.statusText
        }
      }
    
      return {
        status: res.status,
        data:await res.json(),
        headers: res.headers,
        url: res.url,
      }
    
    } catch (err) {
      return {
        status: 404,
        data:{},
        headers: res.headers,
        url: res.url,
        statusText:'fetch error:'+err.toString()
      }
    }
  }
  

1、在pom.xml 引用

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

2、创建插入标记


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

3、实现切入类


@Aspect
@Component
@Slf4j
public class LoggingAspect {

    @Autowired
    public StringRedisTemplate redisTemplatelocate;

    private  <T> T getSessionID(Object postData,Class<T> clazz){
        return (T)postData;
    }

    @Around("@annotation(Interceptor)") //有标记的地方将实现以下和切入
    public Object logExecutionTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //获取切入方法的参数,就是前部请求的json数据
        Object[] args = proceedingJoinPoint.getArgs();

        //获取其中的sessionid
        // requestBase 实体类只有一个参sessionid , 做为其它实体类的父类,用于接收接口上传的参数。
        RequestBase requestBase=getSessionID(args[0],RequestBase.class);
        log.info("sessionid:{}",requestBase.getSessionid());

        //检测该sessionid 是否存在(redis)
        if (requestBase.getSessionid()==null || !redisTemplatelocate.hasKey(requestBase.getSessionid())) {
            //用户未登陆
            throw new Exception("用户未登陆");
        }

        //获取  request 和 response
        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        log.info("request:{}",servletRequestAttributes.getRequest());
        log.info("response:{}",servletRequestAttributes.getResponse());

        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getMethod().getName();
        Instant startTime = Instant.now();
         //实行被切入的方法
        Object result = proceedingJoinPoint.proceed();
        
        String additionalMessage = methodSignature.getMethod().getAnnotation(Interceptor.class).additionalMessage();
        long elapsedTime = Duration.between(startTime, Instant.now()).toMillis();
        log.info("Class Name: {}, Method Name: {}, Additional Message: {}, Elapsed Time: {}ms",
                className, methodName, additionalMessage, elapsedTime);
        log.info("Result: {}", result);
        return result;
    }
}

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


@RestController
@Slf4j
public class ExampleController {

    @PostMapping("/t1")
    @Interceptor(additionalMessage = "要求检测登录")
    @ResponseBody
    public ResponseEntity<RequestBase> getData(@RequestBody DataRequest req) {
        try {
            return new ResponseEntity<>(req, HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
    }
}

5 实体类


@Data
public class DataRequest extends RequestBase {
    private  String name;
}


@Data
public class RequestBase{
    private String sessionid;
}

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

 @Pointcut("execution(public * com.example.myapp..*.*(..))")

@Aspect
@Component
@Slf4j
public class LoginExecution {

    @Autowired
    public StringRedisTemplate redisTemplatelocate;

    private  <T> T getSessionID(Object postData,Class<T> clazz){
        return (T)postData;
    }

    //切入点: com.aop.ttt 下的所有public 方法
    @Pointcut("execution(public * com.aop.ttt..*.*(..))")
    public void publicMethods() {}

    @Around("publicMethods()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取切入方法的参数,就是前部请求的json数据
        Object[] args = joinPoint.getArgs();

        //获取其中的sessionid
        // requestBase 实体类只有一个参sessionid , 做为其它实体类的父类,用于接收接口上传的参数。
        RequestBase requestBase=getSessionID(args[0],RequestBase.class);
        log.info("sessionid:{}",requestBase.getSessionid());

        //检测该sessionid 是否存在(redis)
        if (requestBase.getSessionid()==null || !redisTemplatelocate.hasKey(requestBase.getSessionid())) {
            //用户未登陆
            throw new Exception("用户未登陆");
        }

        //获取  request 和 response
        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        log.info("request:{}",servletRequestAttributes.getRequest());
        log.info("response:{}",servletRequestAttributes.getResponse());


        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getMethod().getName();
        Instant startTime = Instant.now();
        //实行被切入的方法
        Object result = joinPoint.proceed();


        long elapsedTime = Duration.between(startTime, Instant.now()).toMillis();
        log.info("Class Name: {}, Method Name: {}, Elapsed Time: {}ms",
                className, methodName, elapsedTime);
        log.info("Result: {}", result);
        return result;
    }
}

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 首先需要在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 2. 创建一个切面类,实现对程序运行时长的监控。 ```java @Aspect @Component public class TimeAspect { ThreadLocal<Long> startTime = new ThreadLocal<>(); @Pointcut("execution(* com.example.demo.service.*.*(..))") public void pointcut() {} @Before("pointcut()") public void before(JoinPoint joinPoint) { startTime.set(System.currentTimeMillis()); } @AfterReturning("pointcut()") public void afterReturning(JoinPoint joinPoint) { long time = System.currentTimeMillis() - startTime.get(); System.out.println(joinPoint.getSignature() + " executed in " + time + "ms"); } } ``` 3. 上面的切面类中,定义了一个线程局部变量startTime,用于记录程序开始执行的时间。在切点方法执行前,将当前时间保存在startTime中;在切点方法执行完毕后,用当前时间减去startTime,得到程序的执行时长。最后输出执行时长。 4. 在启动类上加上@EnableAspectJAutoProxy注解,开启AOP功能。 ```java @SpringBootApplication @EnableAspectJAutoProxy public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 5. 在需要进行运行时长监控的方法上添加@LogExecutionTime注解。 ```java @Service public class DemoService { @LogExecutionTime public void execute() throws InterruptedException { Thread.sleep(new Random().nextInt(1000)); } } ``` 6. 最后,执行程序,可以看到输出了程序的运行时长。 ```java @Service public class DemoService { @LogExecutionTime public void execute() throws InterruptedException { Thread.sleep(new Random().nextInt(1000)); } } // 输出:com.example.demo.service.DemoService.execute() executed in 340ms ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值