关于开发中使用AOP的坑
在一次分布式宾馆管理系统中使用AOP开发中,PointCut连接点是一个注解类@LoginToken,通过该注解类获取前端传送的Token值,直接封装成User,还能根据Token判断用户是否登录,但是在开发中,发现注解类切入点表达式一直报错
注解类@LoginToken
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginToken {
}
注解实现类,如果要经过网关,还需要在网关中配置
zuul: sensitive-headers:
/**
* 根据token返回用户登录的对象,如果没有登录或者token验签错误,返回null
* @param pro
* @param loginToken
* @return
* @throws Throwable
*/
@Aspect
@Slf4j
@Component
public class LoginTokenAOP2 {
@Around("@annotation(loginToken)")//自定义@Around增强,pointcut连接点是使用@@annotation
//------------------------------注意看这里----------------------------------
public Object tokenHandler(LoginToken loginToken,ProceedingJoinPoint pro) throws Throwable{
//-------------------------------------------------------------------------
log.info("注解生效");
//1、获取请求头
//2、判断用户是否携带token
if(StringUtils.isEmpty(token)){
response.setContentType("application/json;charset=utf8");
ObjectMapper mapper = new ObjectMapper();
response.getWriter().write(mapper.writeValueAsString(ResultInfo.error("您还没有登录")));
return null;
}
//3、获取用户的登录信息
String id = JWTUtils.getClaim(token, "id");
if(loginToken.isLogin() && StringUtils.isEmpty(id)){
response.setContentType("application/json;charset=utf8");
ObjectMapper mapper = new ObjectMapper();
response.getWriter().write(mapper.writeValueAsString(ResultInfo.error("您还没有登录")));
return null;
}
//4、封装
User loginUser = new User();
loginUser.setId(Integer.parseInt(id));
log.info("loginUser="+loginUser);
//5、获取切点的参数
Object[] args = pro.getArgs();
for (Object arg : args) {
if(arg.getClass().equals(User.class)){
arg = loginUser;//将用户信息封装到切入点
}
}
Object proceed = pro.proceed(args);
return proceed;//1、获取request对象
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
//2、获取请求头
String token = request.getHeader("Authorization");
log.info("token="+token);
User user = null;
//3、判断用户是否携带token
if(!StringUtils.isEmpty(token)){
//4、token进行验签
ResultInfo require = JWTUtils.require(token);
if(require.isStatus()){
user = new User();
//5、获取用户数据
String id = JWTUtils.getClaim(token, "id");
String username = JWTUtils.getClaim(token, "username");
user.setId(Integer.parseInt(id));
user.setUsername(username);
}
}
//6、获取切点的参数
Object[] args = pro.getArgs();
//细节:使用增强for循环是不能对数据的值进行改变
// for (Object arg : args) {
// if(arg.getClass().equals(User.class)){
// arg = user;//将用户信息封装到切入点
// break;
// }
// }
for (int i = 0; i < args.length; i++) {
if(args[i].getClass().equals(User.class)){
args[i] = user;
}
}
log.info("user="+user);
//7、执行方法
Object proceed = pro.proceed(args);
return proceed;
}
}
Caused by: java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut
经过各种debug发现是参数的顺序错误,将顺序置换即可
//------------------------------注意看这里----------------------------------
public Object tokenHandler(LoginToken loginToken,ProceedingJoinPoint pro) throws Throwable{
//-------------------------------------------------------------------------
修改后
//------------------------------注意看这里----------------------------------
public Object tokenHandler(ProceedingJoinPoint, proLoginToken loginToken) throws Throwable{
//-------------------------------------------------------------------------
修改后程序正常执行,如果还没正常执行,请检查注解的变量名称和表达式的是否保持一致