Easymall項目分佈式拆分整合(八)
目錄
一.User用戶系統的2個延伸問題
1.登錄頂替
- 每次登錄時,利用唯一值判斷當前用戶是否曾經登錄過; user_id相關,value就是登錄時創建的ticket
- 發現沒有key,從來沒有登陸過,直接執行登錄邏輯
- 發現有值,有人曾經登錄過,獲取ticket,del刪除,執行後續登錄邏輯
1.UserController類
//驗證登錄的用戶名密碼是否正確
@RequestMapping("login")
public String doLogin(User user){
String ticket=userService.doLogin(user);
//成功登錄返回redis的key,失敗返回""
return ticket;
}
2.UserService類
@Autowired
private RedisCumUtils redis;
public String doLogin(User user) {
//查詢一下數據庫數據,是否存在userExist
//處理用戶密碼加密
user.setUserPassword(MD5Util.md5(user.getUserPassword()));
User exist=userMapper.selectExist(user);
try{
if(exist==null){//登錄失敗
return "";
}else{
//通過唯一值確定是否已經存在
String alterKey="alterKey_"+exist.getUserId();
if(redis.isExist(alterKey)){
redis.delete(redis.query(alterKey));
}
//表示成功,存儲在redis返回key值
String ticket=MD5Util.md5("EM_TICKET"+System.currentTimeMillis()
+exist.getUserId());
//準備value值,mapper轉化user爲json字符串
String userJson=MapperUtils.MP.writeValueAsString(exist);
//set數據到redis供後續邏輯使用
redis.addOrUpdateExpire(ticket, userJson, 60*30);
//生產一個
redis.addOrUpdate(alterKey, ticket);
//驗證最多一個用戶登錄,頂替登錄邏輯
//TODO
return ticket;
}
}catch(Exception e){
e.printStackTrace();
return "";
}
}
在登錄方法裏先做判斷,獲取當前值,判斷是否已經存在,如果存在,把之前的值刪除,保存新的數據
2.30分鐘超時突然斷開
用戶在訪問系統過程中,總是通過redis的ticket來判斷登錄用戶的狀態,獲取用戶的信息,從而進行各種操作(購物車,訂單提交)
一旦數據超時30分鐘,就會突然在用戶瀏覽器無法訪問使用用戶登錄狀態;
1.解決辦法:實現續租邏輯
每次校驗登錄狀態,判斷剩餘時間ttl,如果發現登錄狀態的ticket在操作時,判斷剩餘時間小於10分鐘,續租5分鐘
工具類封裝方法
1.判斷剩餘時間
//拿到剩餘時間
public Long queryTimeLeft(String key){
ShardedJedis jedis = pool.getResource();
try{
return jedis.ttl(key);
}catch(Exception e){
e.printStackTrace();
return 0l;
}finally{
pool.returnBrokenResource(jedis);
}
}
2.延長時間
//延遲時間
public void expandTime(String key,Integer seconds){
ShardedJedis jedis = pool.getResource();
try{
jedis.expire(key, seconds);
}catch(Exception e){
e.printStackTrace();
}finally{
pool.returnBrokenResource(jedis);
}
}
2.UserController類
//校驗登錄狀態,查詢redis數據
@RequestMapping("query/{ticket}")
public String checkTicket(@PathVariable String ticket
,String callback){
try{
//走到redis校驗數據
String userJson=userService.queryTicket(ticket);
//封裝返回的json數據,SysResult
SysResult result=null;
if(StringUtils.isNotEmpty(userJson)){//登錄狀態正常
result=SysResult.build(200, "", userJson);
}else{
result=SysResult.build(201, "", null);
}
//將result解析成json等待返回使用
String resultJson=MapperUtils.MP.writeValueAsString(result);
//判斷請求需要的數據格式,callback
if(callback==null){
return resultJson;//作爲json字符串返回
}else{
return callback+"("+resultJson+")";//jsonp格式返回
}
}catch(Exception e){
return "";
}
}
3.userService類
public String queryTicket(String ticket) {
//TODO 超時時間延長--續租
//每次訪問到這個方法,都是由於用戶訪問了head.jsp的js代碼
//判斷剩餘時間
Long time=redis.queryTimeLeft(ticket);
if(time<60*10){//將時間添加5分鐘做續租
Integer extTime=(int) (time+60*5);
redis.expandTime(ticket, extTime);
}
return redis.query(ticket);
}