您的位置:首页 > 数据库 > Redis

初步学习shiro+redis+springMVC的集成配置,做一下记录文档吧

2016-11-10 08:38 567 查看
为了使用redis实现session共享机制,上网找了不少资料,最后发现了一篇比较详细的blog介绍:http://blog.csdn.net/lishehe/article/details/45223823,可以参考参考;按照里面的逐步配置后发现有问题,少了一个redisManager的文件实现类,找了一些其他的资料中文件,可能和作者的配置不太相符合,只能放弃,作参考价值,后来发现有shiro-redis的官方文档:https://github.com/alexxiyang/shiro-redis,这个就比较简洁明了,而且相关的实现类源码都可以下载,发现竟然如此简单就可以了。一番重新配置后,运行了项目,还是报异常,是shiro认证的原因,NOTE Shiro-redis don't support SimpleAuthenticationInfo created by this constructororg.apache.shiro.authc.SimpleAuthenticationInfo.SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName). Please useorg.apache.shiro.authc.SimpleAuthenticationInfo.SimpleAuthenticationInfo(Object principal, Object hashedCredentials, String realmName) instead.官方文档是这么标注的,不信邪,无视了,寻着异常一步一步debug下去,发现是认证成功后保存session出的问题,无法将TBSysPermission
bean对象序列化,找到该bean文件,实现一下Serializable接口,按照提示添加一行
private static final long serialVersionUID = 1L;
搞定,项目成功运行,session共享实现完成。
package com.zkzy.redis;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
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
public void clear() throws CacheException {
logger.debug("从redis中删除所有元素");
try {
cache.flushDB();
} catch (Throwable t) {
throw new CacheException(t);
}
}

@Override
public int size() {
try {
Long longSize = new Long(cache.dbSize());
return longSize.intValue();
} catch (Throwable t) {
throw new CacheException(t);
}
}

@SuppressWarnings("unchecked")
@Override
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);
}
}

@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);
}
}

}
package com.zkzy.redis;

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;

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;
}

}
package com.zkzy.redis;

import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisManager {

private String host = "127.0.0.1";

private int port = 6379;

// 0 - never expire
private int expire = 0;

//timeout for jedis try to connect to redis server, not expire time! In milliseconds
private int timeout = 0;

private String password = "root";

private static JedisPool jedisPool = null;

public RedisManager(){

}

/**
* 初始化方法
*/
public void init(){
if(jedisPool == null){
if(password != null && !"".equals(password)){
jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
}else if(timeout != 0){
jedisPool = new JedisPool(new JedisPoolConfig(), host, port,timeout);
}else{
jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
}

}
}

/**
* get value from redis
* @param key
* @return
*/
public byte[] get(byte[] key){
byte[] value = null;
Jedis jedis = jedisPool.getResource();
try{
value = jedis.get(key);
}finally{
jedisPool.returnResource(jedis);
}
return value;
}

/**
* set
* @param key
* @param value
* @return
*/
public byte[] set(byte[] key,byte[] value){
Jedis jedis = jedisPool.getResource();
try{
jedis.set(key,value);
if(this.expire != 0){
jedis.expire(key, this.expire);
}
}finally{
jedisPool.returnResource(jedis);
}
return value;
}

/**
* set
* @param key
* @param value
* @param expire
* @return
*/
public byte[] set(byte[] key,byte[] value,int expire){
Jedis jedis = jedisPool.getResource();
try{
jedis.set(key,value);
if(expire != 0){
jedis.expire(key, expire);
}
}finally{
jedisPool.returnResource(jedis);
}
return value;
}

/**
* del
* @param key
*/
public void del(byte[] key){
Jedis jedis = jedisPool.getResource();
try{
jedis.del(key);
}finally{
jedisPool.returnResource(jedis);
}
}

/**
* flush
*/
public void flushDB(){
Jedis jedis = jedisPool.getResource();
try{
jedis.flushD
d4d6
B();
}finally{
jedisPool.returnResource(jedis);
}
}

/**
* size
*/
public Long dbSize(){
Long dbSize = 0L;
Jedis jedis = jedisPool.getResource();
try{
dbSize = jedis.dbSize();
}finally{
jedisPool.returnResource(jedis);
}
return dbSize;
}

/**
* keys
* @param regex
* @return
*/
public Set keys(String pattern){
Set keys = null;
Jedis jedis = jedisPool.getResource();
try{
keys = jedis.keys(pattern.getBytes());
}finally{
jedisPool.returnResource(jedis);
}
return keys;
}

public String getHost() {
return host;
}

public void setHost(String host) {
this.host = host;
}

public int getPort() {
return port;
}

public void setPort(int port) {
this.port = port;
}

public int getExpire() {
return expire;
}

public void setExpire(int expire) {
this.expire = expire;
}

public int getTimeout() {
return timeout;
}

public void setTimeout(int timeout) {
this.timeout = timeout;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

}
package com.zkzy.redis;

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;

public class RedisSessionDAO extends AbstractSessionDAO {

private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
/**
* shiro-redis的session对象前缀
*/
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
public Collection getActiveSessions() {
Set sessions = new HashSet();

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;
}

}
package com.zkzy.redis;

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;
}
}

xml文件配置:
<!-- shiro filter -->
<bean id="ShiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>

<!--
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/home.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
-->
<!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean  -->
<!-- defined will be automatically acquired and available via its beanName in chain        -->
<!-- definitions, but you can perform instance overrides or name aliases here if you like: -->
<!-- <property name="filters">
<util:map>
<entry key="anAlias" value-ref="someFilter"/>
</util:map>
</property> -->
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/user/** = anon
/register/** = anon
/unauthorized.jsp = anon
/css/** = anon
/js/** = anon

/** = authc
</value>
</property>
</bean>

<!-- shiro securityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

<!-- Single realm app.  If you have multiple realms, use the 'realms' property instead. -->

<!-- sessionManager -->
<property name="sessionManager" ref="sessionManager" />

<!-- cacheManager -->
<property name="cacheManager" ref="cacheManager" />

<!-- By default the servlet container sessions will be used.  Uncomment this line
to use shiro's native sessions (see the JavaDoc for more): -->
<!-- <property name="sessionMode" value="native"/> -->
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

<!-- shiro redisManager -->
<bean id="redisManager" class="org.crazycake.shiro.RedisManager">
<property name="host" value="127.0.0.1"/>
<property name="port" value="6379"/>
<property name="expire" value="1800"/>
<!-- optional properties:
<property name="timeout" value="10000"/>
<property name="password" value="123456"/>
-->
</bean>

<!-- redisSessionDAO -->
<bean id="redisSessionDAO" class="org.crazycake.shiro.RedisSessionDAO">
<property name="redisManager" ref="redisManager" />
</bean>

<!-- sessionManager -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionDAO" ref="redisSessionDAO" />
</bean>

<!-- cacheManager -->
<bean id="cacheManager" class="org.crazycake.shiro.RedisCacheManager">
<property name="redisManager" ref="redisManager" />
</bean>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shiro redis