| package com.doumee.config.shiro; | 
|   | 
| import lombok.extern.slf4j.Slf4j; | 
| import org.apache.shiro.cache.Cache; | 
| import org.apache.shiro.cache.CacheException; | 
| import org.apache.shiro.subject.PrincipalCollection; | 
| import org.apache.shiro.util.CollectionUtils; | 
| import org.springframework.context.annotation.Scope; | 
| import org.springframework.data.redis.core.RedisTemplate; | 
| import org.springframework.data.redis.serializer.SerializationException; | 
| import org.springframework.stereotype.Component; | 
|   | 
| import javax.annotation.Resource; | 
| import java.io.Serializable; | 
| import java.lang.reflect.Method; | 
| import java.util.ArrayList; | 
| import java.util.Collection; | 
| import java.util.Collections; | 
| import java.util.Set; | 
| import java.util.concurrent.TimeUnit; | 
|   | 
| /** | 
|  * Shiro缓存 | 
|  * @author Eva.Caesar Liu | 
|  * @date 2023/04/17 12:11 | 
|  */ | 
| @Scope(value = "prototype") | 
| @Slf4j | 
| @Component | 
| public class ShiroCache implements Cache<Object, Serializable> { | 
|   | 
|     private String keyPrefix = ""; | 
|   | 
|     @Resource(name="sessionRedisTemplate") | 
|     private RedisTemplate<Object, Serializable> redisTemplate; | 
|   | 
|     public ShiroCache () { | 
|         log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]"); | 
|     } | 
|   | 
|     public ShiroCache(String keyPrefix) { | 
|         log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]"); | 
|         this.keyPrefix = keyPrefix; | 
|     } | 
|   | 
|     @Override | 
|     public Serializable get(Object key) throws CacheException { | 
|         if (key == null) { | 
|             return null; | 
|         } | 
|         return redisTemplate.opsForValue().get(getKey(key)); | 
|     } | 
|   | 
|     @Override | 
|     public Serializable put(Object key, Serializable value) throws CacheException { | 
|         if (key == null) { | 
|             return null; | 
|         } | 
|         redisTemplate.opsForValue().set(getKey(key), value); | 
|         return value; | 
|     } | 
|   | 
|     public Serializable put(Object key, Serializable value, int timeout) throws CacheException { | 
|         if (key == null) { | 
|             return null; | 
|         } | 
|         redisTemplate.opsForValue().set(getKey(key), value, timeout, TimeUnit.SECONDS); | 
|         return value; | 
|     } | 
|   | 
|     @Override | 
|     public void clear() throws CacheException { | 
|         Set<Object> keys = this.keys(); | 
|         redisTemplate.delete(keys); | 
|     } | 
|   | 
|     @Override | 
|     public int size() { | 
|         return this.keys().size(); | 
|     } | 
|   | 
|     @Override | 
|     public Set<Object> keys() { | 
|         Set<Object> keys = redisTemplate.keys(keyPrefix + "*"); | 
|         if (CollectionUtils.isEmpty(keys)) { | 
|             return Collections.emptySet(); | 
|         } | 
|         return keys; | 
|     } | 
|   | 
|     @Override | 
|     public Collection<Serializable> values() { | 
|         Collection<Serializable> values = new ArrayList<>(); | 
|         Set<Object> keys = this.keys(); | 
|         if (CollectionUtils.isEmpty(keys)) { | 
|             return values; | 
|         } | 
|         for (Object k : keys) { | 
|             values.add(redisTemplate.opsForValue().get(k)); | 
|         } | 
|         return values; | 
|     } | 
|   | 
|     @Override | 
|     public Serializable remove(Object key) throws CacheException { | 
|         if (key == null) { | 
|             return null; | 
|         } | 
|         Serializable value = this.get(getKey(key)); | 
|         redisTemplate.delete(getKey(key)); | 
|         return value; | 
|     } | 
|   | 
|     private Object getKey (Object key) { | 
|         if (key instanceof PrincipalCollection) { | 
|             return this.keyPrefix + getRedisKeyFromPrincipalIdField((PrincipalCollection)key); | 
|         } | 
|         return (key instanceof String ? (this.keyPrefix + key) : key); | 
|     } | 
|   | 
|     /** | 
|      * 获取redis cache key | 
|      */ | 
|     private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) { | 
|         Object principalObject = key.getPrimaryPrincipal(); | 
|         if (principalObject instanceof String) { | 
|             return principalObject.toString(); | 
|         } else { | 
|             Method pincipalIdGetter = this.getPrincipalIdGetter(principalObject); | 
|             return this.getIdObj(principalObject, pincipalIdGetter); | 
|         } | 
|     } | 
|   | 
|     private Method getPrincipalIdGetter(Object principalObject) { | 
|         Method pincipalIdGetter; | 
|         String principalIdMethodName = this.getPrincipalIdMethodName(); | 
|   | 
|         try { | 
|             pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName); | 
|             return pincipalIdGetter; | 
|         } catch (NoSuchMethodException e) { | 
|             throw new SerializationException(e.getMessage(), e); | 
|         } | 
|     } | 
|   | 
|     private String getIdObj(Object principalObject, Method pincipalIdGetter) { | 
|         try { | 
|             Object idObj = pincipalIdGetter.invoke(principalObject); | 
|             String redisKey = idObj.toString(); | 
|             return redisKey; | 
|         } catch (Exception e) { | 
|             throw new SerializationException(e.getMessage(), e); | 
|         } | 
|     } | 
|   | 
|     private String getPrincipalIdMethodName() { | 
|         return "getId"; | 
|     } | 
| } |