spring+shiro+reids+ehcache实现session管理

前两天,在项目中遇到需要对session管理的 一个需求,查询了各种资料,也遇到了各种问题,不过,最后还是实现了需求,在此,也总结一下实现的过程,方便以后查阅。文中借鉴了很多其他文章内容,如有不当敬请谅解,一切以学习为主。

项目需求

  • 统计查看在线人数
  • 控制在线人数,管理员可下线某在线用户
  • 控制用户在线时长
  • 保证同一用户只能在同一客户端登录

    基于需求分析,考虑使用redis缓存session的方案:
    1.使用redis可方便的设置缓存的有限期,这样可控制用户的在线时长问题。用户登录,前端操作均会更新缓存数据。
    2.redis性能毋庸置疑,同时,redis的java api也能方便操作redis中的数据

项目依赖

<properties>
    
    <springside.version>4.2.3-GAspringside.version>
    <spring.version>4.0.5.RELEASEspring.version>
    <shiro.version>1.2.3shiro.version>
properties>

<dependency>
    <groupId>org.springsidegroupId>
    <artifactId>springside-coreartifactId>
    <version>${springside.version}version>
dependency>
<dependency>
    <groupId>org.apache.shirogroupId>
    <artifactId>shiro-springartifactId>
    <version>${shiro.version}version>
dependency>
<dependency>
    <groupId>org.apache.shirogroupId>
    <artifactId>shiro-ehcacheartifactId>
    <version>${shiro.version}version>
dependency>
<dependency>
    <groupId>org.springframework.sessiongroupId>
          <artifactId>spring-session-data-redisartifactId>
          <version>1.1.1.RELEASEversion>
          <type>pomtype>
dependency
<dependency>
    <groupId>org.crazycakegroupId>
    <artifactId>shiro-redisartifactId>
    <version>2.4.6version>
dependency>

web.xml配置filter,加载shiro和其他配置文件

    <context-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>
            classpath*:/applicationContext.xml,
            classpath*:/applicationContext-shiro.xml,
            classpath*:/applicationContext-session.xml
        param-value>
    context-param>

    <filter>  
        <filter-name>shiroFilterfilter-name>  
        <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
         <init-param>
              <param-name>targetFilterLifecycleparam-name>
              <param-value>trueparam-value>
          init-param>  
    filter>  
    <filter-mapping>  
        <filter-name>shiroFilterfilter-name>  
        <url-pattern>/*url-pattern> 
        <dispatcher>REQUESTdispatcher>
        <dispatcher>FORWARDdispatcher>
        <dispatcher>INCLUDEdispatcher>
        <dispatcher>ERRORdispatcher> 
    filter-mapping>  

shiro配置文件applicationContext-shiro.xml


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"
    default-lazy-init="true">

    <description>Shiro安全配置description>
    
    <bean id="shiroRealm" class="com.sinosoft.bi.base.security.ShiroRealm">bean>

    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="shiroRealm" />
        <property name="sessionManager" ref="sessionManager">property>
        <property name="cacheManager" ref="shiroEhcacheManager" />
    bean>
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/login" />
        <property name="successUrl" value="/" />
        <property name="unauthorizedUrl" value="/unauthorized" />
        <property name="filterChainDefinitions">
            <value>
                /login = authc
                /logout = logout
                /static/** = anon
                /admin/** = roles[admin]
                /** = user
            value>
        property>
    bean>

    
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache/ehcache-shiro.xml" />
    bean>

    
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    
    

    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">  
        <property name="sessionDAO" ref="sessionDao">property>  
        <property name="globalSessionTimeout" value="60000" />
        <property name="deleteInvalidSessions" value="true">property>
          
        <property name="sessionValidationSchedulerEnabled" value="true" />  
        <property name="sessionListeners" ref="myShiroSessionListener">property>
        
        
    bean>

     
    

    
    <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator">bean>

    
    <bean id="myShiroSessionListener" class="com.sinosoft.bi.base.security.MyShiroSessionListener">bean>  

    <bean id="sessionDao" class="com.sinosoft.bi.base.security.SessionDao">  
        <property name="redisUtil" ref="redisUtil">property>
        <property name="sessionIdGenerator" ref="sessionIdGenerator">property>
    bean> 
beans>

applicationContext-session.xml


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
    default-lazy-init="true">

        
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" >    
            
        <property name="maxIdle" value="${redis.maxIdle}" />    
          
        <property name="maxTotal" value="${redis.maxTotal}" />  
            
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />    
          
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />   
          
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />   
          
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />   
            
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />    
          
        <property name="testWhileIdle" value="${redis.testWhileIdle}" />    
    bean >  


      
      

      
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">   
        <property name="poolConfig" ref="jedisPoolConfig">property>  

       

         <property name="hostName" value="127.0.0.1">property>   
          
        <property name="port" value="6379">property> 
          
       
          
        <property name="timeout" value="${redis.timeout}">property>   
    bean>    

      
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >    
        <property name="connectionFactory" ref="jedisConnectionFactory" />    
            
        <property name="keySerializer" >    
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />    
        property>    
        <property name="valueSerializer" >    
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        property>    
        <property name="hashKeySerializer">    
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>    
        property>    
        <property name="hashValueSerializer">    
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>    
        property>    
          
        <property name="enableTransactionSupport" value="true">property>  
    bean >      

beans>  

redis配置文件redis.properties

redis.hostName=127.0.0.1 
redis.port=6379
#redis.password=123456
redis.timeout=10000  
redis.maxIdle=300  
redis.maxTotal=1000  
redis.maxWaitMillis=1000  
redis.minEvictableIdleTimeMillis=300000  
redis.numTestsPerEvictionRun=1024  
redis.timeBetweenEvictionRunsMillis=30000  
redis.testOnBorrow=true  
redis.testWhileIdle=true

ehcache-shiro.xml

<ehcache updateCheck="false" name="shiroCache">
   <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />
ehcache>

User实体

public class User implements Serializable{
    private static final long serialVersionUID = 1L;
    private String userID;
    private String username;
    private String password;
    ...getter and setter
}

序列化和反序列化工具

public class SerializeUtils {

    /**
     * 序列化
     * 
     * @param object
     * @return
     * @throws Exception
     */
    public static byte[] serialize(Object object) throws Exception {
        if(object == null) return null;
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 反序列化
     * 
     * @param bytes
     * @return
     * @throws Exception
     */
    public static Object unSerialize(byte[] bytes) throws Exception {
        if(bytes == null) return null;
        ByteArrayInputStream bais = null;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }


    // 把session对象转化为byte保存到redis中  
    public static byte[] sessionToByte(Session session){  
        ByteArrayOutputStream bo = null; 
        byte[] bytes = null;
        ObjectOutput oo = null;
        try {
            bo = new ByteArrayOutputStream();  
            oo = new ObjectOutputStream(bo);  
            oo.writeObject(session);  
            bytes = bo.toByteArray();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }finally {
            try {
                if(null != oo){
                    oo.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(null != bo){
                    bo.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;  
    }  

    // 把byte还原为session  
    public static Session byteToSession(byte[] bytes){  
        ObjectInputStream in = null;
        Session session = null;  
        try {  
            in = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(bytes)));    
            session = (Session) in.readObject();  
        } catch (ClassNotFoundException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  catch (Exception e) {
            e.printStackTrace();  
        }
        return session;  
    }  
}

redis工具类

/**
 * @author myj 
 *  基于spring和redis的redisTemplate工具类
 *  针对所有的hash 都是以h开头的方法 
 *  针对所有的Set  都是以s开头的方法 不含通用方法
 *  针对所有的List 都是以l开头的方法
 */

@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate redisTemplate;

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // =============================common============================
    /**
     * 指定缓存失效时间
     * 
     * @param key
     *            键
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     * 
     * @param key
     *            键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     * 
     * @param key
     *            键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public List hmget(){
        List list = new ArrayList();
        List values = redisTemplate.boundHashOps(KEY).values();
        for (Object object : values) {
            list.add((Session) object);
        }
        return list;
    }


    public List keys(){
      Set values =  redisTemplate.keys("*");
      List list = new LinkedList();
      for (Object object : values) {
        list.add((String)object);
      }
      return list;
    }

    /**
     * 删除缓存
     * 
     * @param key
     *            可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

     /** 
     * 删除对应的value 
     *  
     * @param key 
     */  
    public void remove(final String key) {  
        if (exists(key)) {  
            redisTemplate.delete(key);  
        }  
    }

    /** 
     * 判断缓存中是否有对应的value 
     *  
     * @param key 
     * @return 
     */  
    public boolean exists(final String key) {  
        return redisTemplate.hasKey(key);  
    }  


    /** 
     * 批量删除对应的value 
     * @param keys 
     */  
    public void remove(final String... keys) {  
        for (String key : keys) {  
            remove(key);  
        }  
    }

    /** 
     * 批量删除key 
     *  
     * @param pattern 
     */  
    public void removePattern(final String pattern) {  
        Set keys = redisTemplate.keys(pattern);  
        if (keys.size() > 0)  
            redisTemplate.delete(keys);  
    }


    // ============================String=============================

    /**
     * 普通缓存放入并设置时间
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


     /** 
     * 读取缓存 
     *  
     * @param key 
     * @return 
     */  
    public Object get(final String key) {  
        Object result = null;  
        ValueOperations operations = redisTemplate.opsForValue();  
        result = operations.get(key);  
        return result;  
    }  

    /** 
     * 写入缓存 
     *  
     * @param key 
     * @param value 
     * @return 
     */  
    public boolean set(final String key, Object value) {  
        boolean result = false;  
        try {  
            ValueOperations operations = redisTemplate.opsForValue();  
            operations.set(key, value);  
            result = true;  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  

    /** 
     * 写入缓存 
     *  
     * @param key 
     * @param value 
     * @return 
     */  
    public boolean set(final String key, Object value, Long expireTime) {  
        boolean result = false;  
        try {  
            ValueOperations operations = redisTemplate.opsForValue();  
            operations.set(key, value);  
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);  
            result = true;  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  

    /**
     * 递增
     * 
     * @param key
     *            键
     * @param by
     *            要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     * 
     * @param key
     *            键
     * @param by
     *            要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ================================Map=================================
    /**
     * HashGet
     * 
     * @param key
     *            键 不能为null
     * @param item
     *            项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     * 
     * @param key
     *            键
     * @return 对应的多个键值
     */
    public Map hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     * 
     * @param key
     *            键
     * @param map
     *            对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     * 
     * @param key
     *            键
     * @param map
     *            对应多个键值
     * @param time
     *            时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * 
     * @param key
     *            键
     * @param item
     *            项
     * @param value
     *            值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * 
     * @param key
     *            键
     * @param item
     *            项
     * @param value
     *            值
     * @param time
     *            时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     * 
     * @param key
     *            键 不能为null
     * @param item
     *            项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     * 
     * @param key
     *            键 不能为null
     * @param item
     *            项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     * 
     * @param key
     *            键
     * @param item
     *            项
     * @param by
     *            要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     * 
     * @param key
     *            键
     * @param item
     *            项
     * @param by
     *            要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ============================set=============================
    /**
     * 根据key获取Set中的所有值
     * 
     * @param key
     *            键
     * @return
     */
    public Set sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     * 
     * @param key
     *            键
     * @param value
     *            值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     * 
     * @param key
     *            键
     * @param values
     *            值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     * 
     * @param key
     *            键
     * @param time
     *            时间(秒)
     * @param values
     *            值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     * 
     * @param key
     *            键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     * 
     * @param key
     *            键
     * @param values
     *            值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    // ===============================list=================================

    /**
     * 获取list缓存的内容
     * 
     * @param key
     *            键
     * @param start
     *            开始
     * @param end
     *            结束 0 到 -1代表所有值
     * @return
     */
    public List lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     * 
     * @param key
     *            键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     * 
     * @param key
     *            键
     * @param index
     *            索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     * 
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * 
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * 
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean lSet(String key, List value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * 
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean lSet(String key, List value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     * 
     * @param key
     *            键
     * @param index
     *            索引
     * @param value
     *            值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     * 
     * @param key
     *            键
     * @param count
     *            移除多少个
     * @param value
     *            值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
} 
  

MyShiroSessionListener

public class MyShiroSessionListener implements SessionListener {  

    @Autowired RedisUtil redisUtil;

    @Override  
    public void onStart(Session session) {  
    }  

    @Override  
    public void onStop(Session session) {  
        redisUtil.remove(session.getId().toString());  
    }  

    @Override  
    public void onExpiration(Session session) {  
        redisUtil.remove(session.getId().toString());  
    }  

}  

SessionDao

@Component
public class SessionDao extends EnterpriseCacheSessionDAO {  

    private RedisUtil redisUtil; 

    public RedisUtil getRedisUtil(){
        return redisUtil;  
    }  

    public void setRedisUtil(RedisUtil redisUtil) {  
        this.redisUtil = redisUtil;  
    }  

    // 创建session,保存到数据库  
    @Override  
    protected Serializable doCreate(Session session) { 
        Serializable sessionId = super.doCreate(session);
        redisUtil.set(session.getId().toString(), SerializeUtils.sessionToByte(session),1*60*30L);
        return sessionId;  
    }  

    // 获取session  
    @Override  
    protected Session doReadSession(Serializable sessionId) {  
        // 先从缓存中获取session,如果没有再去数据库中获取  
       Session session = super.doReadSession(sessionId);
       if(session == null){
            Object object = null;
            byte[] bytes = null;
            if(redisUtil.exists(sessionId.toString())){
                object = redisUtil.get(sessionId.toString());
            }
            if(null != object){
                bytes = (byte[])object;
            }
            if(bytes != null && bytes.length > 0){  
                session = (Session) SerializeUtils.byteToSession(bytes);
            }  
        }  
        return session;
    }  

    // 更新session的最后一次访问时间  
    @Override  
    protected void doUpdate(Session session) {
        super.doUpdate(session);  
        redisUtil.set(session.getId().toString(), SerializeUtils.sessionToByte(session),1*60*30L);
    }

    @Override
    public Collection getActiveSessions() {
        List list = redisUtil.hmget();
        return list;
    }

    // 删除session  
    @Override
    public void doDelete(Session session) {  
        super.doDelete(session);  
        redisUtil.remove(session.getId().toString());  
    }  


}  

Usercontroller部分代码

    /**
     * 下线某在线用户
     * @return
     */
    @RequestMapping(value = "/offline")
    @ResponseBody
    public String offline(){
        String sessionid = getParams().getString("id");
        byte[] bytes = null;
        Session session =  null;
        try{
            if(redisUtil.exists(sessionid.toString())){
                bytes = (byte[]) redisUtil.get(sessionid.toString());
            }
            if(bytes != null && bytes.length > 0){  
                session = SerializeUtils.byteToSession(bytes);
                if(session !=  null){
                    sessionDao.delete(session);
                }
            }  
            return "success";
        }catch(Exception e){
            e.printStackTrace();
            return "error";
        }
    }

    /**
     * 获取在线人数
     * @param model
     * @return
     */
    @RequestMapping(value = "/getUserOnline")
    public String getUserOnline(Model model){
        Map onlineMap = null;
        Session session =  null;
        User user = null;
        byte[] bytes = null;
        try {
            List list = redisUtil.keys();
            if(list.size() >0){
                onlineMap = new LinkedHashMap();
                for (String key : list) {
                    if(redisUtil.exists(key.toString())){
                        bytes = (byte[]) redisUtil.get(key.toString());
                    }
                    if(bytes != null && bytes.length > 0){  
                        session = SerializeUtils.byteToSession(bytes);
                        if(session !=  null){
                            user = (User) session.getAttribute("currentUser");
                            if(user != null){
                                onlineMap.put(key, user);
                            }
                        }
                    }  
                }
            }
            model.addAttribute("onlineMap", onlineMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "base/user/online";
    }

spring容器启动监听,清楚redis中的缓存

/**
 * spring容器监听类
 * 容器重启时,清空redis缓存
 * @author mayi
 *
 */
@Component
public class MyContextRefreshedEvent implements ApplicationListener<ContextRefreshedEvent>{ 

    @Override  
    public void onApplicationEvent(ContextRefreshedEvent arg0) {  
        @SuppressWarnings("resource")
        JedisPool jedisPool = new JedisPool("127.0.0.1",6379);
        Jedis jedis = jedisPool.getResource();
        jedis.flushAll();
        jedis = null;
        jedisPool = null;
    }  

}  

你可能感兴趣的:(项目总结)