@wendal 有没有例子? 我们贴下代码,帮忙看下有什么问题
public class RedisSessionDAO extends CachingSessionDAO {
private static final Log logger = Logs.get();
// 登录成功的信息存储在 session 的这个 attribute 里.
private static final String AUTHENTICATED_SESSION_KEY =
"org.apache.shiro.subject.support.DefaultSubjectContext_AUTHENTICATED_SESSION_KEY";
private String keyPrefix = "shiro_redis_session:";
private String deleteChannel = "shiro_redis_session:delete";
private int timeToLiveSeconds = 3600; // session缓存失效时间(单位:秒)
private RedisManager redisManager;
/**
* DefaultSessionManager 创建完 session 后会调用该方法。
* 把 session 保持到 Redis。
* 返回 Session ID;主要此处返回的 ID.equals(session.getId())
*/
@Override
protected Serializable doCreate(Session session) {
logger.debug("=> Create session with ID " + session.getId());
// 创建一个Id并设置给Session
Serializable sessionId = this.generateSessionId(session);
assignSessionId(session, sessionId);
// session 由 Redis 缓存失效决定
String key = SerializationUtils.sessionKey(keyPrefix, session);
String value = SerializationUtils.sessionFromString(session);
redisManager.setex(key, value, timeToLiveSeconds);
return sessionId;
}
/**
* 考虑到集群的时候退出登录无法删除集群机器本地session故而所有的都从 Redis 读取 Session.
*
* @param sessionId
* @return
* @throws UnknownSessionException
*/
@Override
public Session readSession(Serializable sessionId) throws UnknownSessionException {
Session s = doReadSession(sessionId);
if (s == null) {
throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
}
return s;
}
/**
* 从 Redis 上读取 session,并缓存到本地 Cache.
*
* @param sessionId
* @return
*/
@Override
protected Session doReadSession(Serializable sessionId) {
logger.debug("=> Read session with ID " + sessionId);
try {
String value = redisManager.get(SerializationUtils.sessionKey(keyPrefix, sessionId));
// 例如 Redis 调用 flushdb 情况了所有的数据,读到的 session 就是空的
if (value != null) {
Session session = SerializationUtils.sessionToString(value);
return session;
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return null;
}
/**
* 更新 session 到 Redis.
*
* @param session
*/
@Override
protected void doUpdate(Session session) {
// 如果会话过期/停止,没必要再更新了
if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
logger.debug("=> Invalid session.");
return;
}
logger.debug("=> Update session with ID " + session.getId());
String key = SerializationUtils.sessionKey(keyPrefix, session);
String value = SerializationUtils.sessionFromString(session);
redisManager.setex(key, value, timeToLiveSeconds);
}
/**
* 从 Redis 删除 session,并且发布消息通知其它 Server 上的 Cache 删除 session.
*
* @param session
*/
@Override
protected void doDelete(Session session) {
logger.debug("=> Delete session with ID " + session.getId());
redisManager.del(SerializationUtils.sessionKey(keyPrefix, session));
// 发布消息通知其它 Server 上的 cache 删除 session.
redisManager.publish(deleteChannel, SerializationUtils.sessionIdToString(session));
}
/**
* 取得所有有效的 session.
*
* @return
*/
@Override
public Collection<Session> getActiveSessions() {
logger.debug("=> Get active sessions");
//Set<String> keys = redisManager.keys(keyPrefix + "*");//TODO 看是否用到
Set<String> keys = new HashSet<>();
Collection<String> values = redisManager.mget(keys.toArray(new String[0]));
List<Session> sessions = new LinkedList<Session>();
for (String value : values) {
sessions.add(SerializationUtils.sessionToString(value));
}
return sessions;
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public String getDeleteChannel() {
return deleteChannel;
}
public void setDeleteChannel(String deleteChannel) {
this.deleteChannel = deleteChannel;
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
public int getTimeToLiveSeconds() {
return timeToLiveSeconds;
}
public void setTimeToLiveSeconds(int timeToLiveSeconds) {
this.timeToLiveSeconds = timeToLiveSeconds;
}
}
public class RedisManager {
private static final Log logger = Logs.get();
private volatile boolean init = false;
private String configFile = "/config/custom/redis.properties";
private JedisCluster jedisPool;
private static final int MAX_NODE = 8;//最大支持节点数为8
public RedisManager() {
init();
}
/**
* Initializing jedis pool to connect to Jedis.
*/
public synchronized void init() {
if (configFile != null && init == false) {
PropertiesProxy properties = new PropertiesProxy(configFile);
int timeout = properties.getInt("redis.timeout");
int maxRedirections = properties.getInt("redis.maxRedirections");
int maxTotal = properties.getInt("redis.maxTotal");
int maxIdle = properties.getInt("redis.maxIdle");
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
Set<HostAndPort> jedisClusterNodes = getHostAndPorts(properties);
// 超时,最大的转发数,最大链接数,最小链接数都会影响到集群
jedisPool = new JedisCluster(jedisClusterNodes, timeout, maxRedirections, config);
init = true;
}
}
private Set<HostAndPort> getHostAndPorts(PropertiesProxy properties) {
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
HostAndPort hostAndPort;
String host;
int port;
for (int i = 1; i <= MAX_NODE; i++) {
host = properties.get("redis.host.node" + i);
port = properties.getInt("redis.port.node" + i);
if (StringUtils.isNotBlank(host) && port > 0) {
hostAndPort = new HostAndPort(host, port);
jedisClusterNodes.add(hostAndPort);
logger.info("redis 集群添加节点:" + hostAndPort.toString());
}
}
return jedisClusterNodes;
}
public String getConfigFile() {
return configFile;
}
public void setConfigFile(String configFile) {
this.configFile = configFile;
}
public JedisCluster getJedis() {
if (jedisPool == null) {
init();
}
return jedisPool;
}
/**
* Get value from Redis
*
* @param key
* @return
*/
public String get(String key) {
logger.info("get key=" + key);
return getJedis().get(key);
}
/**
* Set value into Redis with default time to live in seconds.
*
* @param key
* @param value
*/
public void set(String key, String value) {
logger.info("set key=" + key);
getJedis().set(key, value);
}
/**
* Set value into Redis with specified time to live in seconds.
*
* @param key
* @param value
* @param timeToLiveSeconds
*/
public void setex(String key, String value, int timeToLiveSeconds) {
logger.info("setex key=" + key);
getJedis().setex(key, timeToLiveSeconds, value);
}
/**
* Delete key and its value from Jedis.
*
* @param key
*/
public void del(String key) {
logger.info("del key=" + key);
getJedis().del(key);
}
/**
* Get multiple values for the given keys.
*
* @param keys
* @return
*/
public Collection<String> mget(String... keys) {
if (keys == null && keys.length == 0) {
Collections.emptySet();
}
return getJedis().mget(keys);
}
/**
* Publish message to channel using subscribe and publish protocol.
*
* @param channel
* @param value
*/
public void publish(String channel, String value) {
getJedis().publish(channel, value);
}
}
shiro.ini配置
[main]
cacheManager
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile=classpath:ehcache.xml
Session
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
---------------redis session conf start----------------
redisManager = cn.wizzer.common.redis.RedisManager
redisManager.configFile = /config/custom/redis.properties
sessionDAO = cn.wizzer.common.redis.RedisSessionDAO
sessionDAO.redisManager = $redisManager
sessionDAO.timeToLiveSeconds = 1800
---------------redis session conf end------------------
---------------local session conf start----------------
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
---------------local session conf end------------------
sessionDAO.cacheManager=$cacheManager
sessionDAO.activeSessionsCacheName=shiro-activeSessionCache
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager
现在已经出现异常了
2016-09-14 17:20:17,327 cn.wizzer.common.redis.RedisManager.get(RedisManager.java:91) INFO - get key=shiro_redis_session:aa0ca424-8e31-4093-abdb-2908e0e82c34
NULL
at org.beetl.core.statement.ForStatement.execute(ForStatement.java:83)
at org.beetl.core.statement.Program.execute(Program.java:70)
at org.beetl.core.engine.FilterProgram.execute(FilterProgram.java:31)
at org.beetl.core.Template.renderTo(Template.java:137)
at org.beetl.ext.tag.LayoutTag.render(LayoutTag.java:114)
at org.beetl.core.statement.TagStatement.runTag(TagStatement.java:108)
at org.beetl.core.statement.TagStatement.execute(TagStatement.java:87)
at org.beetl.core.statement.Program.execute(Program.java:70)
at org.beetl.core.engine.FilterProgram.execute(FilterProgram.java:31)
at org.beetl.core.Template.renderTo(Template.java:137)
at org.beetl.core.Template.renderTo(Template.java:103)
at org.beetl.ext.web.WebRender.render(WebRender.java:120)
at org.beetl.ext.nutz.BeetlView.render(BeetlView.java:28)
at org.nutz.mvc.impl.processor.ViewProcessor.process(ViewProcessor.java:66)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:28)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at cn.wizzer.common.processor.XssSqlFilterProcessor.process(XssSqlFilterProcessor.java:35)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at cn.wizzer.common.processor.NutShiroProcessor.process(NutShiroProcessor.java:52)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at cn.wizzer.common.processor.GlobalsSettingProcessor.process(GlobalsSettingProcessor.java:37)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at cn.wizzer.common.processor.LogTimeProcessor.process(LogTimeProcessor.java:21)
at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at cn.wizzer.common.filter.RouteFilter.doFilter(RouteFilter.java:34)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
2016-09-14 17:20:17,342 org.beetl.ext.nutz.LogErrorHandler.processExcption(LogErrorHandler.java:32) DEBUG - null
05:20:17:表达式值为空(NULL):shiro 位于130行 资源:/layouts/private.html
127|
128| <%
129| var secondMenus=@shiro.getPrincipalProperty('secondMenus');
130| for(firstMenu in @shiro.getPrincipalProperty('firstMenus')){
131|
132| %>
========================
调用栈:
/layouts/private.html 行:130
/private/sys/home.html 行:2
2016-09-14 17:20:17,343 cn.wizzer.common.processor.LogTimeProcessor.process(LogTimeProcessor.java:26) DEBUG - [GET ]URI=/nutzwk/private/home 477ms
2016-09-14 17:20:17,880 cn.wizzer.common.redis.RedisSessionDAO.doReadSession(RedisSessionDAO.java:75) DEBUG - => Read session with ID aa0ca424-8e31-4093-abdb-2908e0e82c34