1. 需求分析
在登录后,前端每次向后端发起请求都需要携带下发的token,而后端的每个方法都需要效验token是否有效。当然可以提取出公共的方法,但是终归是与我们业务逻辑无关的代码,而且修改需要改动原来的业务代码,造成耦合
而通过注解+AOP就能很好的解耦合,提高扩展性
2. 什么是AOP
说到AOP第一个想到的肯定是面向切面编程。在传统的面向对象编程(OOP)中,横切关注点如日志、事务管理、安全性等通常会散布在多个模块中,这会导致代码的重复和混乱。AOP的目的是通过将这样的关注点从业务逻辑中分离出来,使得它们可以在一个集中的地方被管理和维护。主要分为如下三部分
- 切入点 - 实际增强的方法
- 增强 - 需要实现的增强逻辑代码
- 切面 - 是一个操作,指把增强使用到切入点的过程
3. 实现
在项目的公共模块common-util中创建如下,也可以根据自己项目架构选择
3.1 新建注解 @DaiJiaLogin
//方法前校验是否登录
@Target(ElementType.METHOD) //在方法上生效
@Retention(RetentionPolicy.RUNTIME) //运行时
public @interface DaiJiaLogin {
}
3.2 新建切面类
@Component
@Aspect //切面类
public class DaiJiaAspect {
}
3.3 在切面类中定义增强方法
注意增强方法上标注的是环绕,格式固定,根据自己的项目架构来修改
“execution(* com.charles.daijia..controller..*(…)) *代表任意的权限修饰符 在com.charles.daijia包名下的controller下的任意类里面任意方法,方法能有任意参数(…)
&&
@annotation(daiJiaLogin)” 同时必需要有这个注解才增强方法
@Resource
private RedisTemplate redisTemplate;
@Around("execution(* com.charles.daijia.*.controller.*.*(..)) && @annotation(daiJiaLogin)")
public void process(ProceedingJoinPoint proceedingJoinPoint, DaiJiaLogin daiJiaLogin) throws Throwable {
//获取请求
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
//请求中得到请求头的token
String token = request.getHeader("token");
if(token == null)
throw new DaiJiaException(ResultCodeEnum.LOGIN_AUTH);
//在redis中查找是否存在token
String id = (String) redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_KEY_PREFIX + token);
if(id == null)
throw new DaiJiaException(ResultCodeEnum.LOGIN_AUTH);
//放入localstorage中
AuthContextHolder.setUserId(Long.parseLong(id));
proceedingJoinPoint.proceed();
}
3.4 使用
只需要在响应的方法上标注@DaiJiaLogin
这个注解就能实现我们需求的功能,而不需改动原有的业务代码
//获取登录用户信息
@Operation(summary = "登录后拉取用户信息")
@DaiJiaLogin // 切面增强实现效验登录是否过期
@GetMapping("/getCustomerLoginInfo")
public Result<CustomerLoginVo> getCustomerLoginInfo(){
//直接从threadLocal中获取
Long userId = AuthContextHolder.getUserId();
return Result.ok(customerService.getCustomerLoginInfo(userId));
}