首页 > 技术文章 > 关于开发中使用AOP的坑

codeli 2020-09-15 17:24 原文

关于开发中使用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{
//-------------------------------------------------------------------------

修改后程序正常执行,如果还没正常执行,请检查注解的变量名称和表达式的是否保持一致

推荐阅读