springboot獲取當前用戶信息的三種方式
說明:在開發(fā)中,我們經(jīng)常需要獲取當前操作的用戶信息,如創(chuàng)建用戶、創(chuàng)建訂單時,我們需要記錄下創(chuàng)建人,本文介紹獲取當前用戶信息的三種方式。
方式一:使用ThreadLocal
ThreadLocal本質(zhì)上是一個Map,鍵是當前線程,值是存入的信息。我們可以在用戶登錄,校驗用戶信息后,將所需要的用戶信息存入到ThreadLocal中,如用戶ID、用戶Token等,然后在需要的時候直接使用即可。
如下,在preHandle()方法中,將當前用戶的ID存入到TokenThreadLocal對象中,
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Value("${token.key}")
private String tokenKey;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 獲取請求頭 拿到Token
String 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的信息解析出來放到ThreadLocal
Long id = Convert.toLong(jwt.getPayload("id"));
// 設(shè)置本地線程池中的用戶ID
TokenThreadLocal.set(id);
// 放行
return true;
}
本地線程對象,TokenThreadLocal
/**
* 本地線程對象
*
* 存放用戶ID
*/
public class TokenThreadLocal {
/**
* 創(chuàng)建一個ThreadLocal對象
*/
private static final ThreadLocal<Long> THREAD_LOCAL= new ThreadLocal<>();
/**
* 添加一個數(shù)據(jù)
* @param key
*/
public static void set(Long key){
THREAD_LOCAL.set(key);
}
/**
* 獲取一個數(shù)據(jù)
* @return
*/
public static Long get(){
return THREAD_LOCAL.get();
}
/**
* 刪除一個數(shù)據(jù)
*/
public static void remove(){
THREAD_LOCAL.remove();
}
}
需要的時候,直接調(diào)用其get()方法,下面是使用AOP+自定義注解實現(xiàn)對創(chuàng)建、更新操作字段的填充;

注意,需要在afterCompletion()方法中調(diào)用ThreadLocal的remove()方法,避免內(nèi)存泄漏;

方式二:通過攔截器和相應(yīng)注解實現(xiàn)
如果項目中,登錄校驗框架使用的是Shiro,有一種更方便的方式,如下:
第一步:創(chuàng)建一個自定義注解,如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 {
}
第二步:創(chuàng)建MVC的配置類,注入一個在線用戶解析對象,后面實現(xiàn);
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設(shè)置
* @author
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private LoginUserArgumentResolver loginUserArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginUserArgumentResolver);
}
}
第三步:創(chuàng)建在線用戶解析類,其中獲取當前用戶的信息使用的是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;
/**
* 登錄解析實現(xiàn)
*
* @author
*/
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(LoginInfo.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
return SecurityUtils.getSubject().getPrincipal();
}
}
第四步:創(chuàng)建一個在線用戶的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更靈活一點,可以設(shè)置有效時間。實現(xiàn)如下:
第一步:登錄驗證通過,將用戶信息存入Redis;
@PostMapping("/login")
public Result<?> counterLogin(@RequestBody LoginBody LoginUser){
// 登錄
LoginUser userInfo = sysLoginService.login(LoginUser.getUsername(), LoginUser.getPassword(),LoginUser.getCounterType());
// 創(chuàng)建Token并返回
return Result.success(tokenService.createToken(userInfo));
}
@Autowired
private RedisService redisService;
// 定義有效時間,為720 * 60 秒,即12小時
private final static long EXPIRE_TIME = 720 * 60;
/**
* 創(chuàng)建令牌
*/
public Map<String, Object> createToken(LoginUser loginUser){
// 生成token
String token = IdUtils.fastUUID();
loginUser.setToken(token);
loginUser.setUserid(loginUser.getSysUser().getUserId());
loginUser.setUsername(loginUser.getSysUser().getUserName());
// 保存用戶token
Map<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類相關(guān)方法
/**
* spring redis 工具類
**/
@Component
public class RedisService{
@Autowired
public 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);
}
}
第三步:需要時,根據(jù)當前用戶的Token,去Redis中取出該用戶的信息;
/**
* 根據(jù)用戶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,并調(diào)用RedisService獲取當前用戶信息,進行進一步的封裝。
總結(jié)
以上是三種獲取當前用戶信息的方式,可以根據(jù)實際情況選擇;更多相關(guān)springboot獲取當前用戶信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中獲取微信用戶信息的方法
- SpringBoot+SpringCloud用戶信息微服務(wù)傳遞實現(xiàn)解析
- Springboot+Shiro記錄用戶登錄信息并獲取當前登錄用戶信息的實現(xiàn)代碼
- SpringBoot使用Redis的zset統(tǒng)計在線用戶信息
- Springboot通過請求頭獲取當前用戶信息方法詳細示范
- SpringBoot登錄、退出、獲取用戶信息的session處理方案
- springboot如何完美通過token獲取用戶信息
- springboot登錄攔截器+ThreadLocal實現(xiàn)用戶信息存儲的實例代碼
- SpringBoot通過參數(shù)注解自動獲取當前用戶信息的方法
- SpringBoot中的ThreadLocal保存請求用戶信息的實例demo
相關(guān)文章
spring中使用@Autowired注解無法注入的情況及解決
這篇文章主要介紹了spring中使用@Autowired注解無法注入的情況及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Spring-Bean創(chuàng)建對象的步驟方式詳解
在本篇文章里小編給大家分享的是關(guān)于Spring-Bean創(chuàng)建對象的步驟方式詳解內(nèi)容,有興趣的朋友們跟著學(xué)習(xí)下。2020-02-02
springboot jackson自定義序列化和反序列化實例
這篇文章主要介紹了spring boot jackson自定義序列化和反序列化實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Java利用 Exchanger 實現(xiàn)游戲中交換裝備
JDK 1.5 開始 JUC 包下提供的 Exchanger 類可用于兩個線程之間交換信息。下面我們就來看看Java是如何利用Exchanger一行代碼實現(xiàn)游戲中交換裝備的2021-09-09
Spring循環(huán)依賴之問題復(fù)現(xiàn)詳解
這篇文章主要為大家詳細介紹了Spring的循環(huán)依賴什么時候會出現(xiàn)以及如何解決循環(huán)依賴,文中的示例代碼講解詳細,感興趣的可以學(xué)習(xí)一下2022-07-07
詳解Spring Cloud 跨服務(wù)數(shù)據(jù)聚合框架
這篇文章主要介紹了詳解Spring Cloud 跨服務(wù)數(shù)據(jù)聚合框架,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03

