日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

當線上集群時候,會出現(xiàn)session共享問題。

雖然Tomcat提供了session copy的功能,但是缺點比較明顯:

1:當Tomcat多的時候,session需要大量同步到多臺集群上,占用內(nèi)網(wǎng)寬帶

2:同一個用戶session,需要在多個Tomcat中都存在,浪費內(nèi)存空間。

凱哥推薦:

redis快速入門

【圖文教程】Redis分片集群搭建

【圖文教程】Redis哨兵集群的搭建

【圖文教程】Redis主從集群安裝

【圖文教程】centos單機安裝Redis

Redis實戰(zhàn)9-全局唯一ID

分庫分表之后,ID主鍵如何處理?

如果要替換掉Tomcat的session共享,替代方案應(yīng)該滿足:

1:數(shù)據(jù)共享

2:內(nèi)存存儲

3:keyvalue結(jié)構(gòu)

基于Redis實現(xiàn)共享session登錄

再來回顧下將驗證碼保存在session中業(yè)務(wù)流程

我們在session中存放的是:session.setAttribute("code", code); 因為session的特點,每次訪問都是一個新的sessionId.我們可以直接使用code作為key.思考:那么如果換成了Redis,還能使用code作為可以嗎?

將用戶信息存放在session中流程:

用戶信息在session中存放:session.setAttribute("user", user); 同樣思考:那么如果換成了Redis,還能使用user作為可以嗎?

將code和user信息存放在Redis中,流程如下

驗證碼數(shù)據(jù)結(jié)構(gòu)是:string類型的

用戶對象數(shù)據(jù)類型是:hash類型的

根據(jù)上面分析,我們修改原來代碼:

需要考慮的是:Redis的key規(guī)則、過期時間

1:發(fā)送驗證碼的時候,將驗證碼存放到Redis中時候,需要考慮過期時間。其核心代碼如下:

stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);

2:用戶登錄的時候,校驗驗證碼及將用戶存放返回token

需要考慮的:

1:token不能重復(fù)

2:用戶過期時間

3:登錄成功后,要將token返回給前端

4:用戶只要訪問,Redis中的過期時間就要延長-在攔截器中處理的

用戶登錄核心代碼修改:

//2.1:校驗驗證碼是否正確

//String code = (String) session.getAttribute("code");

String code = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);

if (StringUtils.isEmpty(code) || !code.equals(loginForm.getCode())) {

return Result.fail("驗證碼錯誤!");

//2.2:根據(jù)手機號查詢,如果不存在,創(chuàng)建新用戶

QueryWrApper queryWrapper = new QueryWrapper<>();

queryWrapper.select("id", "phone", "nick_name");

queryWrapper.eq("phone", phone);

User user = this.getOne(queryWrapper);

if (Objects.isNull(user)) {

log.info("新建用戶");

//新建用戶

user = createUserWithPhone(phone);

//2.3:保存用戶到session中

UserDTO userDTO = new UserDTO();

userDTO.setId(user.getId());

userDTO.setIcon(user.getIcon());

userDTO.setNickName(user.getNickName());

//session.setAttribute("user", userDTO);

//2.3.1:獲取隨機的token,作為用戶登錄的令牌

String token = UUID.randomUUID().toString(true);

//2.3.2:將用戶以hash類型存放到Redis中==》將user對象轉(zhuǎn)換成map

//user對象里有非string類型的字段,用這個方法會報錯的

// Map userMap = BeanUtil.beanToMap(userDTO);

Map userMap = BeanUtil.beanToMap(userDTO,new HashMap<>()

, CopyOptions.create()

.setIgnoreNullValue(true)

.setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));

stringRedisTemplate.opsForHash().putAll(LOGIN_USER_TOKEN_KEY+token,userMap);

//LOGIN_USER_TOKEN_TTL

stringRedisTemplate.expire(LOGIN_USER_TOKEN_KEY+token,LOGIN_USER_TOKEN_TTL,TimeUnit.MINUTES);

//2.3.3: 將token返回

return Result.ok(token);

需要注意:

在使用stringRedisTemplate存放hash對象的時候,對象中所有的key只能是string類型,如果存在非string類型會報錯的。所以這里使用了hootool的BeanUtil工具類:

Map userMap = BeanUtil.beanToMap(userDTO,new HashMap<>()

, CopyOptions.create()

.setIgnoreNullValue(true)

.setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));

攔截器修改代碼:

因為攔截器是我們自定義的,所以不能被spring容器管理的,RedisTemplate就不能自動注入了。我們就使用有參構(gòu)造器,傳遞

public class LoginRedisInterceptor implements HandlerInterceptor {

private StringRedisTemplate stringRedisTemplate;

* 因為這個類不能被spring管理,所以不能直接注入RedisTemplate對象。通過構(gòu)造函數(shù)傳遞

* @param stringRedisTemplate

public LoginRedisInterceptor(StringRedisTemplate stringRedisTemplate){

this.stringRedisTemplate = stringRedisTemplate;

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//1:從請求中獲取到token

String token = request.getHeader("authorization");

if(StringUtils.isEmpty(token)){

response.setStatus(401);

return false;

//2:基于token獲取redis中用戶對象

String key = LOGIN_USER_TOKEN_KEY+token;

Map userMap = stringRedisTemplate.opsForHash().entries(key);

//3:判斷

if(userMap.isEmpty()){

response.setStatus(401);

return false;

//將map轉(zhuǎn)對象

UserDTO user = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);

UserHolder.saveUser(user);

//刷新token的過期時間

stringRedisTemplate.expire(key,LOGIN_USER_TOKEN_TTL, TimeUnit.MINUTES);

return true;

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

UserHolder.removeUser();

總結(jié):

在使用Redis替換session的時候,需要考慮的問題:

1:選擇合適的數(shù)據(jù)結(jié)構(gòu)

2:選擇合適的key

3:選擇合適的存儲粒度

 

大家好,我是凱哥JAVA(kaigejava),樂于分享技術(shù)文章,歡迎大家關(guān)注“凱哥Java”,及時了解更多。讓我們一起學Java。也歡迎大家有事沒事就來和凱哥聊聊~~~

分享到:
標簽:Redis
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定