ThreadLocal动态获取登录用户的ID

1.工具类

package com.sky.context;

public class BaseContext {

    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

    public static void removeCurrentId() {
        threadLocal.remove();
    }

}

 2.拦截器

package com.sky.interceptor;

import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *  在Handler之前执行。就是Controller中标记了@XxxMapping注解的方式
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);

            //把登录ID设置到ThreadLocal上
            BaseContext.setCurrentId(empId);

            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //从ThreadLocal上删除登录ID
        BaseContext.removeCurrentId();

    }
}

 3.service调用

package com.sky.service.impl;

@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    public Result<String> save(EmployeeDTO employeeDTO) {
        //1、校验参数
        String username = employeeDTO.getUsername();
        String name = employeeDTO.getName();
        String sex = employeeDTO.getSex();
        String phone = employeeDTO.getPhone();

        if (StringUtils.isBlank(username)  //username == null || "".equlas(username)
                ||  StringUtils.isBlank(name)
                || StringUtils.isBlank(sex)
                || StringUtils.isBlank(phone)) {
            throw new ArgsErrorException(MessageConstant.ARGS_ERROR);
        }

        //2、处理业务
        //2.1 判断当前用户名是否已经被注册了
        Employee employee = employeeMapper.getByUsername(username);
        //如果重复,直接返回:用户名已存在
        if(!Objects.isNull(employee)) {
            throw new AccountExistsException(MessageConstant.ACCOUNT_FOUND);
        }
        //2.2 补全实体属性
        Employee emp = new Employee();
        //拷贝的属性名跟类型必须一模一样
        BeanUtils.copyProperties(employeeDTO,emp);
        emp.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
        emp.setStatus(StatusConstant.ENABLE);
        LocalDateTime now = LocalDateTime.now();
        emp.setCreateTime(now);
        emp.setUpdateTime(now);
        // TODO 后面需要动态获取登录用户的ID
        Long id = BaseContext.getCurrentId();

        emp.setCreateUser(id);
        emp.setUpdateUser(id);
        //2.3 保存
        employeeMapper.save(emp);

        //3、封装数据
        return Result.success(MessageConstant.SAVE_SUCCESS);
    }

}

 4.内存泄漏问题?

ThreadLocal是弱引用,在调用gc垃圾处理器的时候,会自动回收。

我们只需要在拦截器的渲染后的方法中调用remove方法即可解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值