zoukankan      html  css  js  c++  java
  • OA系统之shiro和redis

      系统采用activiti工作流,SSM框架,quartz定时任务,shiro权限管理,redis缓存。

      这篇文章不适合小白,小白请转http://jinnianshilongnian.iteye.com/,自行学习。
      这篇文章就是为了锻炼我自己的码字速度的,以后搬砖方便,不谢。

    工作流看http://www.kafeitu.me/和http://jinnianshilongnian.iteye.com/ 后者有很多好的文章,包括怎么使用shiro啥的。

    1、序列化工具:
    主要用于对对象进行序列化和反序列化。
    public class SerializationUtils {
    public static byte[] serialize(Object o) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
    ObjectOutputStream outo = new ObjectOutputStream(out);
    outo.writeObject(o);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    return out.toByteArray();
    }

    public static String serializeToString(Serializable obj) {
    try {
    byte[] value = serialize(obj);
    return Base64.encodeToString(value);
    } catch (Exception e) {
    throw new RuntimeException("serialize session error", e);
    }
    }

    public static Object deserialize(byte[] b) {
    ObjectInputStream oin;
    try {
    oin = new ObjectInputStream(new ByteArrayInputStream(b));
    try {
    return oin.readObject();
    } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    return null;
    }
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    return null;
    }
    }

    /**
    * string 转session专用
    * @param base64
    * @return
    */
    public static Session deserializeFromString(String base64) {
    try {
    byte[] objectData = Base64.decode(base64);
    return (Session)deserialize(objectData);
    } catch (Exception e) {
    throw new RuntimeException("deserialize session error", e);
    }
    }
    }

    2、realm 需要自己继承AuthorizingRealm对登录和授权进行重写。
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
    AuthenticationToken token) throws AuthenticationException {
    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    String username = upToken.getUsername();

    Account account = userService.getAccountByAccNum(username);

    if (null == account) {
    logger.error(MessageFormat.format(
    "{0} 在 {1,date,yyyy-MM-dd HH:mm:ss} 登录办公系统(没有该账号)。",
    username, new Date()));
    throw new UnknownAccountException("用户不存在!");
    }

    if ("1".equals(account.getIsLocked())) {
    logger.error(MessageFormat.format(
    "{0} 在 {1,date,yyyy-MM-dd HH:mm:ss} 登录办公系统(账号被锁定)。",
    username, new Date()));
    throw new LockedAccountException("用户被锁定");
    }

    logger.info(MessageFormat.format(
    "{0} 在 {1,date,yyyy-MM-dd HH:mm:ss} 登录办公系统。", username,
    new Date()));


    Object principal = username;
    // 2). credentials: 密码.
    Object credentials = account.getAccPwd();
    String realmName = getName();
    // 4). 盐值.
    ByteSource credentialsSalt = ByteSource.Util.bytes(username);

    JedisPool jedisPool = redisManager.getRedisManager().getJedisPool();
    Jedis resource = jedisPool.getResource();
    try {
    resource.set(RedisSessionDAO.getByteKey(RedisSessionDAO.SHIRO_REDIS_USER_PRE, username), SerializationUtils.serialize(account));
    } catch (Exception e) {
    logger.error("登录缓存存储失败!"+e.toString());
    e.printStackTrace();
    }finally{
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    }
    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials,
    credentialsSalt, realmName);

    // 把账号信息放到Session中,并更新缓存,用于会话管理
    Subject subject = SecurityUtils.getSubject();
    Serializable sessionId = subject.getSession().getId();
    ShiroSession session = (ShiroSession) sessionDao.doReadSessionWithoutExpire(sessionId);
    session.setAttribute("userId", account.getId());
    session.setAttribute("loginName", account.getAccNum());
    sessionDao.update(session);

    return info;
    }

    // 授权会被 shiro 回调的方法
    @SuppressWarnings("unused")
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    // 1. 从 PrincipalCollection 中来获取登录用户的信息
    Object principal = principals.getPrimaryPrincipal();
    String userId=(String)getAvailablePrincipal(principals);
    // 因为非正常退出,即没有显式调用 SecurityUtils.getSubject().logout()
    // (可能是关闭浏览器,或超时),但此时缓存依旧存在(principals),所以会自己跑到授权方法里。
    if (!SecurityUtils.getSubject().isAuthenticated()) {
    doClearCache(principals);
    SecurityUtils.getSubject().logout();
    return null;
    }

    if (principals == null) {
    throw new AuthorizationException("parameters principals is null");
    }
    //获取已认证的用户名(登录名)
    if(StringUtils.isEmpty(userId)){
    return null;
    }

    // 2. 利用登录的用户的信息来用户当前用户的角色或权限(可能需要查询数据库)
    //String sql = "select GROUP_ID_ from act_id_membership where user_id_ = ?";
    String username = principal.toString();

    // 3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
    //List<String> list = jt.queryForList(sql, String.class, username);
    Set<String> roles = new HashSet<>();
    Account account = userService.getAccountByAccNum(username);
    List<PageData> allRoleByAccNum = userService.getAllRoleByAccNum(username);

    for(PageData tem : allRoleByAccNum){
    roles.add(tem.getString("roleCode"));
    }

    Set<String> stringPermissions = new HashSet<String>();
    stringPermissions.add("add");
    stringPermissions.add("del");
    stringPermissions.add("update");
    stringPermissions.add("query");
    // 3. 创建 SimpleAuthorizationInfo, 并设置其 reles 属性.
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    info.setRoles(roles);

    //根据角色获取 角色权限 精确到 CRUD级别
    //info.addObjectPermission(new WildcardPermission("user:add"));
    JedisPool jedisPool = redisManager.getRedisManager().getJedisPool();
    Jedis resource = jedisPool.getResource();
    try {
    if (roles.size() > 0) {
    for (String module : stringPermissions) {
    info.addObjectPermission(new WildcardPermission("user:"+module));
    }
    resource.set(RedisSessionDAO.getByteKey(RedisSessionDAO.PERMISSION_PRE, username),
    SerializationUtils.serialize(info.getObjectPermissions()));
    }
    // cacheManager.getCache("").clear();
    resource.set(RedisSessionDAO.getByteKey(RedisSessionDAO.SHIRO_REDIS_ROLE_PRE, username),
    SerializationUtils.serialize(info.getRoles()));
    } catch (Exception e) {
    logger.error("授权失败!"+e.toString());
    e.printStackTrace();
    }finally{
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    }
    // 4. 返回 SimpleAuthorizationInfo 对象.
    return info;
    }

    /**
    * 更新用户授权信息缓存.
    */

    // 登陆成功后强制加载shiro权限缓存 避免懒加载 先清除
    public void forceShiroToReloadUserAuthorityCache() {
    this.clearCachedAuthorizationInfo(SecurityUtils.getSubject()
    .getPrincipal());
    this.isPermitted(SecurityUtils.getSubject().getPrincipals(),
    "强制加载缓存,避免懒加载" + System.currentTimeMillis());
    }

    3、shiro的session需要重写,并配合一个工厂类和ShiroSessionListener。为什么和怎么写就看这个博客:http://www.cnblogs.com/shihaiming/p/6406640.html

    4、quartz
    我觉得最牛逼的就是那个定时启动时间的设置了,相比自己写的要好很多,当然自己写定时任务也可以(我以前不知道有quartz),用这个就是时间那里太方便了。
    你可能遇见版本不支持的问题,就是shiro是1.6的你用的2.X的,不要紧重写两个类就行了。看博客:http://blog.csdn.net/rogerjava/article/details/70920763
    有两种方式,这里就介绍一种execute。配置文件如下:
    <!--要调度的对象-->
    <bean id="jobBean" class="com.wuqidi.common.quartz.QuartzTestManager" />
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="jobBean"/>
    <property name="targetMethod" value="execute"/><!-- 执行"jobBean"中的execute方法 -->
    <property name="concurrent" value="false"/><!--将并发设置为false-->
    </bean>
    <!-- ======================== 调度 ======================== -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"><!-- 定义 Job 何时执行 -->
    <property name="jobDetail" ref="jobDetail" />
    <property name="cronExpression" value="0/3 * * * * ?" /><!-- 这里就是设置时间的 双击666 -->
    </bean>
    <!-- ======================== 调度工厂 ======================== -->
    <!-- 总管理类如果将lazy-init='false'那么容器启动就会执行调度程序 -->
    <bean id="startQuertz" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" >
    <property name="triggers">
    <list>
    <ref bean="trigger" /><!--作业调度器,list下可加入其他的调度器-->
    </list>
    </property>
    </bean>
    5、缓存 搬得砖
    public class RedisCacheManager implements CacheManager {
    private static final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);

    // fast lookup by name map
    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();

    private JedisPoolManager redisManager;

    public JedisPoolManager getRedisManager() {
    return redisManager;
    }

    public void setRedisManager(JedisPoolManager redisManager) {
    this.redisManager = redisManager;
    }

    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
    // TODO Auto-generated method stub
    logger.debug("获取名称为: " + name + " 的RedisCache实例");
    System.out.println("获取名称为: " + name + " 的RedisCache实例");
    Cache c = caches.get(name);
    if (c == null) {
    c = new RedisCache<K, V>(redisManager);
    caches.put(name, c);
    }
    return c;
    }
    }

    public class RedisCache<K,V> implements Cache<K,V> {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private JedisPoolManager cache;

    private String keyPrefix = RedisSessionDAO.SHIRO_REDIS_SESSION_PRE;

    /**
    * 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(JedisPoolManager 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(JedisPoolManager 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 if(key instanceof PrincipalCollection){
    String preKey = this.keyPrefix + key.toString();
    return preKey.getBytes();
    }else{
    return SerializationUtils.serialize(key);
    }
    }

    @Override
    public V get(K key) throws CacheException {
    Jedis resource = null;
    JedisPool jedisPool = null;
    logger.debug("根据key从Redis中获取对象 key [" + key + "]");
    System.out.println("根据key从Redis中获取对象 key [" + key + "]");
    try {
    if (key == null) {
    return null;
    }else{

    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    System.out.println((new String(getByteKey(key))));

    byte[] rawValue = resource.get(getByteKey(key));//cache.get(getByteKey(key));

    if(rawValue==null || rawValue.length <= 0){return null;}
    @SuppressWarnings("unchecked")
    V value = (V)SerializationUtils.deserialize(rawValue);
    return value;
    }
    } catch (Throwable t) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }

    }

    @Override
    public V put(K key, V value) throws CacheException {
    Jedis resource = null;
    JedisPool jedisPool = null;
    logger.debug("根据key从存储 key [" + key + "]");
    System.out.println("根据key从存储 key [" + key + "]");
    try {
    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    //cache.set(getByteKey(key), SerializationUtils.serialize(value));
    resource.set(this.getByteKey(key),SerializationUtils.serialize(value));
    return value;
    } catch (Throwable t) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }
    }

    @Override
    public V remove(K key) throws CacheException {
    Jedis resource = null;
    JedisPool jedisPool = null;
    logger.debug("从redis中删除 key [" + key + "]");
    System.out.println("从redis中删除 key [" + key + "]");
    try {
    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    V previous = get(key);
    //cache.del(getByteKey(key));
    resource.del(getByteKey(key));
    return previous;
    } catch (Throwable t) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }
    }

    @Override
    public void clear() throws CacheException {
    Jedis resource = null;
    JedisPool jedisPool = null;
    logger.debug("从redis中删除所有元素");
    System.out.println("从redis中删除所有元素");
    try {
    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    resource.flushDB();
    } catch (Throwable t) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }
    }

    @Override
    public int size() {
    Jedis resource = null;
    JedisPool jedisPool = null;
    try {
    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    Long longSize = new Long(resource.dbSize());
    return longSize.intValue();
    } catch (Throwable t) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Set<K> keys() {
    Jedis resource = null;
    JedisPool jedisPool = null;
    try {
    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    Set<byte[]> keys = resource.keys((this.keyPrefix + "*").getBytes());
    // Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
    if (CollectionUtils.isEmpty(keys)) {
    return Collections.emptySet();
    }else{
    Set<K> newKeys = new HashSet<K>();
    for(byte[] key:keys){
    newKeys.add((K)key);
    }
    return newKeys;
    }
    } catch (Throwable t) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }
    }

    @Override
    public Collection<V> values() {
    Jedis resource = null;
    JedisPool jedisPool = null;
    try {
    jedisPool = cache.getJedisPool();
    resource = jedisPool.getResource();
    Set<byte[]> keys = resource.keys((this.keyPrefix + "*").getBytes());
    if (!CollectionUtils.isEmpty(keys)) {
    List<V> values = new ArrayList<V>(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) {
    if (resource != null) {
    jedisPool.returnBrokenResource(resource);
    }
    throw new CacheException(t);
    }
    }
    }
    6、sessiondao
    CachingSessionDAO 据说能减少访问redis的次数,但是 没体会到。。。然后问了同事,同事说shiro的过滤设置下静态资源,恩,我之前就已经设置了。反正就是多次访问的问题没有解决,doread方法。
    public class RedisSessionDAO extends CachingSessionDAO{
    private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);

    public final static String PRINCIPALS_SESSION_KEY
    = "org.apache.shiro.subject.support.DefaultSubjectContext.PRINCIPALS_SESSION_KEY";// 保存 principal
    public final static String AUTHENTICATED_SESSION_KEY
    = "org.apache.shiro.subject.support.DefaultSubjectContext.AUTHENTICATED_SESSION_KEY";// 保存 boolean是否登陆


    /**shiro-redis的session对象前缀 */
    public final static String SHIRO_REDIS_SESSION_PRE = "shiro_redis_session:";

    /**存放uid的对象前缀 */
    public final static String SHIRO_SHESSIONID_PRE = "shiro_sessionid:";

    /**存放uid 当前状态的前缀 */
    public final static String UID_PRE = "uid:";

    /**存放用户权限的前缀 */
    public final static String PERMISSION_PRE ="permission:";

    /**存放用户实体的前缀 */
    public final static String SHIRO_REDIS_USER_PRE ="shiro_redis_user:";

    /**存放用户角色的前缀 */
    public final static String SHIRO_REDIS_ROLE_PRE ="shiro_redis_role:";

    private String expire;

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

    private JedisPoolManager redisManager;

    public void setRedisManager(JedisPoolManager redisManager) {
    this.redisManager = redisManager;
    }
    public JedisPoolManager getRedisManager() {
    return redisManager;
    }

    //**************************************************************************

    // 保存到Redis中key的前缀 prefix+sessionId
    //private String prefix = "";

    // 设置会话的过期时间
    //private int seconds = 0;
    /**
    * 重写CachingSessionDAO中readSession方法,如果Session中没有登陆信息就调用doReadSession方法从Redis中重读
    */
    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
    Session session = getCachedSession(sessionId);
    if (session == null
    || session.getAttribute(PRINCIPALS_SESSION_KEY) == null) {
    session = this.doReadSession(sessionId);
    if (session == null) {
    throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
    } else {
    // 缓存
    cache(session, session.getId());
    }
    }
    return session;
    }


    @SuppressWarnings("static-access")
    public Session doReadSessionWithoutExpire(Serializable sessionId) {
    Session session = null;
    Jedis jedis = null;
    JedisPool jedisPool = null;
    try {
    jedisPool = redisManager.getJedisPool();
    jedis = jedisPool.getResource();

    String key = SHIRO_REDIS_SESSION_PRE + sessionId;
    /* String value = jedis.get(key);
    if (StringUtils.isNotBlank(value)) {
    session = SerializationUtils.deserializeFromString(value);
    }*/
    byte[] value = jedis.get(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE , sessionId));
    if (StringUtils.isNotBlank(new String(value))) {
    session = (Session) SerializationUtils.deserialize(value);
    logger.info("sessionId {} ttl {}: ", sessionId, jedis.ttl(key));
    // 重置Redis中缓存过期时间
    jedis.expire(key, 1800000);
    logger.info("sessionId {} name {} 被读取", sessionId, session.getClass().getName());
    }
    } catch (Exception e) {
    logger.warn("读取Session失败", e);
    } finally {
    jedisPool.returnResource(jedis);
    }

    return session;
    }


    /**
    * 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用
    */
    @Override
    protected void doUpdate(Session session) {
    Long redisExpire = (long) (1800000/1000);
    int timeout = redisExpire.intValue();

    //如果会话过期/停止 没必要再更新了
    try {
    if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
    return;
    }
    } catch (Exception e) {
    logger.error("ValidatingSession error");
    }

    Jedis jedis = null;
    JedisPool jedisPool = redisManager.getJedisPool();
    jedis = jedisPool.getResource();
    try {
    if (session instanceof ShiroSession) {
    // 如果没有主要字段(除lastAccessTime以外其他字段)发生改变
    ShiroSession ss = (ShiroSession) session;
    if (!ss.isChanged()) {
    return;
    }
    Transaction tx = null;
    try {
    // 开启事务
    tx = jedis.multi();
    ss.setChanged(false);
    tx.setex(SHIRO_REDIS_SESSION_PRE + session.getId(), timeout, SerializationUtils.serializeToString(ss));
    logger.info("sessionId {} name {} 被更新", session.getId(), session.getClass().getName());
    // 执行事务
    tx.exec();
    } catch (Exception e) {
    if (tx != null) {
    // 取消执行事务
    tx.discard();
    }
    throw e;
    }

    } else if (session instanceof Serializable) {

    jedis.setex(SHIRO_REDIS_SESSION_PRE + session.getId(), timeout, SerializationUtils.serializeToString((Serializable) session));
    logger.info("sessionId {} name {} 作为非ShiroSession对象被更新, ", session.getId(), session.getClass().getName());
    } else {
    logger.warn("sessionId {} name {} 不能被序列化 更新失败", session.getId(), session.getClass().getName());
    }
    } catch (Exception e) {
    logger.warn("更新Session失败", e);
    } finally {
    jedisPool.returnResource(jedis);
    }
    }

    /**
    * 删除会话;当会话过期/会话停止(如用户退出时)会调用
    */
    @Override
    protected void doDelete(Session session) {
    Jedis jedis = null;
    JedisPool jedisPool = redisManager.getJedisPool();
    try {
    jedis = jedisPool.getResource();
    jedis.del(SHIRO_REDIS_SESSION_PRE + session.getId());
    logger.debug("Session {} 被删除", session.getId());
    } catch (Exception e) {
    logger.warn("修改Session失败", e);
    } finally {
    jedisPool.returnResource(jedis);
    }
    }

    /**
    * 删除cache中缓存的Session
    */
    public void uncache(Serializable sessionId) {
    Session session = this.readSession(sessionId);
    super.uncache(session);
    logger.info("取消session {} 的缓存", sessionId);
    }

    /**
    * 获取当前所有活跃用户,如果用户量多此方法影响性能
    */
    @Override
    public Collection<Session> getActiveSessions() {
    Jedis jedis = null;
    JedisPool jedisPool = redisManager.getJedisPool();
    try {
    jedis = jedisPool.getResource();
    Set<String> keys = jedis.keys(SHIRO_REDIS_SESSION_PRE + "*");
    if (CollectionUtils.isEmpty(keys)) {
    return null;
    }
    List<String> valueList = jedis.mget(keys.toArray(new String[0]));
    Collection<Session> retu = new ArrayList<Session>();
    for(String tem : valueList){
    retu.add(SerializationUtils.deserializeFromString(tem));
    }
    return retu;
    } catch (Exception e) {
    logger.warn("统计Session信息失败", e);
    } finally {
    jedisPool.returnResource(jedis);
    }
    return null;
    }


    //****************************************************************




    @Override
    public void update(Session session) throws UnknownSessionException {
    //super.update(session);
    System.out.println("update" + session.getId());
    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;
    }
    System.out.println("save" + session.getId());
    session.setTimeout(1800000);
    Long redisExpire = (long) (1800000/1000);
    int timeout = redisExpire.intValue();
    JedisPool jedisPool = this.redisManager.getJedisPool();
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    //保存用户会话
    jedis.setex(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE,session.getId()), timeout, SerializationUtils.serialize(session));
    String uid = this.getUserId(session);
    if (null != uid && !"".equals(uid)){
    //保存用户会话对应的UID
    jedis.setex(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()),timeout, uid.getBytes());
    //保存在线UID
    jedis.setex(this.getByteKey(this.UID_PRE,uid), timeout,"online".getBytes());
    }
    jedisPool.returnResource(jedis);
    }catch(Exception ex){
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(ex);
    }
    }

    @Override
    public void delete(Session session) {
    if (session == null || session.getId() == null) {
    logger.error("session or session id is null");
    return;
    }
    System.out.println("delete" + session.getId());

    JedisPool jedisPool = this.redisManager.getJedisPool();
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();

    //删除用户会话
    jedis.del(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE,session.getId()));
    //获取缓存的用户会话对应的UID
    byte[] uid = jedis.get(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()));
    System.out.println("delete" + new String(uid));
    //删除用户会话对应的UID
    jedis.del(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()));

    //删除在线UID
    jedis.del(this.getByteKey(this.UID_PRE,new String(uid)));

    //删除用户缓存的权限
    jedis.del(this.getByteKey(this.PERMISSION_PRE, new String(uid)));

    jedis.del(this.getByteKey(this.SHIRO_REDIS_ROLE_PRE, new String(uid)));

    jedis.del(this.getByteKey(this.SHIRO_REDIS_USER_PRE, new String(uid)));

    jedisPool.returnResource(jedis);
    }catch(Exception ex){
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(ex);
    }

    }

    public boolean isOnLine(String uid){

    Set<byte[]>keys = redisManager.keys(this.UID_PRE + uid);
    if (keys != null && keys.size() > 0){
    return true;
    }
    return false;
    }

    /**
    * 如DefaultSessionManager在创建完session后会调用该方法;
    * 如保存到关系数据库/文件系统/NoSQL数据库;即可以实现会话的持久化;
    * 返回会话ID;主要此处返回的ID.equals(session.getId());
    */
    @Override
    protected Serializable doCreate(Session session) {
    System.out.println("create" + session.getId());
    Serializable sessionId = this.generateSessionId(session);
    this.assignSessionId(session, sessionId);
    this.saveSession(session);
    return session.getId();
    }


    /*从redi获取数据 如果没有从数据库获取*/
    @SuppressWarnings("unused")
    @Override
    protected Session doReadSession(Serializable sessionId) {

    logger.info("获取seesion,id=[{}]",sessionId.toString());

    if (sessionId == null) {
    logger.error("session id is null");
    return null;
    }
    System.out.println("read" + sessionId);
    logger.debug("Redis.SessionId=" + new String(getByteKey(this.SHIRO_REDIS_SESSION_PRE,sessionId)));

    Jedis jedis = null;
    Session session = null;
    try {
    jedis = redisManager.getJedisPool().getResource();
    String key = this.SHIRO_REDIS_SESSION_PRE + sessionId;
    byte[] value = jedis.get(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE , sessionId.toString()));
    if (StringUtils.isNotBlank(new String(value))) {
    session = (Session) SerializationUtils.deserialize(value);
    logger.info("sessionId {} ttl {}: ", sessionId, jedis.ttl(key));
    // 重置Redis中缓存过期时间
    jedis.expire(key, 1800000);
    logger.info("sessionId {} name {} 被读取", sessionId, session.getClass().getName());
    }
    } catch (Exception e) {
    logger.warn("读取Session失败", e);
    System.out.println("读取Session失败"+ e.toString());
    } finally {
    redisManager.getJedisPool().returnResource(jedis);
    }
    return session;
    }

    /**
    * 获得byte[]型的key
    *
    * @param key
    * @return
    */
    public static byte[] getByteKey(String preKey,Serializable sessionId) {
    String key = preKey + sessionId;
    return key.getBytes();

    }

    /**
    * 获取用户唯一标识
    * @param session
    * @return
    */
    public String getUserId(Session session) {
    SimplePrincipalCollection pricipal = (SimplePrincipalCollection) session.getAttribute("org.apache.shiro.subject.support.DefaultSubjectContext_PRINCIPALS_SESSION_KEY");
    if (null != pricipal) {
    return pricipal.getPrimaryPrincipal().toString();
    }
    return null;
    }

    }

    7、jedis池
    写到这如果你已经采用3.X版本,此时我会跟你说直接用close即可,return关闭方法已经过时。
    public class JedisPoolManager {
    private static Logger log = LoggerFactory.getLogger(JedisPoolManager.class);

    private JedisPool jedisPool;
    /**
    * redis的List集合 ,向key这个list添加元素
    */
    public long rpush(String key, String string) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    long ret = jedis.rpush(key, string);
    jedisPool.returnResource(jedis);
    return ret;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e.toString());
    }
    }
    /**
    * 获取key这个List,从第几个元素到第几个元素 LRANGE key start
    * stop返回列表key中指定区间内的元素,区间以偏移量start和stop指定。
    * 下标(index)参数start和stop都以0为底,也就是说,以0表示列表的第一个元素,以1表示列表的第二个元素,以此类推。
    * 也可以使用负数下标,以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。
    */
    public List<String> lrange(String key, long start, long end) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    List<String> ret = jedis.lrange(key, start, end);
    jedisPool.returnResource(jedis);
    return ret;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 将哈希表key中的域field的值设为value。
    */
    public void hset(String key, String field, String value) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.hset(key, field, value);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 向key赋值
    */
    public void set(String key, String value) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.set(key, value);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 向key赋值
    */
    public void set(byte[] key, byte[] value) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.set(key, value);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 获取key的值
    */
    public String get(String key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    String value = jedis.get(key);
    jedisPool.returnResource(jedis);
    return value;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 获取key的值
    */
    public byte[] get(byte[] key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    byte[] value = jedis.get(key);
    jedisPool.returnResource(jedis);
    return value;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }

    }
    /**
    * 将多个field - value(域-值)对设置到哈希表key中。
    */
    public void hmset(String key, Map<String, String> map) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.hmset(key, map);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 给key赋值,并生命周期设置为seconds
    */
    public void setex(String key, int seconds, String value) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.setex(key, seconds, value);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 给key赋值,并生命周期设置为seconds
    */
    public byte[] setex(byte[] key, byte[] value, int seconds) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.setex(key, seconds, value);
    jedisPool.returnResource(jedis);
    return value;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }


    }
    /**
    * 为给定key设置生命周期
    */
    public void expire(String key, int seconds) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.expire(key, seconds);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 检查key是否存在
    */
    public boolean exists(String key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    boolean bool = jedis.exists(key);
    jedisPool.returnResource(jedis);
    return bool;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 检查key是否存在
    */
    public boolean exists(byte[] key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    Set<byte[]> hashSet = jedis.keys(key);
    jedisPool.returnResource(jedis);
    if (null != hashSet && hashSet.size() >0 ){
    return true;
    }else{
    return false;
    }

    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 返回key值的类型 none(key不存在),string(字符串),list(列表),set(集合),zset(有序集),hash(哈希表)
    */
    public String type(String key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    String type = jedis.type(key);
    jedisPool.returnResource(jedis);
    return type;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 从哈希表key中获取field的value
    */
    public String hget(String key, String field) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    String value = jedis.hget(key, field);
    jedisPool.returnResource(jedis);
    return value;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 返回哈希表key中,所有的域和值
    */
    public Map<String, String> hgetAll(String key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    Map<String, String> map = jedis.hgetAll(key);
    jedisPool.returnResource(jedis);
    return map;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }

    }
    /**
    * 返回哈希表key中,所有的域和值
    */
    public Set<?> smembers(String key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    Set<?> set = jedis.smembers(key);
    jedisPool.returnResource(jedis);
    return set;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 返回匹配的 keys 列表
    */
    public Set<byte[]> keys(String pattern) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    Set<byte[]> keys = jedis.keys(pattern.getBytes());
    jedisPool.returnResource(jedis);
    return keys;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }

    }
    /**
    * 移除set集合中的member元素
    */
    public void delSetObj(String key, String field) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.srem(key, field);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 删除元素
    */
    public void del(byte[] key) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.del(key);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 判断member元素是否是集合key的成员。是(true),否则(false)
    */
    public boolean isNotField(String key, String field) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    boolean bool = jedis.sismember(key, field);
    jedisPool.returnResource(jedis);
    return bool;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 如果key已经存在并且是一个字符串,将value追加到key原来的值之后
    */
    public void append(String key, String value) {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.append(key, value);
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }
    }
    /**
    * 清空当前的redis 库
    */
    public void flushDB() {
    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.flushDB();
    jedisPool.returnResource(jedis);
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }

    }
    /**
    * 返回当前redis库所存储数据的大小
    */
    @SuppressWarnings("deprecation")
    public Long dbSize() {

    Long dbSize = 0L;

    Jedis jedis = null;
    try {
    jedis = jedisPool.getResource();
    jedis.dbSize();
    jedisPool.returnResource(jedis);
    return dbSize;
    } catch (Exception e) {
    log.error(e.toString());
    if (jedis != null) {
    jedisPool.returnBrokenResource(jedis);
    }
    throw new JedisException(e);
    }

    }
    /**
    * 关闭 Redis
    */
    public void destory() {
    jedisPool.destroy();
    }

    public JedisPool getJedisPool() {
    return jedisPool;
    }
    public void setJedisPool(JedisPool jedisPool) {
    this.jedisPool = jedisPool;
    }
    }
    8、好了 上配置文件

    <!-- 加载配置属性文件 里面配置了redis和数据库的地址啥的-->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:config.properties" />

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="20" />
    <property name="maxTotal" value="500" />
    <property name="minIdle" value="8" />
    <property name="blockWhenExhausted" value="true" />
    <property name="maxWaitMillis" value="30000" />
    <property name="testOnBorrow" value="true" />
    </bean>

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="${jedis.JedisServerIp}" />
    <property name="port" value="${jedis.JedisServerPort}"/>
    <!-- <property name="timeout" value="${jedis.timeout}"/>-->
    <property name="password" value="${jedis.auth}"></property>
    <property name="poolConfig" ref="jedisPoolConfig" />
    <property name="usePool" value="true"/>
    </bean>

    <!-- JedisPool configuration-->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
    <constructor-arg index="0" ref="jedisPoolConfig" />
    <constructor-arg index="1" value="${jedis.JedisServerIp}"/>
    <constructor-arg index="2" value="${jedis.JedisServerPort}"/>
    <constructor-arg index="3" value="${jedis.timeout}"/>
    <constructor-arg index="4" value="${jedis.auth}"/>
    </bean>

    <!-- JedisPool manager -->
    <bean id="jedisPoolManager" class="com.securityframework.support.JedisPoolManager">
    <property name="jedisPool" ref="jedisPool"></property>
    </bean>
    <!--redisCacheManager要实现org.apache.shiro.cache.CacheManager接口,让shiro使用redis的缓存-->
    <bean id="redisCacheManager" class="com.securityframework.support.RedisCacheManager">
    <property name="redisManager" ref="jedisPoolManager"></property>
    </bean>
    <!-- Redis session dao -->
    <!--redisSessionDAO继承实现了org.apache.shiro.session.mgt.eis.SessionDAO的AbstractSessionDAO-->
    <bean id="redisSessionDAO" class="com.securityframework.support.RedisSessionDAO">
    <property name="redisManager" ref ="jedisPoolManager" />
    <property name="expire" value="${shiro.session.timeout}" />
    </bean>

    好了拜拜。

  • 相关阅读:
    Container(容器)
    version ctrl
    url和uri的区别
    Injector
    build tool
    变量
    python中break和continue的区别
    同步代码块以及同步方法之间的区别以及联系
    写在前面
    WebService入门
  • 原文地址:https://www.cnblogs.com/core404/p/7515882.html
Copyright © 2011-2022 走看看