文章目录
- 1、debug发现问题
- 2、发现 userId 为空
- 3、GuiGuAspect
- 4、@GuiGuLogin
1、debug发现问题

 
2、发现 userId 为空
点击 getUserId() 进入方法内部
package com.atguigu.tingshu.common.util;
/**
 * 获取当前用户信息帮助类
 */
public class AuthContextHolder {
    private static ThreadLocal<Long> userId = new ThreadLocal<Long>();
    private static ThreadLocal<String> username = new ThreadLocal<String>();
    public static void setUserId(Long _userId) {
        userId.set(_userId);
    }
    public static Long getUserId() {
        return userId.get();
    }
    public static void removeUserId() {
        userId.remove();
    }
    public static void setUsername(String _username) {
        username.set(_username);
    }
    public static String getUsername() {
        return username.get();
    }
    public static void removeUsername() {
        username.remove();
    }
}

3、GuiGuAspect
package com.atguigu.tingshu.common.login;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class GuiGuAspect {
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 环绕通知,用于处理登录鉴权
     * 该方法在目标方法执行前后都会执行,用于校验用户是否已经登录
     * 如果用户已经登录,则设置用户ID和用户名到上下文中
     * 如果用户未登录且注解标记为必需登录,则抛出异常
     *
     * @param joinPoint 切入点对象,用于获取目标方法和其参数
     * @param guiGuLogin 注解对象,用于判断是否必需登录
     * @return 目标方法的执行结果
     * @throws Throwable 目标方法可能抛出的异常
     */
    @Around("@annotation(guiGuLogin)")
    public Object auth(ProceedingJoinPoint joinPoint, GuiGuLogin guiGuLogin) throws Throwable {
        // 获取HttpServletRequest对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取token,用于后续的用户身份验证
        String token = request.getHeader("token");
        // 判断token是否为空,如果不为空,则尝试从redis中获取用户信息
        UserInfoVo userInfoVo = null;
        if (StringUtils.isNotBlank(token)){
            // 查询redis中获取用户的登录信息
            userInfoVo = (UserInfoVo)this.redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_KEY_PREFIX + token);
            // 如果获取到用户信息,则将用户ID和用户名设置到上下文中
            if (userInfoVo != null){
                AuthContextHolder.setUserId(userInfoVo.getId());
                AuthContextHolder.setUsername(userInfoVo.getNickname());
            }
        }
        // 如果没有登录并且是必须登录的情况下,应该抛出异常提示未登录
        if (guiGuLogin.required() && userInfoVo == null){
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }
        // 执行目标方法
        Object result = joinPoint.proceed(joinPoint.getArgs());
        // 清除上下文中的用户信息,释放ThreadLocal,防止内存泄漏
        AuthContextHolder.removeUserId();
        AuthContextHolder.removeUsername();
        // 返回目标方法的执行结果
        return result;
    }
}
我们是在切面类 GuiGuAspect 里面获取的 userId ,所以我们需要在指定的方法上面加上 切面注解@GuiGuLogin
4、@GuiGuLogin
package com.atguigu.tingshu.common.login;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GuiGuLogin {
    boolean required() default true;
}

 这样问题就可以得到解决。




















