diff --git a/README.md b/README.md
index 54ccc3c92cd0afdc89596f323005756c6bb9807e..6ca949c12564081a6ff6b2b46414265d24cd83c6 100644
--- a/README.md
+++ b/README.md
@@ -66,4 +66,49 @@ permission 拥有权限的用户
```
* 配置shiro与spring集成文件:spring-shiro.xml
-* 页面中加入shiro标签
\ No newline at end of file
+* 页面中加入shiro标签
+
+## version: 0.0.3-RELEASE (release at 2017/10/27)
+集成redis
+* 导入maven依赖
+```xml
+
+
+ redis.clients
+ jedis
+ 2.9.0
+
+
+ org.springframework.data
+ spring-data-redis
+ 1.8.1.RELEASE
+
+
+```
+
+* 重写相关缓存类
+ExtJedisConnectionFactory.java
+RedisCache.java
+RedisCacheManager.java
+RedisManager.java
+RedisSessionDAO.java
+SerializeUtils.java
+
+* 修改相关配置
+增加spring-redis.xml
+spring-shiro.xml中添加sessionManager, 将cacheManager从Ecache换为RedisCacheManager
+shiro-demo.properties中增加redis相关配置
+```shell
+########################
+## redis config
+########################
+redis.config.maxTotal=50
+redis.config.maxIdle=10
+redis.config.minIdle=10
+redis.config.maxWaitMillis=1800
+redis.address=redis:6379
+redis.masterName=
+redis.password=
+redis.timeout=1800
+redis.expire=1800
+```
diff --git a/pom.xml b/pom.xml
index 7e01bca6c619fdab87240d88edc5af571284d764..ecbc3ae3b14be94373687b092d12f1a88027dd17 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.cliveyuan
shiro-demo
war
- 0.0.2-RELEASE
+ 0.0.3-RELEASE
shiro-demo
http://maven.apache.org
@@ -16,6 +16,19 @@
+
+
+
+ redis.clients
+ jedis
+ 2.9.0
+
+
+ org.springframework.data
+ spring-data-redis
+ 1.8.1.RELEASE
+
+
diff --git a/src/main/java/ga/clive/demo/shiro/cache/ExtJedisConnectionFactory.java b/src/main/java/ga/clive/demo/shiro/cache/ExtJedisConnectionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..df973f5e5c0ab2c581a4ce9ed56ccb1a1b7ea233
--- /dev/null
+++ b/src/main/java/ga/clive/demo/shiro/cache/ExtJedisConnectionFactory.java
@@ -0,0 +1,44 @@
+package ga.clive.demo.shiro.cache;
+import static org.springframework.util.Assert.notNull;
+
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
+import org.springframework.util.StringUtils;
+
+public class ExtJedisConnectionFactory extends JedisConnectionFactory {
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ private String address;
+
+ @Override
+ public void afterPropertiesSet() {
+ notNull(address, "address is 'null'.");
+
+ String hostName = null;
+ Integer port = null;
+ String[] hostArray = address.split(",");
+ for (String host : hostArray) {
+ if (!StringUtils.isEmpty(host)) {
+ String[] ipAndPort = host.split(":");
+ if (ipAndPort.length > 1) {
+ hostName = ipAndPort[0];
+ port = Integer.parseInt(ipAndPort[1]);
+ break;
+ }
+ }
+ }
+
+ notNull(hostName, "ip is 'null'.");
+ notNull(port, "port is 'null'.");
+ setHostName(hostName);
+ setPort(port);
+
+ super.afterPropertiesSet();
+ }
+
+}
diff --git a/src/main/java/ga/clive/demo/shiro/cache/RedisCache.java b/src/main/java/ga/clive/demo/shiro/cache/RedisCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..b582be83ea7fca280c76b72be0103c3688ab8171
--- /dev/null
+++ b/src/main/java/ga/clive/demo/shiro/cache/RedisCache.java
@@ -0,0 +1,195 @@
+package ga.clive.demo.shiro.cache;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RedisCache implements Cache {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /**
+ * The wrapped Jedis instance.
+ */
+ private RedisManager cache;
+
+ /**
+ * The Redis key prefix for the sessions
+ */
+ private String keyPrefix = "shiro_redis_session:";
+
+ /**
+ * Returns the Redis session keys
+ * prefix.
+ * @return The prefix
+ */
+ public String getKeyPrefix() {
+ return keyPrefix;
+ }
+
+ /**
+ * Sets the Redis sessions key
+ * prefix.
+ * @param keyPrefix The prefix
+ */
+ public void setKeyPrefix(String keyPrefix) {
+ this.keyPrefix = keyPrefix;
+ }
+
+ /**
+ * 通过一个JedisManager实例构造RedisCache
+ */
+ public RedisCache(RedisManager cache){
+ if (cache == null) {
+ throw new IllegalArgumentException("Cache argument cannot be null.");
+ }
+ this.cache = cache;
+ }
+
+ /**
+ * Constructs a cache instance with the specified
+ * Redis manager and using a custom key prefix.
+ * @param cache The cache manager instance
+ * @param prefix The Redis key prefix
+ */
+ public RedisCache(RedisManager cache,
+ String prefix){
+
+ this( cache );
+
+ // set the prefix
+ this.keyPrefix = prefix;
+ }
+
+ /**
+ * 获得byte[]型的key
+ * @param key
+ * @return
+ */
+ private byte[] getByteKey(K key){
+ if(key instanceof String){
+ String preKey = this.keyPrefix + key;
+ return preKey.getBytes();
+ }else{
+ return SerializeUtils.serialize(key);
+ }
+ }
+
+ @Override
+ public V get(K key) throws CacheException {
+ logger.debug("根据key从Redis中获取对象 key [" + key + "]");
+ try {
+ if (key == null) {
+ return null;
+ }else{
+ byte[] rawValue = cache.get(getByteKey(key));
+ @SuppressWarnings("unchecked")
+ V value = (V)SerializeUtils.deserialize(rawValue);
+ return value;
+ }
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+
+ }
+
+ @Override
+ public V put(K key, V value) throws CacheException {
+ logger.debug("根据key从存储 key [" + key + "]");
+ try {
+ cache.set(getByteKey(key), SerializeUtils.serialize(value));
+ return value;
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ @Override
+ public V remove(K key) throws CacheException {
+ logger.debug("从redis中删除 key [" + key + "]");
+ try {
+ V previous = get(key);
+ cache.del(getByteKey(key));
+ return previous;
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * 非常危险的操作
+ */
+ @Override
+ @Deprecated
+ public void clear() throws CacheException {
+ logger.debug("从redis中删除所有元素");
+// try {
+// cache.flushDB();
+// } catch (Throwable t) {
+// throw new CacheException(t);
+// }
+ }
+
+ @Override
+ @Deprecated
+ public int size() {
+// try {
+// Long longSize = new Long(cache.dbSize());
+// return longSize.intValue();
+// } catch (Throwable t) {
+// throw new CacheException(t);
+// }
+ return 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ @Deprecated
+ public Set keys() {
+// try {
+// Set keys = cache.keys(this.keyPrefix + "*");
+// if (CollectionUtils.isEmpty(keys)) {
+// return Collections.emptySet();
+// }else{
+// Set newKeys = new HashSet();
+// for(byte[] key:keys){
+// newKeys.add((K)key);
+// }
+// return newKeys;
+// }
+// } catch (Throwable t) {
+// throw new CacheException(t);
+// }
+ return new HashSet();
+ }
+
+ @Override
+ public Collection values() {
+// try {
+// Set keys = cache.keys(this.keyPrefix + "*");
+// if (!CollectionUtils.isEmpty(keys)) {
+// List values = new ArrayList(keys.size());
+// for (byte[] key : keys) {
+// @SuppressWarnings("unchecked")
+// V value = get((K)key);
+// if (value != null) {
+// values.add(value);
+// }
+// }
+// return Collections.unmodifiableList(values);
+// } else {
+// return Collections.emptyList();
+// }
+// } catch (Throwable t) {
+// throw new CacheException(t);
+// }
+ return Collections.emptyList();
+ }
+
+}
diff --git a/src/main/java/ga/clive/demo/shiro/cache/RedisCacheManager.java b/src/main/java/ga/clive/demo/shiro/cache/RedisCacheManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..3569872e8a76de9790cfa0648ab3e80d4e3a43b5
--- /dev/null
+++ b/src/main/java/ga/clive/demo/shiro/cache/RedisCacheManager.java
@@ -0,0 +1,75 @@
+package ga.clive.demo.shiro.cache;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.cache.CacheManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RedisCacheManager implements CacheManager {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(RedisCacheManager.class);
+
+ // fast lookup by name map
+ private final ConcurrentMap caches = new ConcurrentHashMap();
+
+ private RedisManager redisManager;
+
+ /**
+ * The Redis key prefix for caches
+ */
+ private String keyPrefix = "shiro_redis_cache:";
+
+ /**
+ * Returns the Redis session keys
+ * prefix.
+ * @return The prefix
+ */
+ public String getKeyPrefix() {
+ return keyPrefix;
+ }
+
+ /**
+ * Sets the Redis sessions key
+ * prefix.
+ * @param keyPrefix The prefix
+ */
+ public void setKeyPrefix(String keyPrefix) {
+ this.keyPrefix = keyPrefix;
+ }
+
+ @Override
+ public Cache getCache(String name) throws CacheException {
+ logger.debug("获取名称为: " + name + " 的RedisCache实例");
+
+ Cache c = caches.get(name);
+
+ if (c == null) {
+
+ // initialize the Redis manager instance
+ //redisManager.init();
+
+ // create a new cache instance
+ c = new RedisCache(redisManager, keyPrefix);
+
+ // add it to the cache collection
+ caches.put(name, c);
+ }
+ return c;
+ }
+
+ public RedisManager getRedisManager() {
+ return redisManager;
+ }
+
+ public void setRedisManager(RedisManager redisManager) {
+ this.redisManager = redisManager;
+ }
+
+}
diff --git a/src/main/java/ga/clive/demo/shiro/cache/RedisManager.java b/src/main/java/ga/clive/demo/shiro/cache/RedisManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e788e55c0ea4512804477e0a1a70398fed4b6c45
--- /dev/null
+++ b/src/main/java/ga/clive/demo/shiro/cache/RedisManager.java
@@ -0,0 +1,630 @@
+package ga.clive.demo.shiro.cache;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ga.clive.demo.shiro.util.StrUtils;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+import redis.clients.jedis.JedisSentinelPool;
+import redis.clients.jedis.Protocol;
+import redis.clients.jedis.Response;
+import redis.clients.jedis.Transaction;
+import redis.clients.util.Pool;
+
+/**
+ *
+ * - Title: redis管理
+ * - Description:
+ *
+ *
+ * @author clive
+ * @version 1.0
+ * @date 2017-10-26 17:50:51
+ *
+ */
+public class RedisManager {
+
+ Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ // "192.168.100.224:26379,192.168.100.224:26379"
+ private String address = "192.168.100.224:26379,192.168.100.225:26379,192.168.100.226:26379";
+
+ private String masterName;
+ private String password;
+
+ /** 连接超时 ms (毫秒) **/
+ private Integer timeout = 10 * 1000;
+
+ /** 过期时间,0=不过期 单位s **/
+ private Integer expire = 1800;
+ private JedisPoolConfig jedisPoolConfig = null;
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getMasterName() {
+ return masterName;
+ }
+
+ public void setMasterName(String masterName) {
+ this.masterName = masterName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Integer getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(Integer timeout) {
+ this.timeout = timeout;
+ }
+
+ public Integer getExpire() {
+ return expire;
+ }
+
+ public void setExpire(Integer expire) {
+ this.expire = expire;
+ }
+
+ public JedisPoolConfig getJedisPoolConfig() {
+ return jedisPoolConfig;
+ }
+
+ public void setJedisPoolConfig(JedisPoolConfig jedisPoolConfig) {
+ this.jedisPoolConfig = jedisPoolConfig;
+ }
+
+ static public Pool jedisPool = null;
+
+ public void initJedisPoolConfig() {
+ jedisPoolConfig = new JedisPoolConfig();
+ // 最大连接数
+ jedisPoolConfig.setMaxTotal(1000);
+ // 最大空闲连接数
+ jedisPoolConfig.setMaxIdle(5); // 设置最大空闲数
+ jedisPoolConfig.setMinIdle(5); // 设置最小空闲数
+ // 获取连接时的最大等待毫秒数
+ jedisPoolConfig.setMaxWaitMillis(5000);
+ jedisPoolConfig.setTestOnBorrow(true);
+ }
+
+ /**
+ * 初始化Jedis
+ *
+ * @throws Exception
+ */
+ public synchronized void init() throws Exception {
+ String msg = "";
+ if (StrUtils.isEmpty(address)) {
+ msg = "====redis 地址列表[address] 不能为空! ";
+ logger.error(msg);
+ throw new Exception(msg);
+ }
+ /*
+ * if(StrUtils.isEmpty(masterName)){
+ * msg="====redis 主节点名称[masterName] 不能为空!"; logger.error(msg); throw new
+ * Exception(msg); }
+ */
+ if (jedisPoolConfig == null) {
+ initJedisPoolConfig();
+ logger.error(" JedisPoolConfig 没有配置请配置");
+ }
+ if (StrUtils.isEmpty(password)) {
+ password = null;
+ }
+ HashSet sentinels = new HashSet();
+
+ String[] addresStrs = address.split(",");
+ for (String addresStr : addresStrs) {
+ if (StrUtils.isNotEmpty(address)) {
+ sentinels.add(addresStr);
+ }
+ }
+ logger.info("connect redis address={},masterName={}", address, masterName);
+ if (jedisPool != null) {
+ return;
+ }
+ if (StrUtils.isEmpty(masterName) && addresStrs.length == 1) {
+ String[] hostAndPort = addresStrs[0].split(":");
+ String host = hostAndPort[0];
+ int port = Integer.parseInt(hostAndPort[1]);
+ jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);
+ } else {
+ jedisPool = new JedisSentinelPool(masterName, sentinels, jedisPoolConfig, timeout, password,
+ Protocol.DEFAULT_DATABASE);
+ }
+ }
+
+ /**
+ * 根据byte数组key获取数据
+ *
+ * @param key
+ * @return
+ */
+ public byte[] get(byte[] key) {
+ Jedis jedis = null;
+ byte[] bytes = null;
+ try {
+ jedis = jedisPool.getResource();
+ bytes = jedis.get(key);
+ } catch (Exception e) {
+ logger.error("获取缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ return bytes;
+ }
+
+ /**
+ * 根据String key获取数据
+ *
+ * @param key
+ * @return
+ */
+ public String get(String key) {
+ Jedis jedis = null;
+ String value = null;
+ try {
+ jedis = jedisPool.getResource();
+ value = jedis.get(key);
+ } catch (Exception e) {
+ logger.error("获取缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ return value;
+ }
+
+ /**
+ * 跟进key ,value存储,value最大1G
+ *
+ * @param key
+ * @param value
+ */
+ public void set(byte[] key, byte[] value) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ String status = jedis.set(key, value);
+ if (this.expire != 0) {
+ jedis.expire(key, this.expire);
+ }
+ logger.info("jedis set status = {}", status);
+ } catch (Exception e) {
+ logger.error("保存缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 跟进key ,value ,expire(单位s)过期时间存储,value最大1G
+ *
+ * @param key
+ * @param value
+ * @param expire
+ */
+ public void set(byte[] key, byte[] value, int expire) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ jedis.set(key, value);
+ if (expire != 0) {
+ jedis.expire(key, expire);
+ }
+ } catch (Exception e) {
+ logger.error("保存缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ public void set(String key, String value) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ String status = jedis.set(key, value);
+ if (this.expire != 0) {
+ jedis.expire(key, this.expire);
+ }
+ logger.info("jedis set status = {}", status);
+ } catch (Exception e) {
+ logger.error("保存缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 跟进key ,value ,expire(单位s)过期时间存储,value最大1G
+ *
+ * @param key
+ * @param value
+ * @param expire
+ */
+ public void set(String key, String value, int expire) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ String status = jedis.set(key, value);
+ if (expire != 0) {
+ jedis.expire(key, expire);
+ }
+ logger.info("jedis set status = {}", status);
+ } catch (Exception e) {
+ logger.error("保存缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * @param key
+ * @param value
+ * @return 返回true存储成功,否则失败
+ */
+ public boolean setnx(String key, String value) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ // 返回1存储成功 返回0存储失败
+ Long status = jedis.setnx(key, value);
+ if (this.expire != 0) {
+ jedis.expire(key, this.expire);
+ }
+ logger.info("jedis set status = {}", status);
+ return status == 1 ? true : false;
+ } catch (Exception e) {
+ logger.error("保存缓存出错", e);
+ return false;
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 跟进key ,value ,expire(单位s)过期时间存储,value最大1G
+ *
+ * @param key
+ * @param value
+ * @param expire
+ * 返回true存储成功,否则失败
+ */
+ public boolean setnx(String key, String value, int expire) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ Long status = jedis.setnx(key, value);
+ if (expire != 0) {
+ jedis.expire(key, expire);
+ }
+ return status == 1 ? true : false;
+ } catch (Exception e) {
+ logger.error("保存缓存出错", e);
+ return false;
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 获取过期时间(单位s)
+ *
+ * @param key
+ */
+ public Long ttl(String key) {
+ Jedis jedis = null;
+ Long expire = 0L;
+ try {
+ jedis = jedisPool.getResource();
+ expire = jedis.ttl(key);
+ } catch (Exception e) {
+ logger.error("获取过期时间出错", e);
+ } finally {
+ jedis.close();
+ }
+ return expire;
+ }
+
+ /**
+ * 根据key删除缓存
+ *
+ * @param key
+ */
+ public void del(byte[] key) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ Long l = jedis.del(key);
+ logger.info("jedis del number = {}", l);
+ } catch (Exception e) {
+ logger.error("删除缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ public void del(String key) {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ Long l = jedis.del(key);
+ logger.info("jedis del number = {}", l);
+ } catch (Exception e) {
+ logger.error("删除缓存出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 获取所有的keys
+ *
+ * @param pattern
+ * @return
+ */
+ public Set keys(String pattern) {
+ Jedis jedis = null;
+ Set set = null;
+ try {
+ jedis = jedisPool.getResource();
+ set = jedis.keys(pattern);
+ } catch (Exception e) {
+ logger.error("通过表达式获取keys出错", e);
+ } finally {
+ jedis.close();
+ }
+ return set;
+ }
+
+ public Set keys(byte[] pattern) {
+ Jedis jedis = null;
+ Set set = null;
+ try {
+ jedis = jedisPool.getResource();
+ set = jedis.keys(pattern);
+ } catch (Exception e) {
+ logger.error("通过表达式获取keys出错", e);
+ } finally {
+ jedis.close();
+ }
+ return set;
+ }
+
+ /**
+ * 删除当前选中的DB
+ */
+ public void delCurrentAll() {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ String status = jedis.flushDB();
+ logger.info("jedis delAll status = {}", status);
+ } catch (Exception e) {
+ logger.error("删除DB出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 删除所有的DB
+ */
+ public void delAll() {
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ String status = jedis.flushAll();
+ logger.info("jedis delAll status = {}", status);
+ } catch (Exception e) {
+ logger.error("删除所有DB出错", e);
+ } finally {
+ jedis.close();
+ }
+ }
+
+ /**
+ * 当前key 是否存在
+ *
+ * @param key
+ * @return
+ */
+ public boolean exists(String key) {
+ Jedis jedis = null;
+ Boolean exists = null;
+
+ try {
+ jedis = jedisPool.getResource();
+ exists = jedis.exists(key);
+ } catch (Exception e) {
+ logger.error("", e);
+ } finally {
+ if (null != jedis) {
+ jedis.close();
+ }
+ }
+
+ return exists;
+ }
+
+ public synchronized String incrId(String key) {
+ Long value = null;
+ Jedis jedis = null;
+ try {
+ jedis = jedisPool.getResource();
+ value = jedis.incr(key);
+ } catch (Exception e) {
+ logger.error("error in incrId method", e);
+ } finally {
+ if (null != jedis) {
+ jedis.close();
+ }
+ }
+ return value + "";
+ }
+
+ /**
+ * @param key
+ * @param timeOut
+ * @param max
+ * @param incrNum
+ * @return
+ */
+ public boolean maxLimit(String key, Integer timeOut, int max, int incrNum) {
+ boolean bo = false;
+ Jedis jedis = null;
+ Long currentNum = 0L;
+ try {
+ jedis = jedisPool.getResource();
+ Long pttl = jedis.pttl(key);
+ if (pttl > 0) {
+ currentNum = jedis.incrBy(key, incrNum);
+ logger.info("****** Key = {" + key + "} ********* value = " + currentNum + " ******");
+ if (currentNum <= max) {
+ bo = true;
+ }
+ } else if (pttl == -1 || pttl == -2 || pttl == 0) {
+ Transaction tx = jedis.multi();
+ Response rsp = tx.incrBy(key, incrNum);
+ tx.expire(key, timeOut);
+ tx.exec();
+ currentNum = rsp.get();
+ if (currentNum <= max) {
+ bo = true;
+ }
+ }
+ } catch (Exception ex) {
+ logger.error("maxLimit :******Exception******", ex);
+ } finally {
+ if (null != jedis) {
+ jedis.close();
+ }
+ }
+ return bo;
+ }
+
+ /**
+ * @Title: allow @Description: 进行流量控制,允许访问返回true 不允许访问返回false
+ * @param: @param
+ * key 放入redis的key
+ * @param: @param
+ * timeOut 超时时间单位秒
+ * @param: @param
+ * flowSize 超时时间内允许访问的次数
+ * @param: @return
+ * @param: @throws
+ * Exception @return: boolean @throws
+ */
+ public boolean flow(String key, Integer timeOut, Integer flowSize) {
+ boolean bo = false;
+ Jedis jedis = null;
+ Long flowNum = 0L;
+ try {
+ jedis = jedisPool.getResource();
+ Long pttl = jedis.pttl(key);
+ if (pttl > 0) {
+ String flowNow = jedis.get(key);
+ if (StrUtils.isNotEmpty(flowNow)) {
+ flowNum = Long.parseLong(flowNow);
+ }
+ logger.info("==========[flow]===flow flowSize :" + flowSize);
+ logger.info("==========[flow]===flow flowNum :" + flowNum);
+ if (flowNum < flowSize) {
+ bo = true;
+ }
+ } else if (pttl == -1 || pttl == -2 || pttl == 0) {
+ Transaction tx = jedis.multi();
+ Response rsp = tx.incr(key);
+ tx.expire(key, timeOut);
+ tx.exec();
+ flowNum = rsp.get();
+ if (flowNum < flowSize) {
+ bo = true;
+ }
+ }
+ } catch (Exception ex) {
+ logger.error("========Exception===", ex);
+ } finally {
+ if (null != jedis) {
+ jedis.close();
+ }
+ }
+ return bo;
+ }
+
+ public Long DBSize() {
+ return jedisPool.getResource().dbSize();
+ }
+
+ /**
+ * 获取所有key的值
+ *
+ * All the fields and values contained into a hash.
+ *
+ * @param key
+ * @return map
+ */
+ public Map hgetAll(String key) {
+ Jedis jedis = null;
+ Map valueMap = new HashMap<>();
+ try {
+ jedis = jedisPool.getResource();
+ valueMap = jedis.hgetAll(key);
+ } catch (Exception e) {
+ logger.error("error in hgetAll method", e);
+ } finally {
+ if (null != jedis) {
+ jedis.close();
+ }
+ }
+ return valueMap;
+ }
+
+ /**
+ * 保存map
+ * Set the respective fields to the respective values. HMSET replaces old
+ * values with new values.
+ *
+ * If key does not exist, a new key holding a hash is created.
+ *
+ * @param key
+ * @param valueMap
+ * @return
+ */
+ public String hmset(String key, Map valueMap) {
+ Jedis jedis = null;
+ String resp = null;
+ try {
+ jedis = jedisPool.getResource();
+ resp = jedis.hmset(key, valueMap);
+ } catch (Exception e) {
+ logger.error("error in hmset method", e);
+ } finally {
+ if (null != jedis) {
+ jedis.close();
+ }
+ }
+ return resp;
+ }
+
+}
diff --git a/src/main/java/ga/clive/demo/shiro/cache/RedisSessionDAO.java b/src/main/java/ga/clive/demo/shiro/cache/RedisSessionDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c8ebeb867463f135a14ac1b8813866b49c0898d
--- /dev/null
+++ b/src/main/java/ga/clive/demo/shiro/cache/RedisSessionDAO.java
@@ -0,0 +1,142 @@
+package ga.clive.demo.shiro.cache;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RedisSessionDAO extends AbstractSessionDAO {
+
+ private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
+ /**
+ * shiro-redis的session对象前缀
+ */
+ @Autowired
+ private RedisManager redisManager;
+
+ /**
+ * The Redis key prefix for the sessions
+ */
+ private String keyPrefix = "shiro_redis_session:";
+
+ @Override
+ public void update(Session session) throws UnknownSessionException {
+ this.saveSession(session);
+ }
+
+ /**
+ * save session
+ * @param session
+ * @throws UnknownSessionException
+ */
+ private void saveSession(Session session) throws UnknownSessionException{
+ if(session == null || session.getId() == null){
+ logger.error("session or session id is null");
+ return;
+ }
+
+ byte[] key = getByteKey(session.getId());
+ byte[] value = SerializeUtils.serialize(session);
+ session.setTimeout(redisManager.getExpire()*1000);
+ this.redisManager.set(key, value, redisManager.getExpire());
+ }
+
+ @Override
+ public void delete(Session session) {
+ if(session == null || session.getId() == null){
+ logger.error("session or session id is null");
+ return;
+ }
+ redisManager.del(this.getByteKey(session.getId()));
+
+ }
+
+ @Override
+ @Deprecated
+ public Collection getActiveSessions() {
+ Set sessions = new HashSet();
+ logger.error("getActiveSessions() Deprecated");
+ //考虑到生产上redis数据量多, 不建议使用*查询
+// Set keys = redisManager.keys(this.keyPrefix + "*");
+// if(keys != null && keys.size()>0){
+// for(byte[] key:keys){
+// Session s = (Session)SerializeUtils.deserialize(redisManager.get(key));
+// sessions.add(s);
+// }
+// }
+
+ return sessions;
+ }
+
+ @Override
+ protected Serializable doCreate(Session session) {
+ Serializable sessionId = this.generateSessionId(session);
+ this.assignSessionId(session, sessionId);
+ this.saveSession(session);
+ return sessionId;
+ }
+
+ @Override
+ protected Session doReadSession(Serializable sessionId) {
+ if(sessionId == null){
+ logger.error("session id is null");
+ return null;
+ }
+
+ Session s = (Session)SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
+ return s;
+ }
+
+ /**
+ * 获得byte[]型的key
+ * @param key
+ * @return
+ */
+ private byte[] getByteKey(Serializable sessionId){
+ String preKey = this.keyPrefix + sessionId;
+ return preKey.getBytes();
+ }
+
+ public RedisManager getRedisManager() {
+ return redisManager;
+ }
+
+ public void setRedisManager(RedisManager redisManager) {
+ this.redisManager = redisManager;
+
+ /**
+ * 初始化redisManager
+ */
+ //无需初始化
+ //this.redisManager.init();
+ }
+
+ /**
+ * Returns the Redis session keys
+ * prefix.
+ * @return The prefix
+ */
+ public String getKeyPrefix() {
+ return keyPrefix;
+ }
+
+ /**
+ * Sets the Redis sessions key
+ * prefix.
+ * @param keyPrefix The prefix
+ */
+ public void setKeyPrefix(String keyPrefix) {
+ this.keyPrefix = keyPrefix;
+ }
+
+
+}
diff --git a/src/main/java/ga/clive/demo/shiro/cache/SerializeUtils.java b/src/main/java/ga/clive/demo/shiro/cache/SerializeUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..c307c555956748a15f1cb306ee39b8d367b2c545
--- /dev/null
+++ b/src/main/java/ga/clive/demo/shiro/cache/SerializeUtils.java
@@ -0,0 +1,85 @@
+package ga.clive.demo.shiro.cache;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SerializeUtils {
+
+ private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
+
+ /**
+ * 反序列化
+ * @param bytes
+ * @return
+ */
+ public static Object deserialize(byte[] bytes) {
+
+ Object result = null;
+
+ if (isEmpty(bytes)) {
+ return null;
+ }
+
+ try {
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
+ try {
+ ObjectInputStream objectInputStream = new ObjectInputStream(byteStream);
+ try {
+ result = objectInputStream.readObject();
+ }
+ catch (ClassNotFoundException ex) {
+ throw new Exception("Failed to deserialize object type", ex);
+ }
+ }
+ catch (Throwable ex) {
+ throw new Exception("Failed to deserialize", ex);
+ }
+ } catch (Exception e) {
+ logger.error("Failed to deserialize",e);
+ }
+ return result;
+ }
+
+ public static boolean isEmpty(byte[] data) {
+ return (data == null || data.length == 0);
+ }
+
+ /**
+ * 序列化
+ * @param object
+ * @return
+ */
+ public static byte[] serialize(Object object) {
+
+ byte[] result = null;
+
+ if (object == null) {
+ return new byte[0];
+ }
+ try {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
+ try {
+ if (!(object instanceof Serializable)) {
+ throw new IllegalArgumentException(SerializeUtils.class.getSimpleName() + " requires a Serializable payload " +
+ "but received an object of type [" + object.getClass().getName() + "]");
+ }
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
+ objectOutputStream.writeObject(object);
+ objectOutputStream.flush();
+ result = byteStream.toByteArray();
+ }
+ catch (Throwable ex) {
+ throw new Exception("Failed to serialize", ex);
+ }
+ } catch (Exception ex) {
+ logger.error("Failed to serialize",ex);
+ }
+ return result;
+ }
+}
diff --git a/src/main/resources/config/applicationContext.xml b/src/main/resources/config/applicationContext.xml
index 34c80a12ebace73e21f8984c09070aaf46140350..12144d79feef3350badfc4e1391efafca114ae34 100644
--- a/src/main/resources/config/applicationContext.xml
+++ b/src/main/resources/config/applicationContext.xml
@@ -39,6 +39,7 @@
+
diff --git a/src/main/resources/config/cache/spring-redis.xml b/src/main/resources/config/cache/spring-redis.xml
new file mode 100644
index 0000000000000000000000000000000000000000..62ad03e46299c42b32297964ca0158976b08bc73
--- /dev/null
+++ b/src/main/resources/config/cache/spring-redis.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/config/shiro-demo.properties b/src/main/resources/config/shiro-demo.properties
index ea3d7760e7f2d50a5dad95bc6f423c4b911aa1b7..fab7e3a3ee128105b683dab82112c7bea109e8d1 100644
--- a/src/main/resources/config/shiro-demo.properties
+++ b/src/main/resources/config/shiro-demo.properties
@@ -1,10 +1,30 @@
+
+########################
+## mysql config
+########################
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/shiro_demo?useUnicode=true&characterEncoding=utf8
username=root
password=123456
-#c3p0
+########################
+## c3p0 config
+########################
idleConnectionTestPeriod = 60
preferredTestQuery = select 1
testConnectionOnCheckin = true
testConnectionOnCheckout = true
+
+
+########################
+## redis config
+########################
+redis.config.maxTotal=50
+redis.config.maxIdle=10
+redis.config.minIdle=10
+redis.config.maxWaitMillis=1800
+redis.address=redis:6379
+redis.masterName=
+redis.password=namibankredis
+redis.timeout=1800
+redis.expire=1800
\ No newline at end of file
diff --git a/src/main/resources/config/shiro/spring-shiro.xml b/src/main/resources/config/shiro/spring-shiro.xml
index dfafadbc1f80cd3e9033e6d807a0bbb6a89ff6a9..3e7af339965d66489d00c71a9e700778554cdffd 100644
--- a/src/main/resources/config/shiro/spring-shiro.xml
+++ b/src/main/resources/config/shiro/spring-shiro.xml
@@ -1,7 +1,8 @@
-
-
+
@@ -32,26 +34,30 @@
-
-
+
+
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+