spring shiro redis : 将session存入redis,实现session共享

最近一年由于工作繁忙,加上各种事情比较多,好久没有更新文章了,向大家,也向自己说声抱歉!后面会继续将学习的内容分享出来!

项目遇到的问题:


启动项目,登录网站,输入用户名、密码,访问,
当项目tomcat停止,然后重新启动,
在网页继续访问时,因为session失效,被强制跳转到登录页面,提示重新登录,
这样在tomcat集群时,就会有问题,因此需要将session统一存放到redis中,项目的启动和停止不影响session。


我们的项目已经集成好了spring shiro redis,但是session没有存入redis实现共享,因此此文是实现session存入redis集群,共享部分功能:

(该项目借鉴了博文:https://blog.csdn.net/zhaoyachao123/article/details/78332488)


解决步骤:

 

1-sessionManager添加sessionDAO属性

想要实现使用redis管理session 需要在shiro 的sessionmanager添加sessionDAO属性 如下


     a)如果是使用xml配置,如下:


		
		
		
		
		
	
	
	
		
	

b)如果是使用的spring注解配置,如下:

@Configuration
public class ShiroConfig {

	@Bean
	public SessionManager sessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		Collection listeners = new ArrayList();
		listeners.add(new ShiroSessionListener());
		sessionManager.setSessionListeners(listeners);
		sessionManager.setSessionDAO(sessionDAO());
		return sessionManager;
	}

	//SessionDAO是一个接口: org.apache.shiro.session.mgt.eis.SessionDAO
	//我们自己写一个类,类名是SessionDao ,继承EnterpriseCacheSessionDAO
	//而EnterpriseCacheSessionDAO和 SessionDAO的关系如下:
	//EnterpriseCacheSessionDAO extends CachingSessionDAO
	//CachingSessionDAO extends AbstractSessionDAO
	//AbstractSessionDAO implements SessionDAO
	

	@Bean
	public SessionDAO sessionDAO() {
		//改造后
		SessionDao sessionDao = new SessionDao() ;
		return sessionDao ;
		//改造前
//		MemorySessionDAO sessionDAO = new MemorySessionDAO();
//		return sessionDAO;
	}
}


2- 创建sessionDao类

sessionDao需要实现EnterpriseCacheSessionDAO类或者CachingSessionDAO类,咱们这里以EnterpriseCacheSessionDAO类为例如下:

public class SessionDao extends EnterpriseCacheSessionDAO {
	
//	Integer expireSeconds = 60*60*24 ;//60*60*24=7天
	
	@Override
	protected Serializable doCreate(Session session) {
		Serializable sessionId = super.doCreate(session);
		byte[] session_value = sessionToByte(session) ;
		byte[] sessionId_key = sessionId.toString().getBytes() ;
		RedisUtil.set(sessionId_key, session_value) ; 
		return sessionId ;
	}

	@Override
	protected void doDelete(Session session) {
		super.doDelete(session);
		RedisUtil.remove(session.getId().toString());
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		Session session = super.doReadSession(sessionId);
		if(session == null) {
			byte[] sessionId_key = sessionId.toString().getBytes() ;
			byte[] session_value = RedisUtil.get(sessionId_key) ;
			if(session_value != null && session_value.length > 0){
				session = byteToSession(session_value) ;
			}
		}
		return session ;
	}

	@Override
	protected void doUpdate(Session session) {
		super.doUpdate(session);
		byte[] session_value = sessionToByte(session) ;
		byte[] sessionId_key = session.getId().toString().getBytes() ;
		RedisUtil.set(sessionId_key, session_value) ; 
	}
	
	// 把session对象转化为byte保存到redis中
    public byte[] sessionToByte(Session session){
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        byte[] bytes = null;
        try {
            ObjectOutput oo = new ObjectOutputStream(bo);
            oo.writeObject(session);
            bytes = bo.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }
    
 // 把byte还原为session
    public Session byteToSession(byte[] bytes){
        ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
        ObjectInputStream in;
        SimpleSession session = null;
        try {
            in = new ObjectInputStream(bi);
            session = (SimpleSession) in.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        return session;
    }
}


3-redisUtil类如下:


@Component
public class RedisUtil {
	@Autowired
	private JedisCluster jCluster ;
	
	private static JedisCluster jedisCluster ;
	
	@PostConstruct
	public void init() {
		jedisCluster = jCluster ;
	}
	/**
	 * 写入缓存,无超时功能
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public static boolean set(final byte[] key, byte[] value) {
		boolean result = false;
		try {
			jedisCluster.set(key, value) ;
			result = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	/**
	 * 写入缓存,带有超时功能
	 * 
	 * @param key
	 * @param value
	 * @param expireSeconds
	 * @return
	 */
	public static boolean set(final byte[] key, byte[] value, int expireSeconds) {
		boolean result = false;
		try {
			jedisCluster.set(key, value) ;
			jedisCluster.expire(key, expireSeconds) ;
			result = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	
	public static void remove(final String key) {
		if (exists(key)) {
			jedisCluster.del(key);
		}
	}
	
	public static boolean exists(final String key) {
		return jedisCluster.exists(key);
	}
	
	public static byte[] get(final byte[] key) {
		byte[] result = jedisCluster.get(key) ;
		return result;
	}

}


测试:


启动项目,登录网站,访问,

然后将项目停止,重新启动,

继续访问,依然可以正常使用登录后的一起状态。

测试成功
 

你可能感兴趣的:(spring)