<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--session-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
Redis配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis配置
* @author savesl
*/
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
RedisSession共享配置
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
/**
* @author savesl
* maxInactiveIntervalInSeconds 设置session过期时间为40*60秒【默认30分钟】
*/
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 2400)
public class RedisSessionConfig {
}
Redis工具类
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Redis工具类
* @author savesl
*/
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* String类型
*/
@Autowired
private ValueOperations<String, String> valueOperations;
/**
* hash类型
*/
@Autowired
private HashOperations<String, String, Object> hashOperations;
/**
* list类型
*/
@Autowired
private ListOperations<String, Object> listOperations;
/**
* set类型
*/
@Autowired
private SetOperations<String, Object> setOperations;
/**
* sorted set类型
*/
@Autowired
private ZSetOperations<String, Object> zSetOperations;
/**
* 默认过期时长,单位:秒
*/
public final static long DEFAULT_EXPIRE = 60 * 60 * 24;
/**
* 不设置过期时长
*/
public final static long NOT_EXPIRE = -1;
// region 通用
/**
* 正则表达式匹配查找key 数据量如果比较大不要使用,可以用scan代替
* @param pattern 正则表达式
* @return 存放key的list集合
*/
public Set<String> getKeys (String pattern) {
return redisTemplate.keys(pattern);
}
// endregion 通用
// region string类型
public void set(String key, Object value, long expire) {
valueOperations.set(key, toJson(value));
if (expire != NOT_EXPIRE) {
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
}
public void set(String key, Object value) {
set(key, value, DEFAULT_EXPIRE);
}
public <T> T get(String key, Class<T> clazz, long expire) {
String value = valueOperations.get(key);
if (expire != NOT_EXPIRE) {
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
return value == null ? null : fromJson(value, clazz);
}
public <T> T get(String key, Class<T> clazz) {
return get(key, clazz, NOT_EXPIRE);
}
public String get(String key, long expire) {
String value = valueOperations.get(key);
if (expire != NOT_EXPIRE) {
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
return value;
}
public String get(String key) {
return get(key, NOT_EXPIRE);
}
public void delete(String key) {
redisTemplate.delete(key);
}
/**
* 增加数量
* @param i 递增数量
* @return
*/
public long incr(String key,int i) {
return valueOperations.increment(key, i);
}
/**
* 递增,每次+1
* @return
*/
public long incr(String key) {
// System.out.println(key);
// System.out.println(valueOperations);
return valueOperations.increment(key, 1);
}
/**
* 获取当前递增过的对应key的value值
* @param key
* @return
*/
public long getIncrValue(String key) {
return valueOperations.increment(key, 0);
}
// endregion string类型
//region list类型
/**
* 获取list类型的数据 取全部数据start:0 end:-1
* @param key
* @param start 第一个是0 第二个是1 以此类推……
* @param end 最后一个是-1 倒数第二个为-2 以此类推……
* @return
*/
public List<Object> lget(String key,long start,long end){
return listOperations.range(key, start, end);
}
/**
* 返回list类型数据的数据量,数据个数
* @param key
* @return
*/
public int lsize(String key){
return listOperations.size(key).intValue();
}
/**
* 定长存入list中,只保存key对应的最近length条记录。
* 先清理掉length-1之后的数据,然后在开头位置插入最新的数据。
* @param key
* @param data 数据
* @param length 固定长度,超出length-2范围的数据会被清理
* @return
*/
public void pushFixLength(String key,Object data,int length) {
//清理掉过剩的数据
listOperations.trim(key, 0, length-2);
//从开头保存最新的数据
listOperations.leftPush(key, data);
}
// endregion list类型
//region list-hash混合处理
/**
* 返回一个list中保存key的 hash类型数据集合 ,即hash类型数据的key保存在一个list中,通过list的key以获取多个hash中的数据
* @param key list集合的key
* @param start list的起始位置,第一个为0
* @param end list的最后位置,倒数第一个为-1
* @param pre hash 的key的前缀
* @param suf hash 的key的后缀
* @return hash数据的集合
*
*/
public List<Map<String,Object>> lhget(String key,long start,long end,String pre,String suf){
List<Map<String,Object>> listMap = new ArrayList<>();
List<Object> keys = listOperations.range(key, start, end);
for(Object k : keys) {
Map<String, Object> entrie = hashOperations.entries(pre+(String)k+suf);
if(!entrie.isEmpty()) {
listMap.add(entrie);
}
}
return listMap;
}
// endregion list-hash混合处理
// region hash类型
/**
* 获取指定key中的hash类型数据中的键值对
* @param key
*/
public Map<String,Object> hget(String key){
return hashOperations.entries(key);
}
// endregion hash类型
// region z-set类型
/**
* 指定的数据的分值自增(+1)
*/
public double zIncr(String k,String v) {
return zSetOperations.incrementScore(k, v, 1);
}
/**
* 指定的数据分值增加给定的值(+n)
*/
public double zIncr(String k,String v,int step) {
return zSetOperations.incrementScore(k, v, step);
}
/**
* 获取key为k的有序的分数从min到max的数据
* @param k 键
* @param min 最小值
* @param max 最大值
*/
public Set<String> zRangByScore(String k,double min,double max){
Set<Object> setObj = zSetOperations.rangeByScore(k,min,max);
return (Set<String>)(Set<?>)setObj;
}
/**
* 获取key为k的有序的分数从min到max数据 中的从offset开始 共count个元素
* @param k 键
* @param min 最小值
* @param max 最大值
*/
public Set<String> zRangByScore(String k,double min,double max,long offset, long count){
Set<Object> setObj = zSetOperations.rangeByScore(k,min,max,offset,count);
return (Set<String>)(Set<?>)setObj;
}
/**
* 倒序 获取key为k的有序的分数从min到max的数据
* @param k 键
* @param min 最小值
* @param max 最大值
*/
public Set<String> zReverseRangeByScore(String k,double min,double max){
Set<Object> setObj = zSetOperations.reverseRangeByScore(k,min,max);
return (Set<String>)(Set<?>)setObj;
}
/**
* 获取key为k的有序的分数从min到max数据 中的从offset开始 共count个元素
* @param k 键
* @param min 最小值
* @param max 最大值
*/
public Set<String> zReverseRangeByScore(String k,double min,double max,long offset, long count){
Set<Object> setObj = zSetOperations.reverseRangeByScore(k,min,max,offset,count);
return (Set<String>)(Set<?>)setObj;
}
/**
* 获取key为k的 分数从min到max数据的总数
* @param k 键
* @param min 最小值
* @param max 最大值
*/
public long zCount(String k,double min,double max){
return zSetOperations.count(k,min,max);
}
/**
* 返回指定键和值的分值
* @param k 键
* @return 返回分值
*/
public Double zScore(String k,String val){
return zSetOperations.score(k, val);
}
// endregion z-set类型
/**
* Object转成JSON数据
*/
public String toJson(Object object) {
if (object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double || object instanceof Boolean || object instanceof String) {
return String.valueOf(object);
}
return JSON.toJSONString(object);
}
/**
* JSON数据,转成Object
*/
public <T> T fromJson(String json, Class<T> clazz) {
return JSON.parseObject(json, clazz);
}
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public ValueOperations<String, String> getValueOperations() {
return valueOperations;
}
public void setValueOperations(ValueOperations<String, String> valueOperations) {
this.valueOperations = valueOperations;
}
public HashOperations<String, String, Object> getHashOperations() {
return hashOperations;
}
public void setHashOperations(HashOperations<String, String, Object> hashOperations) {
this.hashOperations = hashOperations;
}
public ListOperations<String, Object> getListOperations() {
return listOperations;
}
public void setListOperations(ListOperations<String, Object> listOperations) {
this.listOperations = listOperations;
}
public SetOperations<String, Object> getSetOperations() {
return setOperations;
}
public void setSetOperations(SetOperations<String, Object> setOperations) {
this.setOperations = setOperations;
}
public ZSetOperations<String, Object> getzSetOperations() {
return zSetOperations;
}
public void setzSetOperations(ZSetOperations<String, Object> zSetOperations) {
this.zSetOperations = zSetOperations;
}
}
yml配置
spring:
redis:
database: 0 数据库索引,从0开始
host: 服务器IP
port: redis端口
password: 密码
timeout: 20000ms
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
session:
store-type: redis
单点登录实现
/**
* 登录处理
* @param session
* @return
*/
@RequestMapping(value = "/verifyAccount", method = RequestMethod.POST)
@ResponseBody
public Result verifyAccount(String accountName, String password, HttpSession session){
if(StringUtil.isBlank(accountName) || StringUtil.isBlank(password)){
return Result.error("参数错误");
}
AccountEntity account = accountService.findAccountByName(accountName);
if(null == account || account.getStatus().equals("F")){
return Result.error("该账号不存在或已禁用");
}
//获取redis中该用户对应的 sessionId
String sessionId = redisUtils.get("loginAccount:"+account.getId());
//若sessionId不为空,即:已登录
if(StringUtil.isNotBlank(sessionId)){
String currentSessionId = session.getId();
if(!currentSessionId.equals(sessionId)){
return Result.error("该账号已在其他设备登录!");
}
}
if(!account.getPassword().equals(password)){
return Result.error("密码错误");
}
List<String> authorization = accountService.findAllMenuByAccount(account.getId());
Set<String> permissionSet = new HashSet<>();
for (String auth : authorization) {
if (StringUtils.isBlank(auth)) {
continue;
}
permissionSet.addAll(Arrays.asList(auth.trim().split(",")));
}
account.setPermissionSet(permissionSet);
session.setAttribute("account", account);
redisUtils.set("loginAccount:"+account.getId(), session.getId(), 60*40);
return Result.ok("登录成功!");
}
/**
* 退出登录
* @param session
* @return
*/
@RequestMapping("/logOut")
public String logOut(HttpSession session){
AccountEntity account = (AccountEntity)session.getAttribute("account");
//设置过期
redisUtils.set("loginAccount:"+account.getId(), session.getId(), 0);
session.removeAttribute("account");
return "common/login";
}