refactor: 缓存改造

pull/10/head
Carina 3 years ago
parent 35f9524378
commit 0179041a6e

@ -21,14 +21,16 @@ package org.opsli.common.constants;
* @author Parker
* @date 2020-09-22 17:07
*/
public interface CacheConstants {
public final class CacheConstants {
String PREFIX_NAME = "opsli";
public static final String PREFIX_NAME = "opsli";
/** Ehcache 缓存存放空间 */
String EHCACHE_SPACE = "timed";
public static final String EHCACHE_SPACE = "timed";
/** 热数据前缀 */
String HOT_DATA_PREFIX = "hot_data";
public static final String HOT_DATA_PREFIX = "hot_data";
private CacheConstants(){}
}

@ -1,35 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.common.constants;
/**
*
*
* @author Parker
* @date 2020-09-16 17:42
*/
public interface DictConstants {
/** 缓存前缀 NAME */
String CACHE_PREFIX_NAME = "dict:name:";
/** 缓存前缀 VALUE*/
String CACHE_PREFIX_VALUE = "dict:value:";
/** 缓存前缀 LIST*/
String CACHE_PREFIX_LIST = "dict:list:";
}

@ -21,18 +21,20 @@ package org.opsli.common.constants;
* @author Parker
* @date 202131015:50:16
*/
public interface MenuConstants {
public final class MenuConstants {
/** 菜单根节点ID */
String GEN_ID = "0";
public static final String GEN_ID = "0";
/** 菜单类型 */
String MENU = "1";
public static final String MENU = "1";
/** 按钮类型 */
String BUTTON = "2";
public static final String BUTTON = "2";
/** 外链类型 */
String EXTERNAL = "3";
public static final String EXTERNAL = "3";
private MenuConstants(){}
}

@ -23,35 +23,37 @@ package org.opsli.common.constants;
* @author Parker
* @date 2020-09-16 17:42
*/
public interface MyBatisConstants {
public final class MyBatisConstants {
/** 逻辑删除值 */
String LOGIC_DELETE_VALUE = "1";
public static final String LOGIC_DELETE_VALUE = "1";
/** 逻辑不删除值 */
String LOGIC_NOT_DELETE_VALUE = "0";
public static final String LOGIC_NOT_DELETE_VALUE = "0";
/** ID */
String FIELD_ID = "id";
public static final String FIELD_ID = "id";
/** PID */
String FIELD_PARENT_ID = "parentId";
public static final String FIELD_PARENT_ID = "parentId";
/** PIDs */
String FIELD_PARENT_IDS = "parentIds";
public static final String FIELD_PARENT_IDS = "parentIds";
/** 创建人 */
String FIELD_CREATE_BY = "createBy";
public static final String FIELD_CREATE_BY = "createBy";
/** 更新时间 */
String FIELD_CREATE_TIME = "createTime";
public static final String FIELD_CREATE_TIME = "createTime";
/** 更新人 */
String FIELD_UPDATE_BY = "updateBy";
public static final String FIELD_UPDATE_BY = "updateBy";
/** 更新时间 */
String FIELD_UPDATE_TIME = "updateTime";
public static final String FIELD_UPDATE_TIME = "updateTime";
/** 逻辑删除 */
String FIELD_DELETE_LOGIC = "deleted";
public static final String FIELD_DELETE_LOGIC = "deleted";
/** 乐观锁 */
String FIELD_OPTIMISTIC_LOCK = "version";
public static final String FIELD_OPTIMISTIC_LOCK = "version";
/** 多租户字段 */
String FIELD_TENANT = "tenantId";
public static final String FIELD_TENANT = "tenantId";
/** 组织字段 */
String FIELD_ORG_GROUP = "orgIds";
public static final String FIELD_ORG_GROUP = "orgIds";
private MyBatisConstants(){}
}

@ -21,36 +21,38 @@ package org.opsli.common.constants;
* @author Parker
* @date 2020-09-16 17:42
*/
public interface OrderConstants {
public final class OrderConstants {
/** Util 加载顺序 */
int UTIL_ORDER = 140;
public static final int UTIL_ORDER = 140;
/** 限流器 */
int LIMITER_AOP_SORT = 149;
public static final int LIMITER_AOP_SORT = 149;
/** token */
int TOKEN_AOP_SORT = 150;
public static final int TOKEN_AOP_SORT = 150;
/** 请求加解密 */
int ENCRYPT_ADN_DECRYPT_AOP_SORT = 160;
public static final int ENCRYPT_ADN_DECRYPT_AOP_SORT = 160;
/** 热点数据加载顺序 */
int HOT_DATA_ORDER = 180;
public static final int HOT_DATA_ORDER = 180;
/** 参数非法验证顺序 */
int VERIFY_ARGS_AOP_SORT = 185;
public static final int VERIFY_ARGS_AOP_SORT = 185;
/** 搜索历史 */
int SEARCH_HIS_AOP_SORT = 186;
public static final int SEARCH_HIS_AOP_SORT = 186;
/** SQL 切面执行顺序 */
int SQL_ORDER = 190;
public static final int SQL_ORDER = 190;
/** 参数非法验证顺序 */
int LOG_ORDER = 200;
public static final int LOG_ORDER = 200;
/** Controller异常拦截顺序 */
int EXCEPTION_HANDLER_ORDER = 260;
public static final int EXCEPTION_HANDLER_ORDER = 260;
private OrderConstants(){}
}

@ -0,0 +1,28 @@
package org.opsli.common.constants;
/**
* Redis
* {}
* @author
* @date 2021/12/10 19:52
*/
public final class RedisConstants {
/** 字典名称 */
public static final String PREFIX_DICT_NAME = "hash#{}:dict:name:";
/** 字典值 VALUE */
public static final String PREFIX_DICT_VALUE = "hash#{}:dict:value:";
/** 菜单编号 */
public static final String PREFIX_MENU_CODE = "kv#{}:menu:code:";
/** 参数编号 */
public static final String PREFIX_OPTIONS_CODE = "kv#{}:options:code";
/** 用户搜索记录 */
public static final String PREFIX_HIS_USERNAME = "zset#{}:his:username:";
private RedisConstants(){}
}

@ -6,24 +6,26 @@ package org.opsli.common.constants;
* @author Parker
* @date 2020-09-16 17:42
*/
public interface SignConstants {
public final class SignConstants {
/** 用户账号 */
String ACCOUNT = "account";
public static final String ACCOUNT = "account";
/** 用户ID */
String USER_ID = "userId";
public static final String USER_ID = "userId";
/** 租户ID */
String TENANT_ID = "tenantId";
public static final String TENANT_ID = "tenantId";
/** 时间戳 */
String TIMESTAMP = "timestamp";
public static final String TIMESTAMP = "timestamp";
/** 其他信息 */
String OTHER = "other";
public static final String OTHER = "other";
/** 签名 类型 */
String TYPE = "type";
public static final String TYPE = "type";
private SignConstants(){}
}

@ -21,9 +21,11 @@ package org.opsli.common.constants;
* @author Parker
* @date 2020-09-16 17:42
*/
public interface TokenConstants {
public final class TokenConstants {
/** ACCESS_TOKEN */
String ACCESS_TOKEN = "X-Token";
public static final String ACCESS_TOKEN = "X-Token";
private TokenConstants(){}
}

@ -6,12 +6,13 @@ package org.opsli.common.constants;
* @author Parker
* @date 2020-09-16 17:42
*/
public interface TokenTypeConstants {
public final class TokenTypeConstants {
/** 系统内部TOKEN */
String TYPE_SYSTEM = "system";
public static final String TYPE_SYSTEM = "system";
/** 外部TOKEN */
String TYPE_EXTERNAL = "external";
public static final String TYPE_EXTERNAL = "external";
private TokenTypeConstants(){}
}

@ -21,13 +21,15 @@ package org.opsli.common.constants;
* @author Parker
* @date 202131015:50:16
*/
public interface TreeConstants {
public final class TreeConstants {
/** 是否包含子集 */
String HAS_CHILDREN = "hasChildren";
public static final String HAS_CHILDREN = "hasChildren";
/** 是否是叶子节点 */
String IS_LEAF = "isLeaf";
public static final String IS_LEAF = "isLeaf";
private TreeConstants(){}
}

@ -49,7 +49,7 @@ import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.base.entity.BaseEntity;
import org.opsli.core.base.entity.HasChildren;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg;
import org.opsli.core.security.shiro.realm.JwtRealm;

@ -13,11 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.local;
package org.opsli.core.cache;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
@ -739,6 +740,20 @@ public class CacheUtil {
key;
}
/**
* Key
* @param key Key
* @return String
*/
public static String formatKey(String key){
// 判断 工具类是否初始化完成
ThrowExceptionUtil.isThrowException(!IS_INIT,
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
return StrUtil.format(key, PREFIX_NAME);
}
/**
* key
* @param key Key

@ -0,0 +1,553 @@
package org.opsli.core.cache;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.Striped;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.function.Function;
/**
*
*
* 使
*
* Redis String Hash
*
* @author Parker
* @date 2021/12/10 12:39
*/
@Slf4j
public final class SecurityCache {
/** 热点数据缓存时间 秒 (6小时)*/
private static final int TTL_HOT_DATA_TIME = 21600;
/** 默认缓存时效 超出后自动清理 (分钟) */
private static final int DEFAULT_CACHE_TIME = 5;
/** 创建缓存对象 用于存储 空缓存 */
private static final Cache<String, CacheStatus> LFU_NULL_CACHE;
/** 缓存前缀 KV */
private static final String CACHE_PREFIX_KV = "kv#";
/** 缓存前缀 HASH */
private static final String CACHE_PREFIX_HASH = "hash#";
/** 默认锁时间 (秒) */
private static final int DEFAULT_LOCK_TIME = 10;
/** 锁 */
@SuppressWarnings("UnstableApiUsage")
private static final Striped<Lock> STRIPED = Striped.lock(1024);
static {
// 超时自动清理
LFU_NULL_CACHE = CacheBuilder
.newBuilder()
.expireAfterWrite(DEFAULT_CACHE_TIME, TimeUnit.MINUTES).build();
}
/**
*
* @param redisTemplate redisTemplate
* @param key
* @param callbackSource
* @return Object
*/
public static Object get(
final RedisTemplate<String, Object> redisTemplate,
final String key, final Function<String, Object> callbackSource) {
return get(redisTemplate, key, callbackSource, false);
}
/**
*
* @param redisTemplate redisTemplate
* @param key
* @param callbackSource
* @return Object
*/
public static Object get(
final RedisTemplate<String, Object> redisTemplate,
final String key, final Function<String, Object> callbackSource, final boolean isEden){
if(null == redisTemplate || null == key || null == callbackSource){
throw new RuntimeException("入参[redisTemplate,key,callbackSource]必填");
}
// 缓存 Object 对象
Object cache = getCacheObject(redisTemplate, key);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果还没查到缓存 则需要 穿透到 源数据查询
// 开启本地锁
@SuppressWarnings("UnstableApiUsage")
Lock lock = STRIPED.get(key);
try {
// 尝试获得锁
if(lock.tryLock(DEFAULT_LOCK_TIME, TimeUnit.SECONDS)){
// 梅开二度 如果查到后 直接返回
cache = getCacheObject(redisTemplate, key);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果这时候还没有 则查询源数据
cache = callbackSource.apply(key);
if(null == cache){
// 存储缓存状态
LFU_NULL_CACHE.put(key, CacheStatus.NOT_EXIST);
return null;
}
// 存入 Redis缓存
put(redisTemplate, key, cache, isEden);
}
}catch (Exception e){
log.error(e.getMessage(), e);
}finally {
lock.unlock();
}
return cache;
}
/**
*
* @param redisTemplate redisTemplate
* @param key
* @param val
*/
public static void put(
final RedisTemplate<String, Object> redisTemplate,
final String key, final Object val) {
put(redisTemplate, key, val, false);
}
/**
*
* @param redisTemplate redisTemplate
* @param key
* @param val
* @param isEden
*/
public static void put(
final RedisTemplate<String, Object> redisTemplate,
final String key, final Object val, final boolean isEden) {
if (null == redisTemplate || null == key || null == val) {
throw new RuntimeException("入参[redisTemplate,key,val]必填");
}
// 判断是否为永久存储
if(isEden) {
redisTemplate.opsForValue()
.set("kv#" + key, val);
}else{
// 随机缓存失效时间 防止缓存雪崩
// 范围在当前时效的 1.2 - 2倍
// 生成随机失效时间
int timeout = RandomUtil.randomInt(
Convert.toInt(TTL_HOT_DATA_TIME * 1.2),
Convert.toInt(TTL_HOT_DATA_TIME * 2)
);
redisTemplate.opsForValue()
.set(CACHE_PREFIX_KV + key, val, timeout, TimeUnit.SECONDS);
}
// 清除本地记录
LFU_NULL_CACHE.invalidate(key);
}
/**
* Hash
* @param redisTemplate redisTemplate
* @param key
* @param callbackSource
* @return Object
*/
public static Object hGet(
final RedisTemplate<String, Object> redisTemplate,
final String key, final String field, final Function<String, Object> callbackSource){
if(null == redisTemplate || null == key
|| null == field || null == callbackSource){
throw new RuntimeException("入参[redisTemplate,key,field,callbackSource]必填");
}
final String tempKey = key + "_" + field;
// 缓存 Object 对象
Object cache = getHashCacheObject(redisTemplate, key, field);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果还没查到缓存 则需要 穿透到 源数据查询
// 开启本地锁
@SuppressWarnings("UnstableApiUsage")
Lock lock = STRIPED.get(tempKey);
try {
// 尝试获得锁
if(lock.tryLock(DEFAULT_LOCK_TIME, TimeUnit.SECONDS)){
// 梅开二度 如果查到后 直接返回
cache = getHashCacheObject(redisTemplate, key, field);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果这时候还没有 则查询源数据
cache = callbackSource.apply(null);
if(null == cache){
// 存储缓存状态
LFU_NULL_CACHE.put(key, CacheStatus.NOT_EXIST);
return null;
}
// 存入 Redis缓存
hPut(redisTemplate, key, field, cache);
}
}catch (Exception e){
log.error(e.getMessage(), e);
}finally {
lock.unlock();
}
return cache;
}
/**
* Hash
* hash
* redis redis
*
* @param redisTemplate redisTemplate
* @param key
* @param callbackSource
* @return Object
*/
public static Map<String, Object> hGetAll(
final RedisTemplate<String, Object> redisTemplate, final String key,
final Function<String, Map<String, Object>> callbackSource){
if(null == redisTemplate || null == key
|| null == callbackSource){
throw new RuntimeException("入参[redisTemplate,key,callbackSource]必填");
}
// 缓存 Object 对象
Map<String, Object> cache = getAllHashCacheObject(redisTemplate, key, null);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果还没查到缓存 则需要 穿透到 源数据查询
// 开启本地锁
@SuppressWarnings("UnstableApiUsage")
Lock lock = STRIPED.get(key);
try {
// 尝试获得锁
if(lock.tryLock(DEFAULT_LOCK_TIME, TimeUnit.SECONDS)){
// 梅开二度 如果查到后 直接返回
cache = getAllHashCacheObject(redisTemplate, key, null);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果这时候还没有 则查询源数据
cache = callbackSource.apply(null);
if(null == cache){
// 存储缓存状态
LFU_NULL_CACHE.put(key, CacheStatus.NOT_EXIST);
return null;
}
// 存入 Redis缓存
hAllPut(redisTemplate, key, cache);
}
}catch (Exception e){
log.error(e.getMessage(), e);
}finally {
lock.unlock();
}
return cache;
}
/**
* Hash
*
* @param redisTemplate redisTemplate
* @param key
* @param callbackSourceCount
* @param callbackSource
* @return Object
*/
public static Map<String, Object> hGetAll(
final RedisTemplate<String, Object> redisTemplate, final String key,
final Function<String, Integer> callbackSourceCount, final Function<String, Map<String, Object>> callbackSource){
if(null == redisTemplate || null == key
|| null == callbackSourceCount || null == callbackSource){
throw new RuntimeException("入参[redisTemplate,key,callbackSourceCount,callbackSource]必填");
}
// 缓存 Object 对象
Map<String, Object> cache = getAllHashCacheObject(redisTemplate, key, callbackSourceCount);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果还没查到缓存 则需要 穿透到 源数据查询
// 开启本地锁
@SuppressWarnings("UnstableApiUsage")
Lock lock = STRIPED.get(key);
try {
// 尝试获得锁
if(lock.tryLock(DEFAULT_LOCK_TIME, TimeUnit.SECONDS)){
// 梅开二度 如果查到后 直接返回
cache = getAllHashCacheObject(redisTemplate, key, callbackSourceCount);
// 如果缓存不为空 则直接返回
if(null != cache){
return cache;
}
// 如果这时候还没有 则查询源数据
cache = callbackSource.apply(null);
if(null == cache){
// 存储缓存状态
LFU_NULL_CACHE.put(key, CacheStatus.NOT_EXIST);
return null;
}
// 存入 Redis缓存
hAllPut(redisTemplate, key, cache);
}
}catch (Exception e){
log.error(e.getMessage(), e);
}finally {
lock.unlock();
}
return cache;
}
/**
* Hash
* @param redisTemplate redisTemplate
* @param key
* @param cacheMap Map
*/
public static void hAllPut(
final RedisTemplate<String, Object> redisTemplate,
final String key, final Map<String, Object> cacheMap) {
if (null == redisTemplate || null == key
|| null == cacheMap) {
throw new RuntimeException("入参[redisTemplate,key,cacheMap]必填");
}
redisTemplate.opsForHash()
.putAll(CACHE_PREFIX_HASH + key, cacheMap);
// 清除本地记录
LFU_NULL_CACHE.invalidate(key);
}
/**
* Hash
* @param redisTemplate redisTemplate
* @param key
* @param field
* @param val
*/
public static void hPut(
final RedisTemplate<String, Object> redisTemplate,
final String key, final String field, final Object val) {
if (null == redisTemplate || null == key
|| null == field || null == val) {
throw new RuntimeException("入参[redisTemplate,key,field,val]必填");
}
redisTemplate.opsForHash()
.put(CACHE_PREFIX_HASH + key, field, val);
final String tempKey = key + "_" + field;
// 清除本地记录
LFU_NULL_CACHE.invalidate(tempKey);
}
/**
* Hash
* @param redisTemplate redisTemplate
* @param key
* @param field
* @return boolean
*/
public static boolean hDel(
final RedisTemplate<String, Object> redisTemplate,
final String key, final String field) {
if (null == redisTemplate || null == key) {
throw new RuntimeException("入参[redisTemplate,key,field]必填");
}
final String tempKey = key + "_" + field;
// 清除本地记录
LFU_NULL_CACHE.invalidate(tempKey);
// 判断是否存在
boolean isExist = Boolean.TRUE.equals(redisTemplate.opsForHash().hasKey(key, field));
if(!isExist){
// 如果不存在 直接返回删除成功
return true;
}
// 清除缓存
return 0 != redisTemplate.opsForHash().delete(key, field);
}
/**
*
* @param redisTemplate redisTemplate
* @param key
*/
public static boolean remove(
final RedisTemplate<String, Object> redisTemplate,
final String key) {
if (null == redisTemplate || null == key) {
throw new RuntimeException("入参[redisTemplate,key]必填");
}
// 清除本地记录
LFU_NULL_CACHE.invalidate(key);
// 清除缓存
redisTemplate.delete(key);
return true;
}
// =================================================================================================================
/**
* Redis
* @param redisTemplate redisTemplate
* @param key Key
* @return Object
*/
private static Object getCacheObject(RedisTemplate<String, Object> redisTemplate, String key) {
Object cache = null;
try {
// 先判断本地缓存是否存在 默认为存在(类似于伪布隆过滤)
CacheStatus cacheStatus = LFU_NULL_CACHE.get(key, () -> CacheStatus.EXIST);
// 如果不存在 则直接返回空
if(CacheStatus.NOT_EXIST.equals(cacheStatus)){
return null;
}
// 从 缓存回调查询数据
cache = redisTemplate.opsForValue().get(CACHE_PREFIX_KV + key);
}catch (Exception e){
log.error(e.getMessage(), e);
}
return cache;
}
/**
* Redis Hash
* @param redisTemplate redisTemplate
* @param key Key
* @return Object
*/
private static Object getHashCacheObject(RedisTemplate<String, Object> redisTemplate, String key, String field) {
Object cache = null;
try {
final String tempKey = key + "_" + field;
// 先判断本地缓存是否存在 默认为存在(类似于伪布隆过滤)
CacheStatus cacheStatus = LFU_NULL_CACHE.get(tempKey, () -> CacheStatus.EXIST);
// 如果不存在 则直接返回空
if(CacheStatus.NOT_EXIST.equals(cacheStatus)){
return null;
}
// 从 缓存回调查询数据
cache = redisTemplate.opsForHash().get(CACHE_PREFIX_HASH + key, field);
}catch (Exception e){
log.error(e.getMessage(), e);
}
return cache;
}
/**
* Redis Hash
* @param redisTemplate redisTemplate
* @param key key
* @param callbackSourceCount callbackSourceCount
* @return Object
*/
private static Map<String, Object> getAllHashCacheObject(RedisTemplate<String, Object> redisTemplate, String key,
final Function<String, Integer> callbackSourceCount) {
Map<String, Object> cache = null;
try {
// 先判断本地缓存是否存在 默认为存在(类似于伪布隆过滤)
CacheStatus cacheStatus = LFU_NULL_CACHE.get(key, () -> CacheStatus.EXIST);
// 如果不存在 则直接返回空
if(CacheStatus.NOT_EXIST.equals(cacheStatus)){
return null;
}
// 从 缓存回调查询数据
Map<Object, Object> entries = redisTemplate.opsForHash().entries(CACHE_PREFIX_HASH + key);
// 如果补偿器不为空 则进行补偿判断
if(null != callbackSourceCount){
// 判断数量不相等 则返回一个空 重新查询处理缓存
Integer count = callbackSourceCount.apply(key);
if(count != entries.size()){
return null;
}
}
if(MapUtil.isNotEmpty(entries)){
cache = new HashMap<>();
for (Map.Entry<Object, Object> entry : entries.entrySet()) {
cache.put(String.valueOf(entry.getKey()), entry.getValue());
}
}
}catch (Exception e){
log.error(e.getMessage(), e);
}
return cache;
}
/**
*
*/
private enum CacheStatus{
/** 存在(默认) */
EXIST,
/** 不存在 */
NOT_EXIST
}
/**
*
*/
private SecurityCache(){}
}

@ -1,38 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.opsli.core.cache.pushsub.enums.PushSubType;
/**
* Entity
*
* @author Parker
* @date 2020-09-18 00:01
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CacheDataEntity {
/** key */
private String key;
}

@ -1,34 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.enums;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
public enum CacheHandleType {
/** 更新 */
UPDATE,
/** 删除 */
DELETE,
;
}

@ -1,34 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.enums;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
public enum DictModelType {
/** 对象 */
OBJECT,
/** 集合 */
COLLECTION,
;
}

@ -1,67 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.enums;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
public enum MsgArgsType {
/** 字典模型 */
DICT_MODEL,
/** 字典模型-集合 */
DICT_MODELS,
/** 字典模型-传输类型 */
DICT_MODEL_TYPE,
/** 字典操作类型 */
DICT_TYPE,
/** 用户ID */
USER_ID,
/** 用户名 */
USER_USERNAME,
/** 用户数据类型 */
USER_MODEL_TYPE,
/** 用户数据*/
USER_MODEL_DATA,
/** 组织 用户ID */
ORG_USER_ID,
/** 组织 用户数据 */
ORG_USER_DATA,
/** 租户ID */
TENANT_ID,
/** 租户数据 */
TENANT_DATA,
/** 参数编号 */
OPTION_CODE,
/** 参数数据*/
OPTION_MODEL_DATA,
/** 缓存数据Key */
CACHE_DATA_KEY,
/** 缓存数据Value */
CACHE_DATA_VALUE,
/** 缓存数据Type */
CACHE_DATA_TYPE,
;
}

@ -1,50 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.enums;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
public enum PushSubType {
/** 字典类型 */
DICT,
/** 用户数据 */
USER,
/** 菜单数据 */
MENU,
/** 组织数据 */
ORG,
/** 租户 */
TENANT,
/** 系统数据 */
OPTION,
/** 热点数据 */
HOT_DATA,
;
}

@ -1,37 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.enums;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
public enum UserModelType {
/** 用户模型 */
USER_MODEL,
/** 用户角色集合模型 */
USER_ROLES_MODEL,
/** 用户权限集合模型 */
USER_PERMS_MODEL,
/** 用户菜单集合模型 */
USER_MENU_MODEL,
;
}

@ -1,109 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.constants.CacheConstants;
import org.opsli.common.constants.DictConstants;
import org.opsli.common.enums.CacheType;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.CacheHandleType;
import org.opsli.core.cache.pushsub.enums.DictModelType;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
@Slf4j
public class DictHandler implements RedisPushSubHandler{
@Autowired
private EhCachePlugin ehCachePlugin;
@Override
public PushSubType getType() {
return PushSubType.DICT;
}
@Override
public void handler(JSONObject msgJson) {
DictModelType dictModelType = DictModelType.valueOf((String) msgJson.get(MsgArgsType.DICT_MODEL_TYPE.toString()));
CacheHandleType type = CacheHandleType.valueOf((String) msgJson.get(MsgArgsType.DICT_TYPE.toString()));
if(DictModelType.COLLECTION == dictModelType){
Object dictListObj = msgJson.get(MsgArgsType.DICT_MODELS.toString());
List<DictWrapper> dictWrappers = Convert.toList(DictWrapper.class, dictListObj);
if(CollUtil.isNotEmpty(dictWrappers)){
for (DictWrapper dictWrapper : dictWrappers) {
this.handler(dictWrapper, type);
}
}
} else if(DictModelType.OBJECT == dictModelType){
JSONObject jsonObject = msgJson.getJSONObject(MsgArgsType.DICT_MODEL.toString());
if(jsonObject == null){
return;
}
DictWrapper dictWrapperModel = jsonObject.toJavaObject(DictWrapper.class);
this.handler(dictWrapperModel, type);
}
}
/**
* -
* @param dictWrapperModel model
* @param type
*/
private void handler(DictWrapper dictWrapperModel, CacheHandleType type){
// 解析 key
String ehKeyByName = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_NAME +
dictWrapperModel.getTypeCode() + ":" + dictWrapperModel.getDictName());
String ehKeyByValue = CacheUtil.handleKey(CacheType.EDEN_HASH, DictConstants.CACHE_PREFIX_VALUE +
dictWrapperModel.getTypeCode() + ":" + dictWrapperModel.getDictValue());
// 缓存更新
if(CacheHandleType.UPDATE == type){
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, ehKeyByName);
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, ehKeyByValue);
// 统一转换为 JSONObject
String jsonStr = JSONObject.toJSONString(dictWrapperModel.getModel());
JSONObject value = JSONObject.parseObject(jsonStr);
ehCachePlugin.put(CacheConstants.EHCACHE_SPACE, ehKeyByName, value);
ehCachePlugin.put(CacheConstants.EHCACHE_SPACE, ehKeyByValue, value);
}
// 缓存删除
else if(CacheHandleType.DELETE == type){
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, ehKeyByName);
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, ehKeyByValue);
}
}
}

@ -1,68 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.CacheHandleType;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
@Slf4j
public class HotDataHandler implements RedisPushSubHandler{
@Autowired
private EhCachePlugin ehCachePlugin;
@Override
public PushSubType getType() {
return PushSubType.HOT_DATA;
}
@Override
public void handler(JSONObject msgJson) {
String key = (String) msgJson.get(MsgArgsType.CACHE_DATA_KEY.toString());
Object value = msgJson.get(MsgArgsType.CACHE_DATA_VALUE.toString());
CacheHandleType type = CacheHandleType.valueOf((String )msgJson.get(MsgArgsType.CACHE_DATA_TYPE.toString()));
if(StringUtils.isEmpty(key)){
return;
}
// 拼装缓存key
String cacheName = CacheUtil.handleKey(CacheConstants.HOT_DATA_PREFIX +":"+ key);
if(CacheHandleType.UPDATE == type){
ehCachePlugin.put(CacheConstants.EHCACHE_SPACE, cacheName, value);
}
// 缓存删除
else if(CacheHandleType.DELETE == type){
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheName);
}
}
}

@ -1,76 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.utils.OptionsUtil;
import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
@Slf4j
public class OptionHandler implements RedisPushSubHandler{
@Autowired
private EhCachePlugin ehCachePlugin;
@Override
public PushSubType getType() {
return PushSubType.OPTION;
}
@Override
public void handler(JSONObject msgJson) {
// 系统参数刷新
this.optionHandler(msgJson);
}
/**
*
* @param msgJson Json
*/
private void optionHandler(JSONObject msgJson){
JSONObject data = msgJson.getJSONObject(MsgArgsType.OPTION_MODEL_DATA.toString());
// 数据为空则不执行
if(data == null){
return;
}
// 获得参数编号
String optionCode = (String) msgJson.get(MsgArgsType.OPTION_CODE.toString());
if(StringUtils.isEmpty(optionCode)){
return;
}
String cacheKey = CacheUtil.handleKey(OptionsUtil.PREFIX_CODE + optionCode);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey);
}
}

@ -1,77 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.utils.OrgUtil;
import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
@Slf4j
public class OrgHandler implements RedisPushSubHandler{
@Autowired
private EhCachePlugin ehCachePlugin;
@Override
public PushSubType getType() {
return PushSubType.ORG;
}
@Override
public void handler(JSONObject msgJson) {
// 用户刷新
this.orgHandler(msgJson);
}
/**
*
* @param msgJson Json
*/
private void orgHandler(JSONObject msgJson){
JSONObject data = msgJson.getJSONObject(MsgArgsType.ORG_USER_DATA.toString());
// 数据为空则不执行
if(data == null){
return;
}
// 获得用户ID
String userId = (String) msgJson.get(MsgArgsType.ORG_USER_ID.toString());
if(StringUtils.isEmpty(userId)){
return;
}
String cacheKey = CacheUtil.handleKey(UserUtil.PREFIX_ID_ORGS + userId);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey);
}
}

@ -1,41 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONObject;
import org.opsli.core.cache.pushsub.enums.PushSubType;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
public interface RedisPushSubHandler {
/**
*
* @return
*/
PushSubType getType();
/**
*
* @param msgJson Json
*/
void handler(JSONObject msgJson);
}

@ -1,76 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.utils.TenantUtil;
import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
@Slf4j
public class TenantHandler implements RedisPushSubHandler{
@Autowired
private EhCachePlugin ehCachePlugin;
@Override
public PushSubType getType() {
return PushSubType.TENANT;
}
@Override
public void handler(JSONObject msgJson) {
// 用户刷新
this.orgHandler(msgJson);
}
/**
*
* @param msgJson Json
*/
private void orgHandler(JSONObject msgJson){
JSONObject data = msgJson.getJSONObject(MsgArgsType.TENANT_DATA.toString());
// 数据为空则不执行
if(data == null){
return;
}
// 获得租户ID
String tenantId = (String) msgJson.get(MsgArgsType.TENANT_ID.toString());
if(StringUtils.isEmpty(tenantId)){
return;
}
String cacheKey = CacheUtil.handleKey(TenantUtil.PREFIX_CODE + tenantId);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey);
}
}

@ -1,168 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.enums.UserModelType;
import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
*
* @author Parker
* @date 2020-09-16
*/
@Slf4j
public class UserHandler implements RedisPushSubHandler{
@Autowired
private EhCachePlugin ehCachePlugin;
@Override
public PushSubType getType() {
return PushSubType.USER;
}
@Override
public void handler(JSONObject msgJson) {
UserModelType userModelType = UserModelType.valueOf((String)
msgJson.get(MsgArgsType.USER_MODEL_TYPE.toString()));
// 用户刷新
if(UserModelType.USER_MODEL == userModelType){
this.userHandler(msgJson);
}
// 用户角色刷新
else if(UserModelType.USER_ROLES_MODEL == userModelType){
this.userRolesHandler(msgJson);
}
// 用户权限刷新
else if(UserModelType.USER_PERMS_MODEL == userModelType){
this.userPermsHandler(msgJson);
}
// 用户菜单刷新
else if(UserModelType.USER_MENU_MODEL == userModelType){
this.userMenusHandler(msgJson);
}
}
/**
*
* @param msgJson Json
*/
private void userHandler(JSONObject msgJson){
JSONObject data = msgJson.getJSONObject(MsgArgsType.USER_MODEL_DATA.toString());
// 数据为空则不执行
if(data == null){
return;
}
// 获得用户ID 和 用户名
String userId = (String) msgJson.get(MsgArgsType.USER_ID.toString());
String username = (String) msgJson.get(MsgArgsType.USER_USERNAME.toString());
if(StringUtils.isEmpty(userId) || StringUtils.isEmpty(username) ){
return;
}
String cacheKeyById = CacheUtil.handleKey(UserUtil.PREFIX_ID + userId);
String cacheKeyByName = CacheUtil.handleKey(UserUtil.PREFIX_USERNAME + username);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKeyById);
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKeyByName);
}
/**
*
* @param msgJson Json
*/
private void userRolesHandler(JSONObject msgJson){
JSONArray dataArray = msgJson.getJSONArray(MsgArgsType.USER_MODEL_DATA.toString());
// 数据为空则不执行
if(dataArray == null || dataArray.isEmpty()){
return;
}
// 获得用户ID
String userId = (String) msgJson.get(MsgArgsType.USER_ID.toString());
if(StringUtils.isEmpty(userId)){
return;
}
String cacheKey = CacheUtil.handleKey(UserUtil.PREFIX_ID_ROLES + userId);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey);
}
/**
*
* @param msgJson Json
*/
private void userPermsHandler(JSONObject msgJson){
JSONArray dataArray = msgJson.getJSONArray(MsgArgsType.USER_MODEL_DATA.toString());
// 数据为空则不执行
if(dataArray == null || dataArray.isEmpty()){
return;
}
// 获得用户ID
String userId = (String) msgJson.get(MsgArgsType.USER_ID.toString());
if(StringUtils.isEmpty(userId)){
return;
}
String cacheKey = CacheUtil.handleKey(UserUtil.PREFIX_ID_PERMISSIONS + userId);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey);
}
/**
*
* @param msgJson Json
*/
private void userMenusHandler(JSONObject msgJson){
JSONArray dataArray = msgJson.getJSONArray(MsgArgsType.USER_MODEL_DATA.toString());
// 数据为空则不执行
if(dataArray == null || dataArray.isEmpty()){
return;
}
// 获得用户ID
String userId = (String) msgJson.get(MsgArgsType.USER_ID.toString());
if(StringUtils.isEmpty(userId)){
return;
}
String cacheKey = CacheUtil.handleKey(UserUtil.PREFIX_ID_MENUS + userId);
// 先删除
ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey);
}
}

@ -1,64 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.core.cache.pushsub.entity.CacheDataEntity;
import org.opsli.core.cache.pushsub.enums.CacheHandleType;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
/**
*
*
* @author Parker
* @date 2020-09-15
*/
@Data
@Accessors(chain = true)
public final class CacheDataMsgFactory extends BaseSubMessage{
/** 通道 */
private static final String CHANNEL = RedisPushSubReceiver.BASE_CHANNEL + RedisPushSubReceiver.CHANNEL;
private CacheDataMsgFactory(){}
/**
*
* @param cacheDataEntity
* @param value
* @param cacheHandleType
* @return
*/
public static BaseSubMessage createMsg(CacheDataEntity cacheDataEntity, Object value,
CacheHandleType cacheHandleType){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.CACHE_DATA_KEY.toString(),cacheDataEntity.getKey());
jsonObj.put(MsgArgsType.CACHE_DATA_VALUE.toString(),value);
jsonObj.put(MsgArgsType.CACHE_DATA_TYPE.toString(), cacheHandleType.toString());
// 热点数据 - 系统数据
baseSubMessage.build(CHANNEL, PushSubType.HOT_DATA.toString(), jsonObj);
return baseSubMessage;
}
}

@ -1,83 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.core.cache.pushsub.enums.CacheHandleType;
import org.opsli.core.cache.pushsub.enums.DictModelType;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
import java.util.List;
/**
*
*
* @author Parker
* @date 2020-09-15
*/
@Data
@Accessors(chain = true)
public final class DictMsgFactory extends BaseSubMessage{
/** 通道 */
private static final String CHANNEL = RedisPushSubReceiver.BASE_CHANNEL+RedisPushSubReceiver.CHANNEL;
private DictMsgFactory(){}
/**
*
* @param dictWrapperModel
* @param cacheHandleType
* @return
*/
public static BaseSubMessage createMsg(DictWrapper dictWrapperModel, CacheHandleType cacheHandleType){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.DICT_MODEL.toString(), dictWrapperModel);
jsonObj.put(MsgArgsType.DICT_MODEL_TYPE.toString(), DictModelType.OBJECT);
jsonObj.put(MsgArgsType.DICT_TYPE.toString(), cacheHandleType.toString());
// DICT 字典
baseSubMessage.build(CHANNEL,PushSubType.DICT.toString(),jsonObj);
return baseSubMessage;
}
/**
*
* @param dictWrapperModels
* @param cacheHandleType
* @return
*/
public static BaseSubMessage createMsg(List<DictWrapper> dictWrapperModels, CacheHandleType cacheHandleType){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.DICT_MODELS.toString(), dictWrapperModels);
jsonObj.put(MsgArgsType.DICT_MODEL_TYPE.toString(), DictModelType.COLLECTION);
jsonObj.put(MsgArgsType.DICT_TYPE.toString(), cacheHandleType.toString());
// DICT 字典
baseSubMessage.build(CHANNEL,PushSubType.DICT.toString(),jsonObj);
return baseSubMessage;
}
}

@ -1,61 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.options.OptionsModel;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
/**
*
*
* @author Parker
* @date 2020-09-15
*/
@Data
@Accessors(chain = true)
public final class OptionMsgFactory extends BaseSubMessage{
/** 通道 */
private static final String CHANNEL = RedisPushSubReceiver.BASE_CHANNEL+RedisPushSubReceiver.CHANNEL;
private OptionMsgFactory(){}
/**
* -
* @param optionsModel
* @return
*/
public static BaseSubMessage createOptionMsg(OptionsModel optionsModel){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.OPTION_CODE.toString(), optionsModel.getOptionCode());
jsonObj.put(MsgArgsType.OPTION_MODEL_DATA.toString(), optionsModel);
// 参数
baseSubMessage.build(CHANNEL,PushSubType.OPTION.toString(),jsonObj);
return baseSubMessage;
}
}

@ -1,60 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.api.wrapper.system.user.UserOrgRefWebModel;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
/**
*
*
* @author Parker
* @date 2020-09-15
*/
@Data
@Accessors(chain = true)
public final class OrgMsgFactory extends BaseSubMessage{
/** 通道 */
private static final String CHANNEL = RedisPushSubReceiver.BASE_CHANNEL+RedisPushSubReceiver.CHANNEL;
private OrgMsgFactory(){}
/**
* -
* @param orgRefModel
* @return
*/
public static BaseSubMessage createOrgMsg(UserOrgRefWebModel orgRefModel){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.ORG_USER_ID.toString(), orgRefModel.getUserId());
jsonObj.put(MsgArgsType.ORG_USER_DATA.toString(), orgRefModel);
// 组织
baseSubMessage.build(CHANNEL,PushSubType.ORG.toString(),jsonObj);
return baseSubMessage;
}
}

@ -1,60 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.api.wrapper.system.tenant.TenantModel;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
/**
*
*
* @author Parker
* @date 2020-09-15
*/
@Data
@Accessors(chain = true)
public final class TenantMsgFactory extends BaseSubMessage{
/** 通道 */
private static final String CHANNEL = RedisPushSubReceiver.BASE_CHANNEL+RedisPushSubReceiver.CHANNEL;
private TenantMsgFactory(){}
/**
* -
* @param tenantModel
* @return
*/
public static BaseSubMessage createTenantMsg(TenantModel tenantModel){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.TENANT_ID.toString(), tenantModel.getId());
jsonObj.put(MsgArgsType.TENANT_DATA.toString(), tenantModel);
// 租户
baseSubMessage.build(CHANNEL,PushSubType.TENANT.toString(),jsonObj);
return baseSubMessage;
}
}

@ -1,122 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.enums.UserModelType;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
import java.util.List;
/**
*
*
* @author Parker
* @date 2020-09-15
*/
@Data
@Accessors(chain = true)
public final class UserMsgFactory extends BaseSubMessage{
/** 通道 */
private static final String CHANNEL = RedisPushSubReceiver.BASE_CHANNEL+RedisPushSubReceiver.CHANNEL;
private UserMsgFactory(){}
/**
* -
* @param userModel
* @return
*/
public static BaseSubMessage createUserMsg(UserModel userModel){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.USER_ID.toString(), userModel.getId());
jsonObj.put(MsgArgsType.USER_USERNAME.toString(), userModel.getUsername());
jsonObj.put(MsgArgsType.USER_MODEL_TYPE.toString(), UserModelType.USER_MODEL.toString());
jsonObj.put(MsgArgsType.USER_MODEL_DATA.toString(), userModel);
// 用户
baseSubMessage.build(CHANNEL,PushSubType.USER.toString(),jsonObj);
return baseSubMessage;
}
/**
* -
* @param userId ID
* @param roles
* @return
*/
public static BaseSubMessage createUserRolesMsg(String userId, List<String> roles){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.USER_ID.toString(), userId);
jsonObj.put(MsgArgsType.USER_MODEL_TYPE.toString(), UserModelType.USER_ROLES_MODEL.toString());
jsonObj.put(MsgArgsType.USER_MODEL_DATA.toString(), roles);
// 用户
baseSubMessage.build(CHANNEL,PushSubType.USER.toString(),jsonObj);
return baseSubMessage;
}
/**
* -
* @param userId ID
* @param perms
* @return
*/
public static BaseSubMessage createUserPermsMsg(String userId, List<String> perms){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.USER_ID.toString(), userId);
jsonObj.put(MsgArgsType.USER_MODEL_TYPE.toString(), UserModelType.USER_PERMS_MODEL.toString());
jsonObj.put(MsgArgsType.USER_MODEL_DATA.toString(), perms);
// 用户
baseSubMessage.build(CHANNEL,PushSubType.USER.toString(),jsonObj);
return baseSubMessage;
}
/**
* -
* @param userId ID
* @param menus
* @return
*/
public static BaseSubMessage createUserMenusMsg(String userId, List<MenuModel> menus){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.USER_ID.toString(), userId);
jsonObj.put(MsgArgsType.USER_MODEL_TYPE.toString(), UserModelType.USER_MENU_MODEL.toString());
jsonObj.put(MsgArgsType.USER_MODEL_DATA.toString(), menus);
// 用户
baseSubMessage.build(CHANNEL,PushSubType.USER.toString(),jsonObj);
return baseSubMessage;
}
}

@ -1,132 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.cache.pushsub.receiver;
import cn.hutool.core.util.ClassUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.opsli.common.enums.SystemInfo;
import org.opsli.core.cache.pushsub.enums.PushSubType;
import org.opsli.core.cache.pushsub.handler.RedisPushSubHandler;
import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
import org.opsli.plugins.redis.pushsub.receiver.BaseReceiver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Modifier;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Redis
*
*
* @author Parker
* @date 2020-09-15
*/
@Slf4j
@Configuration
public class RedisPushSubReceiver extends BaseReceiver {
/** Spring Bean 前缀 */
public static final String SPRING_PREFIX = "redisPushSub_";
/** 监听信道 */
public static final String CHANNEL = "opsli";
/** 处理方法集合 */
private static final ConcurrentMap<PushSubType, RedisPushSubHandler> HANDLER_MAP = new ConcurrentHashMap<>();
@Autowired
private AutowireCapableBeanFactory beanFactory;
@Autowired
private DefaultListableBeanFactory defaultListableBeanFactory;
public RedisPushSubReceiver() {
super(CHANNEL);
}
@Bean
public void initRedisPushSubHandler(){
// 拿到state包下 实现了 SystemEventState 接口的,所有子类
Set<Class<?>> clazzSet = ClassUtil.scanPackageBySuper(
RedisPushSubHandler.class.getPackage().getName(),
RedisPushSubHandler.class
);
for (Class<?> aClass : clazzSet) {
// 位运算 去除抽象类
if((aClass.getModifiers() & Modifier.ABSTRACT) != 0){
continue;
}
try {
Object obj = aClass.newInstance();
RedisPushSubHandler handler = (RedisPushSubHandler) obj;
// 加入集合
HANDLER_MAP.put(handler.getType(),handler);
//将new出的对象放入Spring容器中
defaultListableBeanFactory.registerSingleton(SPRING_PREFIX+aClass.getSimpleName(), obj);
//自动注入依赖
beanFactory.autowireBean(obj);
} catch (Exception e){
log.error(CoreMsg.REDIS_EXCEPTION_PUSH_SUB.getMessage());
}
}
}
@Override
public void receiveMessage(String msg) {
if(msg == null || "".equals(msg)){
return;
}
long beginTime = System.currentTimeMillis();
// 替换 转意符
String replaceAll = msg.replaceAll("\\\\", "");
String substring = replaceAll.substring(1, replaceAll.length() - 1);
JSONObject msgJson = JSONObject.parseObject(substring);
String type = (String) msgJson.get(BaseSubMessage.BASE_TYPE);
String identifier = (String) msgJson.get(BaseSubMessage.BASE_ID);
// 本机不广播
if(SystemInfo.INSTANCE.getSystemID().equals(identifier)){
return;
}
PushSubType pt = PushSubType.valueOf(type);
RedisPushSubHandler redisPushSubHandler = HANDLER_MAP.get(pt);
if(redisPushSubHandler == null){
return;
}
redisPushSubHandler.handler(msgJson);
long endTime = System.currentTimeMillis();
log.info("订阅节点更新缓存 耗时(毫秒):{}",(endTime-beginTime));
}
}

@ -29,7 +29,7 @@ import org.opsli.common.annotation.hotdata.EnableHotData;
import org.opsli.common.annotation.hotdata.HotDataDel;
import org.opsli.common.annotation.hotdata.HotDataPut;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.cache.pushsub.entity.CacheDataEntity;
import org.opsli.core.cache.pushsub.enums.CacheHandleType;
import org.opsli.core.cache.pushsub.msgs.CacheDataMsgFactory;

@ -23,7 +23,7 @@ import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.exception.TokenException;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg;
import org.opsli.plugins.redis.RedisPlugin;

@ -19,19 +19,20 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.dict.DictDetailApi;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.constants.DictConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.common.constants.RedisConstants;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.cache.SecurityCache;
import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
@ -56,6 +57,8 @@ public class DictUtil {
/** 字典Service */
private static DictDetailApi dictDetailApi;
/** Redis */
private static RedisTemplate<String, Object> redisTemplate;
/**
*
@ -70,75 +73,30 @@ public class DictUtil {
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 缓存Key
String cacheKey = DictConstants.CACHE_PREFIX_VALUE + typeCode;
// 缓存Key + VALUE
String cacheKeyVal = cacheKey + ":" + dictValue;
// 字典名称
String dictName = null;
DictDetailModel cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
dictValue);
// 如果缓存有值 直接返回
if (cacheModel != null &&
StringUtils.isNotEmpty(cacheModel.getDictName())){
return cacheModel.getDictName();
}
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_DICT_VALUE + typeCode);
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKeyVal);
if(hasNilFlag){
return defaultVal;
}
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKeyVal)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
Object cache = SecurityCache.hGet(redisTemplate, cacheKey, dictValue, (k) -> {
// 查询数据库 并保存到缓存内
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if (!resultVo.isSuccess()) {
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
dictValue);
// 如果缓存有值 直接返回
if (cacheModel != null &&
StringUtils.isNotEmpty(cacheModel.getDictName())){
return cacheModel.getDictName();
}
// 查询数据库 并保存到缓存内
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if(resultVo.isSuccess()){
List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) {
if(model.getDictValue().equals(dictValue)){
// 保存至缓存
DictWrapper dictWrapper = DictUtil.putByModel(model);
// 缓存名
dictName = dictWrapper.getDictName();
break;
}
List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) {
if (model.getDictValue().equals(dictValue)) {
// 转化Model
return DictUtil.formatModel(model);
}
}
return null;
});
}catch (Exception e){
log.error(e.getMessage(),e);
if(null == cache){
return defaultVal;
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKeyVal);
}
// 如果名称还是 为空 则赋默认值
if(StringUtils.isEmpty(dictName)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(cacheKeyVal);
dictName = defaultVal;
}
return dictName;
DictWrapper dictWrapper = Convert.convert(DictWrapper.class, cache);
return dictWrapper.getDictName();
}
/**
@ -153,75 +111,32 @@ public class DictUtil {
ThrowExceptionUtil.isThrowException(!IS_INIT,
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 缓存Key
String cacheKey = DictConstants.CACHE_PREFIX_NAME + typeCode;
// 缓存Key + VALUE
String cacheKeyVal = cacheKey + ":" + dictName;
// 字典值
String dictValue = null;
DictDetailModel cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
dictName);
// 如果缓存有值 直接返回
if (cacheModel != null &&
StringUtils.isNotEmpty(cacheModel.getDictValue())){
return cacheModel.getDictValue();
}
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKeyVal);
if(hasNilFlag){
return defaultVal;
}
// 缓存Key
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_DICT_NAME + typeCode);
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKeyVal)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
Object cache = SecurityCache.hGet(redisTemplate, cacheKey, dictName, (k) -> {
// 查询数据库 并保存到缓存内
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if (!resultVo.isSuccess()) {
return null;
}
cacheModel = CacheUtil.getHash(DictDetailModel.class, cacheKey,
dictName);
// 如果缓存有值 直接返回
if (cacheModel != null &&
StringUtils.isNotEmpty(cacheModel.getDictValue())){
return cacheModel.getDictValue();
}
// 查询数据库 并保存到缓存内
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if(resultVo.isSuccess()){
List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) {
if(model.getDictName().equals(dictName)){
// 保存至缓存
DictWrapper dictWrapper = DictUtil.putByModel(model);
// 值
dictValue = dictWrapper.getDictValue();
break;
}
List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) {
if (model.getDictName().equals(dictName)) {
// 转化Model
return DictUtil.formatModel(model);
}
}
return null;
});
}catch (Exception e){
log.error(e.getMessage(),e);
if(null == cache){
return defaultVal;
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKeyVal);
}
// 如果值还是 为空 则赋默认值
if(StringUtils.isEmpty(dictValue)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(cacheKeyVal);
dictValue = defaultVal;
}
return dictValue;
DictWrapper dictWrapper = Convert.convert(DictWrapper.class, cache);
return dictWrapper.getDictValue();
}
/**
@ -235,134 +150,36 @@ public class DictUtil {
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 缓存Key
String cacheKey = DictConstants.CACHE_PREFIX_NAME + typeCode;
// 处理集合数据
List<DictWrapper> dictWrapperModels = handleDictList(
CacheUtil.getHashAll(cacheKey), typeCode);
if(CollUtil.isNotEmpty(dictWrapperModels)){
return sortDictWrappers(dictWrapperModels);
}
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return sortDictWrappers(dictWrapperModels);
}
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKey)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return sortDictWrappers(dictWrapperModels);
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
// 处理集合数据
dictWrapperModels = handleDictList(
CacheUtil.getHashAll(cacheKey), typeCode);
if(CollUtil.isNotEmpty(dictWrapperModels)){
return sortDictWrappers(dictWrapperModels);
}
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_DICT_VALUE + typeCode);
Map<String, Object> dictCacheMap = SecurityCache.hGetAll(redisTemplate, cacheKey, (k) -> {
// 查询数据库 并保存到缓存内
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if(resultVo.isSuccess()){
List<DictDetailModel> dictDetailModels = resultVo.getData();
// 处理数据库查询数据
if(CollUtil.isNotEmpty(dictDetailModels)){
dictWrapperModels = Lists.newArrayListWithCapacity(dictDetailModels.size());
for (DictDetailModel model : dictDetailModels) {
// 保存至缓存
DictWrapper dictWrapper = DictUtil.putByModel(model);
dictWrapperModels.add(dictWrapper);
}
return sortDictWrappers(dictWrapperModels);
}
if (!resultVo.isSuccess()) {
return null;
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKey);
}
List<DictDetailModel> dictDetailModels = resultVo.getData();
Map<String, Object> dictMap = Maps.newHashMapWithExpectedSize(dictDetailModels.size());
for (DictDetailModel model : dictDetailModels) {
dictMap.put(model.getDictValue(), model);
}
return dictMap;
});
// 如果值还是 为空 则赋默认值
if(CollUtil.isEmpty(dictWrapperModels)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(cacheKey);
}
List<DictWrapper> dictWrappers = handleDictList(dictCacheMap, typeCode);
// 排序
return sortDictWrappers(dictWrapperModels);
return sortDictWrappers(dictWrappers);
}
/**
*
* @param dictWrapperModels Model
* @return List
*/
private static List<DictWrapper> sortDictWrappers(List<DictWrapper> dictWrapperModels) {
// 非法判读
if(dictWrapperModels == null){
return null;
}
ListUtil.sort(dictWrapperModels, (o1, o2) -> {
int oInt1 = Integer.MAX_VALUE;
int oInt2 = Integer.MAX_VALUE;
if(o1 != null && o1.getModel() != null){
oInt1 = o1.getModel().getSortNo()==null?oInt1:o1.getModel().getSortNo();
}
if(o2 != null && o2.getModel() != null){
oInt2 = o2.getModel().getSortNo()==null?oInt2:o2.getModel().getSortNo();
}
return Integer.compare(oInt1, oInt2);
});
return dictWrapperModels;
}
// ===============
/**
*
* @param model
*/
private static DictWrapper putByModel(DictDetailModel model){
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
// 保存至缓存
DictUtil.put(dictWrapperModel);
return dictWrapperModel;
}
/**
*
* @param model
*/
public static void put(DictWrapper model){
// 判断 工具类是否初始化完成
ThrowExceptionUtil.isThrowException(!IS_INIT,
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 清除缓存
DictUtil.del(model);
CacheUtil.putHash(DictConstants.CACHE_PREFIX_NAME + model.getTypeCode(),
model.getDictName(), model.getModel());
CacheUtil.putHash(DictConstants.CACHE_PREFIX_VALUE + model.getTypeCode(),
model.getDictValue(), model.getModel());
}
/**
*
@ -378,60 +195,29 @@ public class DictUtil {
return true;
}
boolean hasNilFlagByName = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_NAME +
model.getTypeCode() + ":" + model.getDictName());
boolean hasNilFlagByValue = CacheUtil.hasNilFlag(DictConstants.CACHE_PREFIX_VALUE +
model.getTypeCode() + ":" + model.getDictValue());
// 缓存Key
String cacheKeyByValue = CacheUtil.formatKey(
RedisConstants.PREFIX_DICT_VALUE + model.getTypeCode());
// 缓存Key
String cacheKeyByName = CacheUtil.formatKey(
RedisConstants.PREFIX_DICT_NAME + model.getTypeCode());
DictWrapper dictByName = CacheUtil.getHash(DictWrapper.class,
DictConstants.CACHE_PREFIX_NAME + model.getTypeCode(),
model.getDictName());
DictWrapper dictByValue = CacheUtil.getHash(DictWrapper.class,
DictConstants.CACHE_PREFIX_VALUE + model.getTypeCode(),
model.getDictValue());
// 计数器
int count = 0;
if (hasNilFlagByName){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delNilFlag(DictConstants.CACHE_PREFIX_NAME +
model.getTypeCode() + ":" + model.getDictName());
int count = 2;
{
boolean tmp = SecurityCache.hDel(redisTemplate, cacheKeyByValue, model.getDictValue());
if(tmp){
count--;
}
}
if (hasNilFlagByValue){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delNilFlag(DictConstants.CACHE_PREFIX_VALUE +
model.getTypeCode() + ":" + model.getDictValue());
{
boolean tmp = SecurityCache.hDel(redisTemplate, cacheKeyByName, model.getDictName());
if(tmp){
count--;
}
}
if (dictByName != null){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delHash(DictConstants.CACHE_PREFIX_NAME +
model.getTypeCode(), model.getDictName());
if(tmp){
count--;
}
}
if (dictByValue != null){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delHash(DictConstants.CACHE_PREFIX_VALUE +
model.getTypeCode(), model.getDictValue());
if(tmp){
count--;
}
}
return count == 0;
}
@ -450,10 +236,24 @@ public class DictUtil {
return true;
}
// 缓存Key
String cacheKeyByValue = CacheUtil.formatKey(
RedisConstants.PREFIX_DICT_VALUE + typeCode);
// 缓存Key
String cacheKeyByName = CacheUtil.formatKey(
RedisConstants.PREFIX_DICT_NAME + typeCode);
// 计数器
int count = dictWrapperList.size();
for (DictWrapper dictWrapperModel : dictWrapperList) {
boolean tmp = DictUtil.del(dictWrapperModel);
int count = 2;
{
boolean tmp = SecurityCache.remove(redisTemplate, cacheKeyByValue);
if(tmp){
count--;
}
}
{
boolean tmp = SecurityCache.remove(redisTemplate, cacheKeyByName);
if(tmp){
count--;
}
@ -461,6 +261,45 @@ public class DictUtil {
return count == 0;
}
/**
*
* @param model
*/
private static DictWrapper formatModel(DictDetailModel model){
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
return dictWrapperModel;
}
/**
*
* @param dictWrapperModels Model
* @return List
*/
private static List<DictWrapper> sortDictWrappers(List<DictWrapper> dictWrapperModels) {
// 非法判读
if(dictWrapperModels == null){
return null;
}
ListUtil.sort(dictWrapperModels, (o1, o2) -> {
int oInt1 = Integer.MAX_VALUE;
int oInt2 = Integer.MAX_VALUE;
if(o1 != null && o1.getModel() != null){
oInt1 = o1.getModel().getSortNo()==null?oInt1:o1.getModel().getSortNo();
}
if(o2 != null && o2.getModel() != null){
oInt2 = o2.getModel().getSortNo()==null?oInt2:o2.getModel().getSortNo();
}
return Integer.compare(oInt1, oInt2);
});
return dictWrapperModels;
}
/***
*
* @param dictMap Map
@ -496,9 +335,10 @@ public class DictUtil {
*
*/
@Autowired
public void init(DictDetailApi dictDetailApi) {
public void init(DictDetailApi dictDetailApi,
RedisTemplate<String, Object> redisTemplate) {
DictUtil.dictDetailApi = dictDetailApi;
DictUtil.redisTemplate = redisTemplate;
IS_INIT = true;
}

@ -16,7 +16,7 @@
package org.opsli.core.utils;
import lombok.extern.slf4j.Slf4j;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redisson.RedissonLock;
import org.springframework.beans.factory.annotation.Autowired;

@ -15,16 +15,20 @@
*/
package org.opsli.core.utils;
import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.menu.MenuApi;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.common.constants.RedisConstants;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.cache.SecurityCache;
import org.opsli.core.msg.CoreMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
@ -50,6 +54,8 @@ public class MenuUtil {
/** 增加初始状态开关 防止异常使用 */
private static boolean IS_INIT;
private static RedisTemplate<String, Object> redisTemplate;
/**
*
* @param permissions
@ -60,57 +66,20 @@ public class MenuUtil {
ThrowExceptionUtil.isThrowException(!IS_INIT,
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 缓存Key
String cacheKey = PREFIX_CODE + permissions;
// 先从缓存里拿
MenuModel menuModel = CacheUtil.getTimed(MenuModel.class, cacheKey);
if (menuModel != null){
return menuModel;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKey)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
menuModel = CacheUtil.getTimed(MenuModel.class, cacheKey);
if (menuModel != null){
return menuModel;
}
// 缓存Key
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_MENU_CODE + permissions);
Object cache = SecurityCache.get(redisTemplate, cacheKey, (k) -> {
// 查询数据库
ResultVo<MenuModel> resultVo = menuApi.getByPermissions(permissions);
if(resultVo.isSuccess()){
menuModel = resultVo.getData();
// 存入缓存
CacheUtil.put(cacheKey, menuModel);
if(!resultVo.isSuccess()){
return null;
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKey);
}
return resultVo.getData();
}, true);
if(menuModel == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(cacheKey);
return null;
}
return menuModel;
return Convert.convert(MenuModel.class, cache);
}
@ -130,46 +99,24 @@ public class MenuUtil {
return true;
}
// 计数器
int count = 0;
MenuModel model = CacheUtil.getTimed(MenuModel.class, PREFIX_CODE + menu.getPermissions());
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_CODE + menu.getPermissions());
// 只要不为空 则执行刷新
if (hasNilFlag){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delNilFlag(PREFIX_CODE + menu.getPermissions());
if(tmp){
count--;
}
}
if(model != null){
count++;
// 先删除
boolean tmp = CacheUtil.del(PREFIX_CODE + menu.getPermissions());
if(tmp){
count--;
}
}
// 缓存Key
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_MENU_CODE + menu.getPermissions());
return count == 0;
// 删除缓存
return SecurityCache.remove(redisTemplate, cacheKey);
}
// =====================================
/**
*
*/
@Autowired
public void init(MenuApi menuApi) {
public void init(MenuApi menuApi,
RedisTemplate<String, Object> redisTemplate) {
MenuUtil.menuApi = menuApi;
MenuUtil.redisTemplate = redisTemplate;
IS_INIT = true;
}

@ -27,12 +27,15 @@ import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.options.OptionsApi;
import org.opsli.api.wrapper.system.options.OptionsModel;
import org.opsli.common.annotation.OptionDict;
import org.opsli.common.constants.RedisConstants;
import org.opsli.common.enums.OptionsType;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.cache.SecurityCache;
import org.opsli.core.msg.CoreMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
@ -54,9 +57,6 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
@Lazy(false)
public class OptionsUtil {
/** 前缀 */
public static final String PREFIX_CODE = "options:code";
/** 参数 Api */
private static OptionsApi optionsApi;
@ -66,6 +66,8 @@ public class OptionsUtil {
/** 增加初始状态开关 防止异常使用 */
private static boolean IS_INIT;
private static RedisTemplate<String, Object> redisTemplate;
/**
* optionsType
* @param optionsType
@ -137,58 +139,18 @@ public class OptionsUtil {
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 缓存Key
String cacheKey = PREFIX_CODE;
// 缓存Key + VALUE
String cacheKeyVal = cacheKey + ":" + optionCode;
// 先从缓存里拿
OptionsModel model = CacheUtil.getHash(OptionsModel.class, cacheKey, optionCode);
if (model != null){
return model;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKeyVal);
if(hasNilFlag){
return null;
}
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKeyVal)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
model = CacheUtil.getHash(OptionsModel.class, cacheKey, optionCode);
if (model != null){
return model;
}
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_OPTIONS_CODE);
Object cache = SecurityCache.hGet(redisTemplate, cacheKey, optionCode, (k) -> {
// 查询数据库
ResultVo<OptionsModel> resultVo = optionsApi.getByCode(optionCode);
if(resultVo.isSuccess()){
model = resultVo.getData();
// 存入缓存
CacheUtil.putHash(cacheKey, optionCode, model);
if(!resultVo.isSuccess()){
return null;
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKeyVal);
}
if(model == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(cacheKeyVal);
return null;
}
return resultVo.getData();
});
return model;
return Convert.convert(OptionsModel.class, cache);
}
// ============== 刷新缓存 ==============
@ -208,36 +170,10 @@ public class OptionsUtil {
}
// 缓存Key
String cacheKey = PREFIX_CODE;
// 缓存Key + VALUE
String cacheKeyVal = cacheKey + ":" + option.getOptionCode();
// 计数器
int count = 0;
OptionsModel model = CacheUtil.getHash(OptionsModel.class, cacheKey, option.getOptionCode());
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKeyVal);
// 只要不为空 则执行刷新
if (hasNilFlag){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delNilFlag(cacheKeyVal);
if(tmp){
count--;
}
}
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_OPTIONS_CODE);
if(model != null){
count++;
// 先删除
boolean tmp = CacheUtil.delHash(cacheKey, option.getOptionCode());
if(tmp){
count--;
}
}
return count == 0;
// 删除缓存
return SecurityCache.hDel(redisTemplate, cacheKey, option.getOptionCode());
}
/**
@ -292,9 +228,10 @@ public class OptionsUtil {
*
*/
@Autowired
public void init(OptionsApi optionsApi) {
public void init(OptionsApi optionsApi,
RedisTemplate<String, Object> redisTemplate) {
OptionsUtil.optionsApi = optionsApi;
OptionsUtil.redisTemplate = redisTemplate;
IS_INIT = true;
}
}

@ -19,7 +19,8 @@ import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.common.constants.RedisConstants;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.plugins.redis.RedisPlugin;
import org.springframework.beans.factory.annotation.Autowired;
@ -48,8 +49,6 @@ public class SearchHisUtil {
/** 搜索历史缓存数据KEY */
private static final int DEFAULT_COUNT = 10;
/** 缓存前缀 */
private static final String CACHE_PREFIX = "his:username:";
/** Redis插件 */
private static RedisPlugin redisPlugin;
@ -79,7 +78,7 @@ public class SearchHisUtil {
// 获得当前用户
UserModel user = UserUtil.getUser();
String cacheKey = CacheUtil.getPrefixName() + CACHE_PREFIX + user.getUsername() + ":" + key;
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_HIS_USERNAME + user.getUsername() + ":" + key);
return redisPlugin.zReverseRange(cacheKey, 0, count - 1);
}
@ -109,7 +108,7 @@ public class SearchHisUtil {
}
String cacheKey = CacheUtil.getPrefixName() + CACHE_PREFIX + user.getUsername() + ":" + key;
String cacheKey = CacheUtil.formatKey(RedisConstants.PREFIX_HIS_USERNAME + user.getUsername() + ":" + key);
String val = values[0];
// 记录

@ -15,16 +15,19 @@
*/
package org.opsli.core.utils;
import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.tenant.TenantApi;
import org.opsli.api.wrapper.system.tenant.TenantModel;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.cache.SecurityCache;
import org.opsli.core.msg.CoreMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
@ -53,6 +56,8 @@ public class TenantUtil {
/** 增加初始状态开关 防止异常使用 */
private static boolean IS_INIT;
private static RedisTemplate<String, Object> redisTemplate;
/**
* tenantId
* @param tenantId ID
@ -64,56 +69,20 @@ public class TenantUtil {
CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
// 缓存Key
String cacheKey = PREFIX_CODE + tenantId;
// 先从缓存里拿
TenantModel tenantModel = CacheUtil.getTimed(TenantModel.class, cacheKey);
if (tenantModel != null){
return tenantModel;
}
String cacheKey = CacheUtil.formatKey(PREFIX_CODE + tenantId);
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKey)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
tenantModel = CacheUtil.getTimed(TenantModel.class, cacheKey);
if (tenantModel != null){
return tenantModel;
}
Object cache = SecurityCache.get(redisTemplate, cacheKey, (k) -> {
// 查询数据库
ResultVo<TenantModel> resultVo = tenantApi.getTenantByUsable(tenantId);
if(resultVo.isSuccess()){
tenantModel = resultVo.getData();
// 存入缓存
CacheUtil.put(cacheKey, tenantModel);
if(!resultVo.isSuccess()){
return null;
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKey);
}
if(tenantModel == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(cacheKey);
return null;
}
return resultVo.getData();
}, true);
return tenantModel;
return Convert.convert(TenantModel.class, cache);
}
@ -133,32 +102,10 @@ public class TenantUtil {
return true;
}
// 计数器
int count = 0;
TenantModel tenantModel = CacheUtil.getTimed(TenantModel.class, PREFIX_CODE + tenantId);
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_CODE + tenantId);
// 只要不为空 则执行刷新
if (hasNilFlag){
count++;
// 清除空拦截
boolean tmp = CacheUtil.delNilFlag(PREFIX_CODE + tenantId);
if(tmp){
count--;
}
}
if(tenantModel != null){
count++;
// 先删除
boolean tmp = CacheUtil.del(PREFIX_CODE + tenantId);
if(tmp){
count--;
}
}
// 缓存Key
String cacheKey = CacheUtil.formatKey(PREFIX_CODE + tenantId);
return count == 0;
return SecurityCache.remove(redisTemplate, cacheKey);
}
@ -168,9 +115,10 @@ public class TenantUtil {
*
*/
@Autowired
public void init(TenantApi tenantApi) {
public void init(TenantApi tenantApi,
RedisTemplate<String, Object> redisTemplate) {
TenantUtil.tenantApi = tenantApi;
TenantUtil.redisTemplate = redisTemplate;
IS_INIT = true;
}

@ -35,7 +35,7 @@ import org.opsli.common.enums.LoginLimitRefuse;
import org.opsli.common.exception.TokenException;
import org.opsli.core.api.TokenThreadLocal;
import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg;
import org.opsli.plugins.redis.RedisPlugin;

@ -33,7 +33,7 @@ import org.opsli.api.wrapper.system.user.UserOrgRefWebModel;
import org.opsli.common.exception.TokenException;
import org.opsli.core.api.TokenThreadLocal;
import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg;
import org.springframework.beans.factory.annotation.Autowired;

@ -21,15 +21,8 @@ import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.dict.DictDetailApi;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.constants.DictConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.utils.DictUtil;
import org.opsli.core.utils.DistributedLockUtil;
import org.opsli.core.utils.ThrowExceptionUtil;
import org.opsli.modulars.generator.template.service.IGenTemplateDetailService;

@ -2,8 +2,8 @@
echo "Git Pushing ......"
echo ""
git push "git@github.com:hiparker/opsli-boot.git" master
git push -f "git@gitee.com:hiparker/opsli-boot.git" master
git push "git@github.com:hiparker/opsli-boot.git" development
git push -f "git@gitee.com:hiparker/opsli-boot.git" development

@ -2,8 +2,8 @@
echo "Git Pushing ......"
echo ""
git push "git@github.com:hiparker/opsli-boot.git" master
git push -f "git@gitee.com:hiparker/opsli-boot.git" master
git push "git@github.com:hiparker/opsli-boot.git" development
git push -f "git@gitee.com:hiparker/opsli-boot.git" development

Loading…
Cancel
Save