方案1(不推荐)
//需要同时维护两个键值对,保证数据一致,很麻烦
private String oldToken = "";
private void redisSaveLoginToken(String userIdMD5, String token) {
String redisKey = RedisConstant.REDIS_USER_PREFIX + userIdMD5;
BoundValueOperations<String, String> operations = stringRedisTemplate.boundValueOps(redisKey);
//替换旧token之前将旧的token保存到成员变量oldToken,如果是第一登录就是null
oldToken = operations.get();
//一个用户绑定一个token,如果用户重复登录根据key相同,对token进行覆盖
if (StringUtils.isNotBlank(token)) {
operations.set(token, RedisConstant.REDIS_TOKEN_TTL, TimeUnit.MINUTES);
}
}
private void redisSaveUserInfo(String token, User user, String remoteAddr) {
//Redis保存最新客户端登录的用户信息
String redisKey = RedisConstant.REDIS_TOKEN_PREFIX + token;
UserDto userDto = new UserDto();
BeanUtils.copyProperties(user, userDto);
userDto.setRemoteAddr(remoteAddr);
String userJSON = JacksonUtil.writeValueAsString(userDto);
log.info("[redisSaveUserInfo] userJSON:{}", userJSON);
try {
stringRedisTemplate.opsForValue().set(redisKey, userJSON, RedisConstant.REDIS_TOKEN_TTL, TimeUnit.MINUTES);
} catch (Exception e) {
log.error("[Redis-addOps]" + e.getMessage());
}
//根据旧token删除Redis旧客户端登录的用户信息(旧token作废),oldToken==null 表示第一次登录
if (StringUtils.isNotBlank(oldToken)) {
log.info("oldToken:{}", oldToken);
String deleteKey = RedisConstant.REDIS_TOKEN_PREFIX + oldToken;
try {
stringRedisTemplate.delete(deleteKey);
} catch (Exception e) {
log.error("[Redis-delOps]" + e.getMessage());
}
}
}
方案2
/**
* 使用hash类型数据结构,Redis就不需要维护两个键值对(userid,token),(token,userInfo)
* 现在只需要维护一个键值对(userid,[token,userInfo]),相同账号重复登录,后面的会踢出前面的token
*
* @param userId
* @param token
* @param userInfo
*/
private void redisSaveTokenAndUserInfo(String userId, String token, String userInfo) {
try {
//单端登录,踢除旧token,即作废旧客户端的token
stringRedisTemplate.delete(userId);
//保存最新的token,一个用户只有redis
BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps(userId);
hashOps.put(token, userInfo);
hashOps.expire(30, TimeUnit.MINUTES);
} catch (Exception e) {
log.error(e.getMessage());
}