前后端分离的开发中,用户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 引用
-
-
org.springframework.boot -
spring-boot-starter-aop -
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 getSessionID(Object postData,Class 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
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 getSessionID(Object postData,Class 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;
- }
- }