最近一年由于工作繁忙,加上各种事情比较多,好久没有更新文章了,向大家,也向自己说声抱歉!后面会继续将学习的内容分享出来!
项目遇到的问题:
启动项目,登录网站,输入用户名、密码,访问,
当项目tomcat停止,然后重新启动,
在网页继续访问时,因为session失效,被强制跳转到登录页面,提示重新登录,
这样在tomcat集群时,就会有问题,因此需要将session统一存放到redis中,项目的启动和停止不影响session。
我们的项目已经集成好了spring shiro redis,但是session没有存入redis实现共享,因此此文是实现session存入redis集群,共享部分功能:
(该项目借鉴了博文:https://blog.youkuaiyun.com/zhaoyachao123/article/details/78332488)
解决步骤:
1-sessionManager添加sessionDAO属性
想要实现使用redis管理session 需要在shiro 的sessionmanager添加sessionDAO属性 如下
a)如果是使用xml配置,如下:
<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionDAO" ref="sessionDao"></property>
<property name="globalSessionTimeout" value="60000" />
<!-- 删除失效session -->
<property name="sessionValidationSchedulerEnabled" value="true" />
<property name="sessionListeners" ref="myShiroSessionListener"></property>
</bean>
<bean id="myShiroSessionListener" class="com.zyc.listener.MyShiroSessionListener"></bean>
<bean id="sessionDao" class="com.zyc.security.SessionDao">
<property name="redisUtil" ref="redisUtil"></property>
</bean>
</bean>
b)如果是使用的spring注解配置,如下:
@Configuration
public class ShiroConfig {
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
Collection<SessionListener> listeners = new ArrayList<SessionListener>();
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;
}
}
测试:
启动项目,登录网站,访问,
然后将项目停止,重新启动,
继续访问,依然可以正常使用登录后的一起状态。
测试成功