如何使用springAop实现拦截目标方法,并且给目标方法传值,实现权限等功能
今天需要加一个需求。
大致意思是用户可以切换为其他用户的角色,用其他用户的角色权限进行各种操作。
在项目本身是有个缓存去保存用户的登录信息的。
简单一点的做法,在所有涉及到角色权限的方法上,都加一个方法进行判断用户是否使用的其他角色权限。
不过由于涉及的方法实在太多,如果这么做的话势必会增加很多工作量导致代码臃肿重复。
那么我想应该是可以通过Spring AOP面向切面实现的。
在不修改原代码的情况给目标方法增加新的功能。
在项目中新建一个类ApplyOrderAspect
具体实现方法如下
@Slf4j
@Component
@Aspect
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ApplyOrderAspect {
private final UserAuthorizeMapper userAuthorizeMapper;
private final ApplyOrderDao orderDao;
private final UserMapper userMapper;
@Pointcut("@annotation(com.XXX.GetUserInfo)")
public void getUserInfo(){}
@Around("getUserInfo()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("进入切面。。。before");
Object[] args = joinPoint.getArgs();
// 识别当前登录者的身份
User user = orderDao.getUser();
// 判断是否切换了其他角色的权限
UserAuthorize userAuthorize = userAuthorizeMapper.selectOne(new LambdaQueryWrapper<UserAuthorize>()
.eq(UserAuthorize::getAuthorizeUserId, user.getId())
.eq(UserAuthorize::getOperation, ConstantCode.ONE));
if(ObjectUtils.isNotEmpty(userAuthorize)){
LocalDateTime nowTime= LocalDateTime.now();
if(nowTime.isAfter(userAuthorize.getStartTime()) && nowTime.isBefore(userAuthorize.getEndTime())){
User otherUser = userMapper.selectById(userAuthorize.getUserId());
args[0] = otherUser;
}else {
throw new BizException(1008,"You are not authorized to operate as "+userAuthorize.getUserName());
}
}else {
args[0] = user;
}
return joinPoint.proceed(args);
}
}
以上为具体代码实现
ProceedingJoinPoint这个类比较关键,它继承了JointPoint。
可以通过反射的方式获取到目标方法的入参。
Object[] args = joinPoint.getArgs();
获取到的参数为数组形式。
定义切入点方法getUserInfo(),使用@Pointcut注解指定一个注解类
在拦截方法上around()上加上注解@Around(“getUserInfo()”),这个是表明使用注解拦截目标方法。在所需要拦截的方法上加上 @GetUserInfo注解
接下来再看看业务代码service和impl中是怎么接受值的
我是直接在传参中 new User(),需要放在方法参数第一个,因为在拦截器中被赋值到了数组第一个args[0] = user,
然后再具体的impl实现类中
方法体上加上注解 @GetUserInfo,表明这个方法被拦截,User中也能被注入相应的值
虽然拦截目标方法很多忠,比如拦截具体方法,拦截某个类中所有方法等,但对于后期突然增加的需求,使用注解的方式比较方便。