基于拦截器对ThreadLocal的使用

基于拦截器对 ThreadLocal 的使用通常在一些需要处理与当前线程相关的数据的场景中非常有用。 ThreadLocal提供了一种线程范围内的变量存储方式,每个线程都可以独立地对其进行读写而不影响其他线程。

1.创建ThreadLocal的工具类

首先,定义一个ThreadLocal变量,用于存储线程范围内的数据。例如,可以用于存储当前用户的信息。


public class RequestContext {
    private static final ThreadLocal<String> userContext = new ThreadLocal<>();

    /**
     * 设置用户信息
     * @param user
     */
    public static void setUserContext(String user) {
        userContext.set(user);
    }

    /**
     * 得到用户信息
     * @return
     */
    public static String getUserContext() {
        return userContext.get();
    }

    /**
     * 清理用户数据
     */
    public static void clear() {
        userContext.remove();
    }
}

2.创建拦截器

接下来,创建一个拦截器,在请求开始时将用户信息存入 ThreadLocal,在请求结束后清除信息。

@Slf4j
@Configuration
public class MyInterceptor implements HandlerInterceptor {
    @Resource
    private SysUserMapper userMapper;

    /**
     * 添加用户信息缓存和设置ThreadLocal
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(StpUtil.isLogin()){
            // 获取当前会话的 token 值
            String tokenValue = StpUtil.getTokenValue();
            log.info("当前会话的token值"+tokenValue);
            // 获取指定 token 对应的账号id,如果未登录,则返回 null
            String id = (String) StpUtil.getLoginIdByToken(tokenValue);
            log.info(id);
            RequestContext.setUserContext(id);
            SysUser user = (SysUser) RedisUtils.get(id);
            System.out.println(RequestContext.getUserContext());
            if(user==null){
                SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserId, id));
                System.out.println(sysUser);
                RedisUtils.set(id,sysUser,3000);
                log.info(sysUser.toString());
                log.info(id);
            }

        }
        return true;
    }

    /**
     * 清理清理ThreadLocal变量
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清理ThreadLocal变量
        RequestContext.clear();
    }
}

 这里我在处理Token时直接使用了第三方工具satoken,jwt携带的信息只有id信息,这个id我使用了用户id 

3.总结

通过这种方式,ThreadLocal 允许你在整个请求处理期间共享数据,而不必显式地将数据传递到每一个方法中。拦截器确保了 ThreadLocal 数据的初始化和清理,避免了内存泄漏的风险。这在处理用户会话、事务管理或审计日志等需要线程隔离的场景中非常有用。 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个基于 MyBatis 的分页拦截器配置类示例,可以用于实现分页查询: ```java import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.RowBounds; import org.springframework.stereotype.Component; import java.util.Map; import java.util.Properties; @Intercepts(@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {org.apache.ibatis.mapping.MappedStatement.class, Object.class, RowBounds.class, org.apache.ibatis.session.ResultHandler.class})) @Component public class PaginationInterceptor implements Interceptor { private static final String PAGE = "page"; private static final String ROWS = "rows"; @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); RowBounds rowBounds = (RowBounds) args[2]; if (rowBounds != RowBounds.DEFAULT) { // 如果是分页查询,则进行分页处理 args[2] = new RowBounds(getOffset(rowBounds), rowBounds.getLimit()); // 将分页参数设置到 ThreadLocal 中 setPageParameter(rowBounds.getOffset(), rowBounds.getLimit()); } return invocation.proceed(); } private void setPageParameter(int offset, int limit) { Map<String, Object> pageParams = PageContextHolder.getPageParams(); if (pageParams != null) { pageParams.put(PAGE, offset / limit + 1); pageParams.put(ROWS, limit); } } private int getOffset(RowBounds rowBounds) { return rowBounds.getOffset() <= 0 ? 0 : rowBounds.getOffset(); } @Override public Object plugin(Object o) { return o instanceof org.apache.ibatis.executor.Executor ? org.apache.ibatis.plugin.Plugin.wrap(o, this) : o; } @Override public void setProperties(Properties properties) { } } ``` 在这个配置类中,我们定义了一个 `PaginationInterceptor` 拦截器,它实现了 `Interceptor` 接口,可以拦截 MyBatis 的查询方法。在 `intercept` 方法中,我们判断是否为分页查询,如果是,则进行分页处理并将分页参数设置到 `ThreadLocal` 中。在 `setPageParameter` 方法中,我们将分页参数设置到 `Map<String, Object>` 类型的 `PageContextHolder` 中,这个类是一个自定义的上下文工具类,用于存储分页参数。在 `plugin` 方法中,我们将拦截器包装成一个插件,用于拦截 MyBatis 的查询方法,最后在 Spring 容器中将这个拦截器配置为一个 Bean。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值