获取当前用户信息的几种方式

说明:在开发中,我们经常需要获取当前操作的用户信息,如创建用户、创建订单时,我们需要记录下创建人,本文介绍获取当前用户信息的三种方式。

方式一:使用ThreadLocal

ThreadLocal本质上是一个Map,键是当前线程,值是存入的信息。我们可以在用户登录,校验用户信息后,将所需要的用户信息存入到ThreadLocal中,如用户ID、用户Token等,然后在需要的时候直接使用即可。

如下,在preHandle()方法中,将当前用户的ID存入到TokenThreadLocal对象中,

@Component
public class TokenInterceptor implements HandlerInterceptor {@Value("${token.key}")private String tokenKey;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取请求头 拿到TokenString token = request.getHeader("Token");String authToken = request.getHeader("authentication");if (StrUtil.isAllEmpty(token,authToken)){return responseHandler(response);}//  校验Token的合法性和有效性JWT jwt = JWTUtil.parseToken(StrUtil.isBlank(token) ? authToken : token);try {// 校验Token是否合法 校验Token是否过期if (!(jwt.setKey(tokenKey.getBytes()).verify() && jwt.validate(0))){return responseHandler(response);}} catch (Exception e) {// 抛出自定义异常 Token是非法的// throw new RuntimeException(e);return responseHandler(response);}// 把Token的信息解析出来放到ThreadLocalLong id = Convert.toLong(jwt.getPayload("id"));// 设置本地线程池中的用户IDTokenThreadLocal.set(id);// 放行return true;}

本地线程对象,TokenThreadLocal

/*** 本地线程对象** 存放用户ID*/
public class TokenThreadLocal {/*** 创建一个ThreadLocal对象*/private static final ThreadLocal<Long> THREAD_LOCAL= new ThreadLocal<>();/*** 添加一个数据* @param key*/public static void set(Long key){THREAD_LOCAL.set(key);}/*** 获取一个数据* @return*/public static Long get(){return THREAD_LOCAL.get();}/*** 删除一个数据*/public static void remove(){THREAD_LOCAL.remove();}
}

需要的时候,直接调用其get()方法,下面是使用AOP+自定义注解实现对创建、更新操作字段的填充;

在这里插入图片描述

注意,需要在afterCompletion()方法中调用ThreadLocal的remove()方法,避免内存泄漏;

在这里插入图片描述

方式二:通过拦截器和相应注解实现

如果项目中,登录校验框架使用的是Shiro,有一种更方便的方式,如下:

第一步:创建一个自定义注解,如LoginInfo,表示登录用户的信息,注意元注解的属性;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 登录用户* @author */
@Target(value = ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginInfo {
}

第二步:创建MVC的配置类,注入一个在线用户解析对象,后面实现;

import org.decent.modules.integral.resolver.LoginUserArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.util.List;/*** web设置* @author*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Resourceprivate LoginUserArgumentResolver loginUserArgumentResolver;@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {resolvers.add(loginUserArgumentResolver);}
}

第三步:创建在线用户解析类,其中获取当前用户的信息使用的是Shiro框架的方法,SecurityUtils.getSubject().getPrincipal(),该方法返回的是一个Object类型的对象;

import org.apache.shiro.SecurityUtils;
import org.decent.modules.integral.annotation.LoginInfo;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;/*** 登录解析实现** @author*/
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {return methodParameter.hasParameterAnnotation(LoginInfo.class);}@Overridepublic Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {return SecurityUtils.getSubject().getPrincipal();}
}

第四步:创建一个在线用户的JavaBean,存放一些可能会用得上的属性;

import lombok.Data;/*** 在线用户信息*/
@Data
public class LoginUser {/*** 登录人id*/private String id;/*** 登录人账号*/private String username;/*** 登录人名字*/private String realname;
}

第五步:在需要使用的接口上,直接使用注解即可。当请求访问该接口时,会被前面的拦截器拦截住,然后把当前用户的信息取出来并封装到JavaBean对象中,非常方便;

	@PostMapping(value = "/add")public Result<?> add(@LoginInfo LoginUser loginUser) {......}

方式三:使用Redis存储用户信息

这种方式思路和第一种相同,当用户通过校验时,将用户信息查询出来并存起来,需要的时候再取出来用。当然,使用Redis存储比ThreadLocal更灵活一点,可以设置有效时间。实现如下:

第一步:登录验证通过,将用户信息存入Redis;

    @PostMapping("/login")public Result<?> counterLogin(@RequestBody LoginBody LoginUser){// 登录LoginUser userInfo = sysLoginService.login(LoginUser.getUsername(), LoginUser.getPassword(),LoginUser.getCounterType());// 创建Token并返回return Result.success(tokenService.createToken(userInfo));}
     @Autowiredprivate RedisService redisService;// 定义有效时间,为720 * 60 秒,即12小时private final static long EXPIRE_TIME = 720 * 60;/*** 创建令牌*/public Map<String, Object> createToken(LoginUser loginUser){// 生成tokenString token = IdUtils.fastUUID();loginUser.setToken(token);loginUser.setUserid(loginUser.getSysUser().getUserId());loginUser.setUsername(loginUser.getSysUser().getUserName());// 保存用户tokenMap<String, Object> map = new HashMap<String, Object>();map.put("token", token);map.put("loginUser",loginUser);// 将该用户的信息存入到Redis中redisService.setCacheObject(token, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);return map;}

RedisService类相关方法

/*** spring redis 工具类**/
@Component
public class RedisService{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象*/public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 获得缓存的基本对象*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}
}

第三步:需要时,根据当前用户的Token,去Redis中取出该用户的信息;

    /*** 根据用户Token获取用户身份信息** @return 用户信息*/public LoginUser getLoginUser(String token){if (StringUtils.isNotEmpty(token)){String userKey = getTokenKey(token);LoginUser user = redisService.getCacheObject(userKey);return user;}return null;}

用户的Token是需要放在Request对象里面的,所以可以再写一个TokenService对象,用来获取当前用户的Token,并调用RedisService获取当前用户信息,进行进一步的封装。

总结

以上是三种获取当前用户信息的方式,可以根据实际情况选择;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/205739.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年中国感应电炉产业链、产量、销量及市场规模分析[图]

感应电炉行业定义是指使用电磁感应原理&#xff0c;通过感应电流使金属工件在短时间内达到预定温度的工业设备。广泛应用于冶金、机械、汽车、航空、航天、船舶、电子、医疗器械等领域。 感应电炉行业产业链 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; …

简于外 强于内,联想全新ThinkCentre M90a Pro Gen4以强劲性能开启商用新体验

近日&#xff0c;联想发布了最新一代商用台式一体机联想ThinkCentre M90a Pro Gen4。作为联想ThinkCentre M大师系列的旗舰产品&#xff0c;其配备了优质的显示屏&#xff0c;拥有强大的性能和稳定安全的特性&#xff0c;能够满足多样的工作场合&#xff0c;为商用一体机的行业…

MAX/MSP SDK学习06:内存管理

提供两种内存分配方式&#xff1a;①简单指针&#xff0c;②句柄&#xff08;二级指针&#xff09;&#xff1b;官方文档建议使用前者。 // 简单指针 char *ptr; ptr sysmem_newptr(2000); post("I have a pointer %lx and it is %ld bytes in size",ptr, sysmem_p…

git merge 和 git rebase

一、是什么 在使用 git 进行版本管理的项目中&#xff0c;当完成一个特性的开发并将其合并到 master 分支时&#xff0c;会有两种方式&#xff1a; git merge git rebasegit rebase 与 git merge都有相同的作用&#xff0c;都是将一个分支的提交合并到另一分支上&#xff0c;…

代码随想录算法训练营第四十二天【动态规划part04】 | 01背包、416. 分割等和子集

01背包问题 题目链接&#xff1a; 题目页面 求解思路&#xff1a; 确定dp数组及其下标含义&#xff1a;dp[i][j] 表示从下标为 [0] 到 [i] 的物品里任意选取&#xff0c;放进容量为j的背包&#xff0c;此时的价值总和最大值确定递推公式&#xff1a; 不放物品i&#xff0c;…

Apache配置文件详解

引言: Apache是一种功能强大的Web服务器软件,通过配置文件可以对其行为进行高度定制。对于初学者来说,理解和正确配置Apache的配置文件是非常重要的。本文将详细解释Apache配置文件的各个方面,并给出一些入门指南,帮助读者快速上手。 1、主配置文件(httpd.conf): 主…

Springboot-热部署-IDEA2023

方式一&#xff1a;jrebel 方式二&#xff1a; 1、导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <…

连线长光卫星:吉林一号的在线产品与生态体系!

我们在《连线长光卫星&#xff1a;探索卫星应用的更多可能&#xff01;》一文中&#xff0c;通过直播连线嘉宾的分享&#xff0c;让大家了解到了长光卫星的生产基地、三次技术飞跃、亚米级影像产品、150公里大幅宽卫星、卫星在灾害监测及经济分析等多个场景中的应用。 这里我们…

百度发布Q3财报:AI原生应用驱动业绩增长 公司股价应声涨超5%

作为中国科技巨头&#xff0c;百度一直走在人工智能&#xff08;AI&#xff09;技术的前沿。 11月21日&#xff0c;百度发布的第三季度财务报告再次证明了其在AI领域的领先地位。报告显示&#xff0c;第三季度百度实现营收344.47亿元&#xff0c;归属于百度的净利润&#xff0…

基于STM32的电子时钟(论文+源码)

1. 系统设计 电子时钟是一种广泛使用的工具&#xff0c;其可以帮助人们准确掌握时间&#xff0c;本课题基于STM32的电子时钟系统的设计&#xff0c;在功能上设计如下&#xff1a; 具有电子时钟的基本功能&#xff0c;显示年月日&#xff0c;时分秒等基本信息&#xff1b;可以…

Windows常用cmd网络命令详解

中午好&#xff0c;我的网工朋友。 上回给你们梳理了一些有趣的cmd命令&#xff0c;很多朋友希望再拓展一下&#xff0c;这不就来了&#xff1f; 今天从windows切入&#xff0c;给你分享一些常用cmd网络命令&#xff0c;如果能熟悉上手&#xff0c;很多功能都可以快速实现&am…

Threejs_11 补间动画的实现

啥是补间动画呢&#xff1f;其实就是我们在threejs中移动一个物体的时候&#xff0c;不让他是瞬时移动&#xff0c;让他跟css动画的transition一样&#xff0c;有个过度效果&#xff0c;就是补间动画。补间动画如何设置呢&#xff1f; 补间动画实现 1.引入补间动画库 在我们…