org.opsliframework.boot
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/RedissonConfig.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/RedissonConfig.java
new file mode 100644
index 0000000..1da556c
--- /dev/null
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/RedissonConfig.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.autoconfigure.conf;
+
+import lombok.extern.slf4j.Slf4j;
+import org.opsli.plugins.redisson.RedissonLock;
+import org.opsli.plugins.redisson.RedissonManager;
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+
+/**
+ * Redisson自动化配置
+ *
+ * @author Parker
+ * @date 2019/6/19 下午11:55
+ */
+@Slf4j
+@Configuration
+@ConditionalOnProperty(name = "redisson.lock.server.enable", havingValue = "true")
+@EnableConfigurationProperties(RedissonProperties.class)
+public class RedissonConfig {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Order(value = 2)
+ public RedissonLock redissonLock(RedissonManager redissonManager) {
+ RedissonLock redissonLock = new RedissonLock(redissonManager);
+ log.info("[RedissonLock]组装完毕");
+ return redissonLock;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Order(value = 1)
+ public RedissonManager redissonManager(RedissonProperties redissonProperties) {
+ RedissonManager redissonManager =
+ new RedissonManager(redissonProperties);
+ log.info("[RedissonManager]组装完毕,当前连接方式:" + redissonProperties.getType().getDesc() +
+ ",连接地址:" + redissonProperties.getAddress());
+ return redissonManager;
+ }
+}
+
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java
index d7e17ed..ea2a91f 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/local/CacheUtil.java
@@ -649,7 +649,7 @@ public class CacheUtil {
public void init(CacheProperties cacheProperties){
if(cacheProperties != null){
// 获得 超级管理员
- CacheUtil.PREFIX_NAME = Convert.toStr(cacheProperties.getPrefix(), "opsli") + ":";
+ CacheUtil.PREFIX_NAME = Convert.toStr(cacheProperties.getPrefix(), "opsli") + "::";
}
}
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/CoreMsg.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/CoreMsg.java
index 2724f5a..eae5848 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/CoreMsg.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/CoreMsg.java
@@ -38,6 +38,7 @@ public enum CoreMsg implements BaseMsg {
* Redis
*/
REDIS_EXCEPTION_PUSH_SUB(10200,"Redis 订阅通道失败!"),
+ REDIS_EXCEPTION_LOCK(10201,"无法申领分布式锁"),
/**
* Excel
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/cache/RedisCacheManager.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/cache/RedisCacheManager.java
index d77c149..f8850ec 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/cache/RedisCacheManager.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/security/shiro/cache/RedisCacheManager.java
@@ -32,7 +32,7 @@ public class RedisCacheManager implements CacheManager {
/**
* The Redis key prefix for caches
*/
- public static final String DEFAULT_CACHE_KEY_PREFIX = "shiro:cache:";
+ public static final String DEFAULT_CACHE_KEY_PREFIX = "shiro::cache::";
private String keyPrefix = DEFAULT_CACHE_KEY_PREFIX;
public static final String DEFAULT_PRINCIPAL_ID_FIELD_NAME = "authCacheKey or id";
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java
index 3c8ff26..926d37d 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java
@@ -58,7 +58,7 @@ public class CaptchaUtil {
private static final List CAPTCHA_STRATEGY_LIST;
/** 缓存前缀 */
- private static final String PREFIX = "temp:captcha:";
+ private static final String PREFIX = "temp::captcha::";
/** 默认验证码保存 5 分钟 */
private static final int TIME_OUT = 300;
/** Redis插件 */
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java
index 53d9f5b..456e2f2 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java
@@ -46,7 +46,7 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
public class MenuUtil {
/** 前缀 */
- public static final String PREFIX_CODE = "menu:code:";
+ public static final String PREFIX_CODE = "menu::code::";
/** Redis插件 */
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java
index 3418416..e3143c7 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java
@@ -46,7 +46,7 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
public class OrgUtil {
/** 前缀 */
- public static final String PREFIX_CODE = "org:userId:";
+ public static final String PREFIX_CODE = "org::userId::";
/** Redis插件 */
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java
index 96d9014..029a0e2 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java
@@ -48,7 +48,7 @@ public class SearchHisUtil {
/** 搜索历史缓存数据KEY */
private static final int DEFAULT_COUNT = 10;
- private static final String CACHE_PREFIX = "his:username:";
+ private static final String CACHE_PREFIX = "his::username::";
/** Redis插件 */
private static RedisPlugin redisPlugin;
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java
index 8ff8ee7..10d31ef 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java
@@ -46,7 +46,7 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
public class TenantUtil {
/** 前缀 */
- public static final String PREFIX_CODE = "tenant:id:";
+ public static final String PREFIX_CODE = "tenant::id::";
/** Redis插件 */
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java
index 657a517..e048bd6 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java
@@ -61,11 +61,11 @@ public class UserTokenUtil {
/** token 缓存名 */
public static final String TOKEN_NAME = TokenConstants.ACCESS_TOKEN;
/** 缓存前缀 */
- private static final String TICKET_PREFIX = "ticket:";
+ private static final String TICKET_PREFIX = "ticket::";
/** 账号失败次数 */
- public static final String ACCOUNT_SLIP_COUNT_PREFIX = "account:slip:count:";
+ public static final String ACCOUNT_SLIP_COUNT_PREFIX = "account::slip::count::";
/** 账号失败锁定KEY */
- public static final String ACCOUNT_SLIP_LOCK_PREFIX = "account:slip:lock:";
+ public static final String ACCOUNT_SLIP_LOCK_PREFIX = "account::slip::lock::";
/** 限制登录数量 -1 为无限大 */
public static final int ACCOUNT_LIMIT_INFINITE = -1;
/** 登录配置信息 */
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java
index 9f4d69d..ee46173 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java
@@ -15,7 +15,9 @@
*/
package org.opsli.core.utils;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
+import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
@@ -31,16 +33,19 @@ import org.opsli.common.exception.TokenException;
import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.msgs.UserMsgFactory;
+import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg;
import org.opsli.plugins.redis.RedisLockPlugins;
import org.opsli.plugins.redis.RedisPlugin;
import org.opsli.plugins.redis.lock.RedisLock;
+import org.opsli.plugins.redisson.RedissonLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
@@ -58,18 +63,18 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER;
public class UserUtil {
/** 前缀 */
- public static final String PREFIX_ID = "userId:";
- public static final String PREFIX_ID_ROLES = "userId:roles:";
- public static final String PREFIX_ID_PERMISSIONS = "userId:permissions:";
- public static final String PREFIX_ID_MENUS = "userId:menus:";
- public static final String PREFIX_USERNAME = "username:";
+ public static final String PREFIX_ID = "userId::";
+ public static final String PREFIX_ID_ROLES = "userId::roles::";
+ public static final String PREFIX_ID_PERMISSIONS = "userId::permissions::";
+ public static final String PREFIX_ID_MENUS = "userId::menus::";
+ public static final String PREFIX_USERNAME = "username::";
/** Redis插件 */
private static RedisPlugin redisPlugin;
- /** Redis分布式锁 */
- private static RedisLockPlugins redisLockPlugins;
+ /** Redisson 分布式锁 */
+ private static RedissonLock REDISSON_LOCK;
/** 用户Service */
private static UserApi userApi;
@@ -104,36 +109,35 @@ public class UserUtil {
* @return UserModel
*/
public static UserModel getUser(String userId){
+
+ // 缓存Key
+ String cacheKey = PREFIX_ID + userId;
+
// 先从缓存里拿
- UserModel userModel = CacheUtil.getTimed(UserModel.class, PREFIX_ID + userId);
+ UserModel userModel = CacheUtil.getTimed(UserModel.class, cacheKey);
if (userModel != null){
return userModel;
}
-
// 拿不到 --------
// 防止缓存穿透判断
- boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID + userId);
+ boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
- // 锁凭证 redisLock 贯穿全程
- RedisLock redisLock = new RedisLock();
- redisLock.setLockName(PREFIX_ID + userId)
- .setAcquireTimeOut(3000L)
- .setLockTimeOut(5000L);
-
try {
- // 这里增加分布式锁 防止缓存击穿
- // ============ 尝试加锁
- redisLock = redisLockPlugins.tryLock(redisLock);
- if(redisLock == null){
+ // 分布式上锁
+ boolean isLock = REDISSON_LOCK.tryLock(
+ cacheKey, 5);
+ if(!isLock){
+ // 无法申领分布式锁
+ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
- userModel = CacheUtil.getTimed(UserModel.class, PREFIX_ID + userId);
+ userModel = CacheUtil.getTimed(UserModel.class, cacheKey);
if (userModel != null){
return userModel;
}
@@ -147,18 +151,22 @@ public class UserUtil {
if(resultVo.isSuccess()){
userModel = resultVo.getData();
// 存入缓存
- CacheUtil.put(PREFIX_ID + userId, userModel);
+ CacheUtil.put(cacheKey, userModel);
}
+
}catch (Exception e){
- log.error(e.getMessage(),e);
+ log.error(e.getMessage(), e);
}finally {
- // ============ 释放锁
- redisLockPlugins.unLock(redisLock);
+ // 是否是当前线程
+ if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){
+ // 释放锁
+ REDISSON_LOCK.unlock(cacheKey);
+ }
}
if(userModel == null){
// 设置空变量 用于防止穿透判断
- CacheUtil.putNilFlag(PREFIX_ID + userId);
+ CacheUtil.putNilFlag(cacheKey);
return null;
}
@@ -172,56 +180,58 @@ public class UserUtil {
* @return UserModel
*/
public static UserModel getUserByUserName(String userName){
+ // 缓存Key
+ String cacheKey = PREFIX_USERNAME + userName;
+
// 先从缓存里拿
- UserModel userModel = CacheUtil.getTimed(UserModel.class, PREFIX_USERNAME + userName);
+ UserModel userModel = CacheUtil.getTimed(UserModel.class, cacheKey);
if (userModel != null){
return userModel;
}
// 拿不到 --------
// 防止缓存穿透判断
- boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_USERNAME + userName);
+ boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
- // 锁凭证 redisLock 贯穿全程
- RedisLock redisLock = new RedisLock();
- redisLock.setLockName(PREFIX_USERNAME + userName)
- .setAcquireTimeOut(3000L)
- .setLockTimeOut(5000L);
-
try {
- // 这里增加分布式锁 防止缓存击穿
- // ============ 尝试加锁
- redisLock = redisLockPlugins.tryLock(redisLock);
- if(redisLock == null){
+ // 分布式上锁
+ boolean isLock = REDISSON_LOCK.tryLock(
+ cacheKey, 5);
+ if(!isLock){
+ // 无法申领分布式锁
+ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
- userModel = CacheUtil.getTimed(UserModel.class, PREFIX_USERNAME + userName);
- if (userModel != null){
+ userModel = CacheUtil.getTimed(UserModel.class, cacheKey);
+ if (userModel != null) {
return userModel;
}
// 查询数据库
ResultVo resultVo = userApi.getUserByUsername(userName);
- if(resultVo.isSuccess()){
+ if (resultVo.isSuccess()) {
userModel = resultVo.getData();
// 存入缓存
- CacheUtil.put(PREFIX_USERNAME + userName, userModel);
+ CacheUtil.put(cacheKey, userModel);
}
}catch (Exception e){
- log.error(e.getMessage(),e);
+ log.error(e.getMessage(), e);
}finally {
- // ============ 释放锁
- redisLockPlugins.unLock(redisLock);
+ // 是否是当前线程
+ if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){
+ // 释放锁
+ REDISSON_LOCK.unlock(cacheKey);
+ }
}
if(userModel == null){
// 设置空变量 用于防止穿透判断
- CacheUtil.putNilFlag(PREFIX_USERNAME + userName);
+ CacheUtil.putNilFlag(cacheKey);
return null;
}
@@ -234,80 +244,62 @@ public class UserUtil {
* @return List
*/
public static List getUserRolesByUserId(String userId){
- List roles = null;
+ // 缓存Key
+ String cacheKey = PREFIX_ID_ROLES + userId;
+
+ List roles;
// 先从缓存里拿
- try {
- Object obj = CacheUtil.getTimed(PREFIX_ID_ROLES + userId);
- if(obj instanceof List){
- List list = Convert.toList(String.class, obj);
- if (!list.isEmpty()) {
- return list;
- }
- }else {
- JSONArray jsonArray = Convert.convert(JSONArray.class, obj);
- if (jsonArray != null && !jsonArray.isEmpty()) {
- return jsonArray.toJavaList(String.class);
- }
- }
- }catch (Exception e){
- log.error(e.getMessage(), e);
+ Object obj = CacheUtil.getTimed(cacheKey);
+ roles = Convert.toList(String.class, obj);
+ if(CollUtil.isNotEmpty(roles)){
+ return roles;
}
// 拿不到 --------
// 防止缓存穿透判断
- boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_ROLES + userId);
+ boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
- // 锁凭证 redisLock 贯穿全程
- RedisLock redisLock = new RedisLock();
- redisLock.setLockName(PREFIX_ID_ROLES + userId)
- .setAcquireTimeOut(3000L)
- .setLockTimeOut(5000L);
-
try {
- // 这里增加分布式锁 防止缓存击穿
- // ============ 尝试加锁
- redisLock = redisLockPlugins.tryLock(redisLock);
- if(redisLock == null){
+ // 分布式上锁
+ boolean isLock = REDISSON_LOCK.tryLock(
+ cacheKey, 5);
+ if(!isLock){
+ // 无法申领分布式锁
+ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
- try {
- Object obj = CacheUtil.getTimed(PREFIX_ID_ROLES + userId);
- if(obj instanceof List){
- List list = Convert.toList(String.class, obj);
- if (!list.isEmpty()) {
- return list;
- }
- }else {
- JSONArray jsonArray = Convert.convert(JSONArray.class, obj);
- if (jsonArray != null && !jsonArray.isEmpty()) {
- return jsonArray.toJavaList(String.class);
- }
- }
- }catch (Exception ignored){}
+ obj = CacheUtil.getTimed(cacheKey);
+ roles = Convert.toList(String.class, obj);
+ if(CollUtil.isNotEmpty(roles)){
+ return roles;
+ }
// 查询数据库
ResultVo> resultVo = userApi.getRolesByUserId(userId);
if(resultVo.isSuccess()){
roles = resultVo.getData();
// 存入缓存
- CacheUtil.put(PREFIX_ID_ROLES + userId, roles);
+ CacheUtil.put(cacheKey, roles);
}
}catch (Exception e){
- log.error(e.getMessage(),e);
+ log.error(e.getMessage(), e);
}finally {
- // ============ 释放锁
- redisLockPlugins.unLock(redisLock);
+ // 是否是当前线程
+ if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){
+ // 释放锁
+ REDISSON_LOCK.unlock(cacheKey);
+ }
}
- if(roles == null || roles.size() == 0){
+ if(CollUtil.isEmpty(roles)){
// 设置空变量 用于防止穿透判断
- CacheUtil.putNilFlag(PREFIX_ID_ROLES + userId);
+ CacheUtil.putNilFlag(cacheKey);
return null;
}
@@ -321,81 +313,63 @@ public class UserUtil {
* @return List
*/
public static List getUserAllPermsByUserId(String userId){
- List permissions = null;
+
+ // 缓存Key
+ String cacheKey = PREFIX_ID_PERMISSIONS + userId;
+
+ List permissions;
// 先从缓存里拿
- try {
- Object obj = CacheUtil.getTimed(PREFIX_ID_PERMISSIONS + userId);
- if(obj instanceof List){
- List list = Convert.toList(String.class, obj);
- if (!list.isEmpty()) {
- return list;
- }
- }else {
- JSONArray jsonArray = Convert.convert(JSONArray.class, obj);
- if (jsonArray != null && !jsonArray.isEmpty()) {
- return jsonArray.toJavaList(String.class);
- }
- }
- }catch (Exception e){
- log.error(e.getMessage(), e);
+ Object obj = CacheUtil.getTimed(cacheKey);
+ permissions = Convert.toList(String.class, obj);
+ if(CollUtil.isNotEmpty(permissions)){
+ return permissions;
}
-
// 拿不到 --------
// 防止缓存穿透判断
- boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_PERMISSIONS + userId);
+ boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
- // 锁凭证 redisLock 贯穿全程
- RedisLock redisLock = new RedisLock();
- redisLock.setLockName(PREFIX_ID_PERMISSIONS + userId)
- .setAcquireTimeOut(3000L)
- .setLockTimeOut(5000L);
-
try {
- // 这里增加分布式锁 防止缓存击穿
- // ============ 尝试加锁
- redisLock = redisLockPlugins.tryLock(redisLock);
- if(redisLock == null){
+ // 分布式上锁
+ boolean isLock = REDISSON_LOCK.tryLock(
+ cacheKey, 5);
+ if(!isLock){
+ // 无法申领分布式锁
+ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
- try {
- Object obj = CacheUtil.getTimed(PREFIX_ID_PERMISSIONS + userId);
- if(obj instanceof List){
- List list = Convert.toList(String.class, obj);
- if (!list.isEmpty()) {
- return list;
- }
- }else {
- JSONArray jsonArray = Convert.convert(JSONArray.class, obj);
- if (jsonArray != null && !jsonArray.isEmpty()) {
- return jsonArray.toJavaList(String.class);
- }
- }
- }catch (Exception ignored){}
+ obj = CacheUtil.getTimed(cacheKey);
+ permissions = Convert.toList(String.class, obj);
+ if(CollUtil.isNotEmpty(permissions)){
+ return permissions;
+ }
// 查询数据库
ResultVo> resultVo = userApi.getAllPerms(userId);
if(resultVo.isSuccess()){
permissions = resultVo.getData();
// 存入缓存
- CacheUtil.put(PREFIX_ID_PERMISSIONS + userId, permissions);
+ CacheUtil.put(cacheKey, permissions);
}
}catch (Exception e){
- log.error(e.getMessage(),e);
+ log.error(e.getMessage(), e);
}finally {
- // ============ 释放锁
- redisLockPlugins.unLock(redisLock);
+ // 是否是当前线程
+ if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){
+ // 释放锁
+ REDISSON_LOCK.unlock(cacheKey);
+ }
}
- if(permissions == null || permissions.size() == 0){
+ if(CollUtil.isEmpty(permissions)){
// 设置空变量 用于防止穿透判断
- CacheUtil.putNilFlag(PREFIX_ID_PERMISSIONS + userId);
+ CacheUtil.putNilFlag(cacheKey);
return null;
}
@@ -408,101 +382,64 @@ public class UserUtil {
* @return List
*/
public static List getMenuListByUserId(String userId){
- List menus = null;
+
+ // 缓存Key
+ String cacheKey = PREFIX_ID_MENUS + userId;
+
+ List menus;
// 先从缓存里拿
- try {
- Object obj = CacheUtil.getTimed(PREFIX_ID_MENUS + userId);
- if(obj instanceof List){
- List> list = Convert.toList(obj);
- if (!list.isEmpty()) {
- List menuModels = Lists.newArrayListWithCapacity(list.size());
- for (Object menuObj : list) {
- if(menuObj instanceof MenuModel){
- menuModels.add((MenuModel) menuObj);
- }else if(menuObj instanceof JSONObject){
- JSONObject jsonObject = (JSONObject) menuObj;
- MenuModel t = JSONObject.toJavaObject(jsonObject, MenuModel.class);
- menuModels.add(t);
- }
- }
- return menuModels;
- }
- }else {
- JSONArray jsonArray = Convert.convert(JSONArray.class, obj);
- if (jsonArray != null && !jsonArray.isEmpty()) {
- return jsonArray.toJavaList(MenuModel.class);
- }
- }
- }catch (Exception e){
- log.error(e.getMessage(), e);
+ Object obj = CacheUtil.getTimed(cacheKey);
+ menus = Convert.toList(MenuModel.class, obj);
+ if(CollUtil.isNotEmpty(menus)){
+ return menus;
}
-
// 拿不到 --------
// 防止缓存穿透判断
- boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_MENUS + userId);
+ boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey);
if(hasNilFlag){
return null;
}
- // 锁凭证 redisLock 贯穿全程
- RedisLock redisLock = new RedisLock();
- redisLock.setLockName(PREFIX_ID_MENUS + userId)
- .setAcquireTimeOut(3000L)
- .setLockTimeOut(5000L);
try {
- // 这里增加分布式锁 防止缓存击穿
- // ============ 尝试加锁
- redisLock = redisLockPlugins.tryLock(redisLock);
- if(redisLock == null){
+ // 分布式上锁
+ boolean isLock = REDISSON_LOCK.tryLock(
+ cacheKey, 5);
+ if(!isLock){
+ // 无法申领分布式锁
+ log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return null;
}
// 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求
- try {
- Object obj = CacheUtil.getTimed(PREFIX_ID_MENUS + userId);
- if(obj instanceof List){
- List> list = Convert.toList(obj);
- if (!list.isEmpty()) {
- List menuModels = Lists.newArrayListWithCapacity(list.size());
- for (Object menuObj : list) {
- if(menuObj instanceof MenuModel){
- menuModels.add((MenuModel) menuObj);
- }else if(menuObj instanceof JSONObject){
- JSONObject jsonObject = (JSONObject) menuObj;
- MenuModel t = JSONObject.toJavaObject(jsonObject, MenuModel.class);
- menuModels.add(t);
- }
- }
- return menuModels;
- }
- }else {
- JSONArray jsonArray = Convert.convert(JSONArray.class, obj);
- if (jsonArray != null && !jsonArray.isEmpty()) {
- return jsonArray.toJavaList(MenuModel.class);
- }
- }
- }catch (Exception ignored){}
+ obj = CacheUtil.getTimed(cacheKey);
+ menus = Convert.toList(MenuModel.class, obj);
+ if(CollUtil.isNotEmpty(menus)){
+ return menus;
+ }
// 查询数据库
ResultVo> resultVo = userApi.getMenuListByUserId(userId);
if(resultVo.isSuccess()){
menus = resultVo.getData();
// 存入缓存
- CacheUtil.put(PREFIX_ID_MENUS + userId, menus);
+ CacheUtil.put(cacheKey, menus);
}
}catch (Exception e){
- log.error(e.getMessage(),e);
+ log.error(e.getMessage(), e);
}finally {
- // ============ 释放锁
- redisLockPlugins.unLock(redisLock);
+ // 是否是当前线程
+ if(REDISSON_LOCK.isHeldByCurrentThread(cacheKey)){
+ // 释放锁
+ REDISSON_LOCK.unlock(cacheKey);
+ }
}
- if(menus == null || menus.size() == 0){
+ if(CollUtil.isEmpty(menus)){
// 设置空变量 用于防止穿透判断
- CacheUtil.putNilFlag(PREFIX_ID_MENUS + userId);
+ CacheUtil.putNilFlag(cacheKey);
return null;
}
@@ -727,28 +664,25 @@ public class UserUtil {
UserUtil.redisPlugin = redisPlugin;
}
- @Autowired
- public void setRedisLockPlugins(RedisLockPlugins redisLockPlugins) {
- UserUtil.redisLockPlugins = redisLockPlugins;
- }
-
@Autowired
public void setUserApi(UserApi userApi) {
UserUtil.userApi = userApi;
}
+
/**
* 初始化
* @param globalProperties 配置类
*/
@Autowired
- public void init(GlobalProperties globalProperties){
+ public void init(GlobalProperties globalProperties, RedissonLock redissonLock){
if(globalProperties != null && globalProperties.getAuth() != null
&& globalProperties.getAuth().getToken() != null
){
// 获得 超级管理员
UserUtil.SUPER_ADMIN = globalProperties.getAuth().getSuperAdmin();
}
+ UserUtil.REDISSON_LOCK = redissonLock;
}
}
diff --git a/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLock.java b/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLock.java
index ab13800..d90c337 100644
--- a/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLock.java
+++ b/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLock.java
@@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class RedisLock {
- private static final String LOCK_PREFIX = "lock:";
+ private static final String LOCK_PREFIX = "lock::";
/** 锁名称 */
private String lockName;
diff --git a/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLockImpl.java b/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLockImpl.java
index ba36276..0d2bfa8 100644
--- a/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLockImpl.java
+++ b/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/lock/RedisLockImpl.java
@@ -53,7 +53,7 @@ import java.util.List;
public class RedisLockImpl implements RedisLockPlugins {
/** 锁前缀 */
- private static final String LOCK_NAME_PREFIX = "lock:";
+ private static final String LOCK_NAME_PREFIX = "lock::";
@Autowired
private RedisPlugin redisPlugin;
diff --git a/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/pushsub/receiver/BaseReceiver.java b/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/pushsub/receiver/BaseReceiver.java
index 0a46a1d..62985e2 100644
--- a/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/pushsub/receiver/BaseReceiver.java
+++ b/opsli-plugins/opsli-plugins-redis/src/main/java/org/opsli/plugins/redis/pushsub/receiver/BaseReceiver.java
@@ -11,7 +11,7 @@ package org.opsli.plugins.redis.pushsub.receiver;
*/
public abstract class BaseReceiver {
- public static final String BASE_CHANNEL = "listener:msg:";
+ public static final String BASE_CHANNEL = "listener::msg::";
private final String channel;
public BaseReceiver(String channel){
diff --git a/opsli-plugins/opsli-plugins-redisson/README.md b/opsli-plugins/opsli-plugins-redisson/README.md
new file mode 100644
index 0000000..07451e4
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/README.md
@@ -0,0 +1,35 @@
+## application.properties配置方式(yaml同理)
+### redisson分布式锁配置--单机
+
+ redisson.lock.server.address=127.0.0.1:6379
+ redisson.lock.server.type=standalone
+ redisson.lock.server.password=
+ redisson.lock.server.database=1
+
+### redisson分布式锁配置--哨兵
+**redisson.lock.server.address** 格式为: sentinel.conf配置里的sentinel别名,sentinel1节点的服务IP和端口,sentinel2节点的服务IP和端口,sentinel3节点的服务IP和端口
+
比如sentinel.conf里配置为sentinel monitor my-sentinel-name 127.0.0.1 6379 2,那么这里就配置my-sentinel-name
+
+ redisson.server.address=my-sentinel-name,127.0.0.1:26379,127.0.0.1:26389,127.0.0.1:26399
+ redisson.server.type=sentinel
+ redisson.lock.server.password=
+ redisson.lock.server.database=1
+
+### redisson分布式锁配置--集群方式
+cluster方式至少6个节点(3主3从,3主做sharding,3从用来保证主宕机后可以高可用)
+
地址格式为: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
+
+ redisson.server.address=127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
+ redisson.server.type=cluster
+ redisson.lock.server.password=
+ redisson.lock.server.database=1
+
+### redisson分布式锁配置--主从
+地址格式为**主节点,子节点,子节点**
+
比如:127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381
+
代表主节点:127.0.0.1:6379,从节点127.0.0.1:6380,127.0.0.1:6381
+
+ redisson.server.address=127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381
+ redisson.server.type=masterslave
+ redisson.lock.server.password=
+ redisson.lock.server.database=1
diff --git a/opsli-plugins/opsli-plugins-redisson/pom.xml b/opsli-plugins/opsli-plugins-redisson/pom.xml
new file mode 100644
index 0000000..375d15c
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/pom.xml
@@ -0,0 +1,25 @@
+
+
+
+ opsli-plugins
+ org.opsliframework.boot
+ 1.0.0
+ ../pom.xml
+
+
+ 4.0.0
+ opsli-plugins-redisson
+ ${project.parent.version}
+
+
+
+
+ org.redisson
+ redisson
+
+
+
+
+
\ No newline at end of file
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/RedissonLock.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/RedissonLock.java
new file mode 100644
index 0000000..35cad7c
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/RedissonLock.java
@@ -0,0 +1,122 @@
+package org.opsli.plugins.redisson;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.Redisson;
+import org.redisson.api.RLock;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Description: 针对源码Redisson进行一层封装
+ *
+ * @author xub
+ * @date 2019/6/19 下午10:26
+ */
+@Slf4j
+public class RedissonLock {
+
+ private static final String PREFIX = "lock::";
+
+ private RedissonManager redissonManager;
+ private Redisson redisson;
+
+
+ public RedissonLock(RedissonManager redissonManager) {
+ this.redissonManager = redissonManager;
+ this.redisson = redissonManager.getRedisson();
+ }
+
+ public RedissonLock() {}
+
+ /**
+ * 加锁操作 (设置锁的有效时间)
+ * @param lockName 锁名称
+ * @param leaseTime 锁有效时间
+ */
+ public void lock(String lockName, long leaseTime) {
+ RLock rLock = redisson.getLock(PREFIX + lockName);
+ rLock.lock(leaseTime,TimeUnit.SECONDS);
+ }
+
+ /**
+ * 加锁操作 (锁有效时间采用默认时间30秒)
+ * @param lockName 锁名称
+ */
+ public void lock(String lockName) {
+ RLock rLock = redisson.getLock(PREFIX + lockName);
+ rLock.lock();
+ }
+
+ /**
+ * 加锁操作(tryLock锁,没有等待时间)
+ * @param lockName 锁名称
+ * @param leaseTime 锁有效时间
+ */
+ public boolean tryLock(String lockName, long leaseTime) {
+
+ RLock rLock = redisson.getLock(PREFIX + lockName);
+ boolean getLock;
+ try {
+ getLock = rLock.tryLock( leaseTime, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ log.error("获取Redisson分布式锁[异常],lockName=" + lockName, e);
+ e.printStackTrace();
+ return false;
+ }
+ return getLock;
+ }
+
+ /**
+ * 加锁操作(tryLock锁,有等待时间)
+ * @param lockName 锁名称
+ * @param leaseTime 锁有效时间
+ * @param waitTime 等待时间
+ */
+ public boolean tryLock(String lockName, long leaseTime, long waitTime) {
+ RLock rLock = redisson.getLock(PREFIX + lockName);
+ boolean getLock;
+ try {
+ getLock = rLock.tryLock( waitTime, leaseTime, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ log.error("获取Redisson分布式锁[异常],lockName=" + lockName, e);
+ e.printStackTrace();
+ return false;
+ }
+ return getLock;
+ }
+
+ /**
+ * 解锁
+ * @param lockName 锁名称
+ */
+ public void unlock(String lockName) {
+ redisson.getLock(PREFIX + lockName).unlock();
+ }
+
+ /**
+ * 判断该锁是否已经被线程持有
+ * @param lockName 锁名称
+ */
+ public boolean isLock(String lockName) {
+ RLock rLock = redisson.getLock(PREFIX + lockName);
+ return rLock.isLocked();
+ }
+
+
+ /**
+ * 判断该线程是否持有当前锁
+ * @param lockName 锁名称
+ */
+ public boolean isHeldByCurrentThread(String lockName) {
+ RLock rLock = redisson.getLock(PREFIX + lockName);
+ return rLock.isHeldByCurrentThread();
+ }
+
+ public RedissonManager getRedissonManager() {
+ return redissonManager;
+ }
+
+ public void setRedissonManager(RedissonManager redissonManager) {
+ this.redissonManager = redissonManager;
+ }
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/RedissonManager.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/RedissonManager.java
new file mode 100644
index 0000000..fb8d698
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/RedissonManager.java
@@ -0,0 +1,113 @@
+package org.opsli.plugins.redisson;
+
+import cn.hutool.core.util.ClassUtil;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.opsli.plugins.redisson.strategy.RedissonConfigService;
+import org.redisson.Redisson;
+import org.redisson.config.Config;
+
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * @Description: Redisson核心配置,用于提供初始化的redisson实例
+ *
+ * @author xub
+ * @date 2019/6/19 下午10:16
+ */
+@Slf4j
+public class RedissonManager {
+
+ private final Redisson redisson;
+
+ public RedissonManager(RedissonProperties redissonProperties) {
+ try {
+ //通过不同部署方式获得不同config实体
+ Config config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
+ redisson = (Redisson) Redisson.create(config);
+ } catch (Exception e) {
+ log.error("Redisson 初始化异常", e);
+ throw new IllegalArgumentException("请输入正确的配置," +
+ "connectionType必须在 standalone/sentinel/cluster/masterslave");
+ }
+ }
+
+ public Redisson getRedisson() {
+ return redisson;
+ }
+
+ /**
+ * Redisson连接方式配置工厂
+ * 双重检查锁
+ */
+ static class RedissonConfigFactory {
+
+ /** 策略集合 */
+ private final Map strategyMap = Maps.newHashMap();
+
+ private RedissonConfigFactory() {
+ Set> clazzSet = ClassUtil.scanPackageBySuper(
+ RedissonConfigService.class.getPackage().getName()+".impl",
+ RedissonConfigService.class
+ );
+ for (Class> aClass : clazzSet) {
+ // 位运算 去除抽象类
+ if((aClass.getModifiers() & Modifier.ABSTRACT) != 0){
+ continue;
+ }
+
+ try {
+ Object obj = aClass.newInstance();
+ RedissonConfigService handler = (RedissonConfigService) obj;
+ // 加入集合
+ strategyMap.put(handler.getType(),handler);
+ } catch (Exception e){
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ private static volatile RedissonConfigFactory factory = null;
+
+ public static RedissonConfigFactory getInstance() {
+ if (factory == null) {
+ synchronized (Object.class) {
+ if (factory == null) {
+ factory = new RedissonConfigFactory();
+ }
+ }
+ }
+ return factory;
+ }
+
+
+ /**
+ * 根据连接类型获取对应连接方式的配置,基于策略模式
+ *
+ * @param redissonProperties redis连接信息
+ * @return Config
+ */
+ Config createConfig(RedissonProperties redissonProperties) {
+ Preconditions.checkNotNull(redissonProperties);
+ Preconditions.checkNotNull(redissonProperties.getAddress(), "redisson.lock.server.address 不能为空!");
+ Preconditions.checkNotNull(redissonProperties.getType().getType(), "redisson.lock.server.password 不能为空!");
+ Preconditions.checkNotNull(redissonProperties.getDatabase(), "redisson.lock.server.database cannot 不能为空");
+ String connectionType = redissonProperties.getType().getType();
+ //声明配置上下文
+ RedissonConfigService redissonConfigService = strategyMap.get(redissonProperties.getType());
+ if (redissonConfigService == null){
+ throw new IllegalArgumentException("创建Redisson连接Config失败!当前连接方式:" + connectionType);
+ }
+ return redissonConfigService.createRedissonConfig(redissonProperties);
+ }
+ }
+
+}
+
+
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/annotation/DistributedLock.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/annotation/DistributedLock.java
new file mode 100644
index 0000000..e0a5a21
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/annotation/DistributedLock.java
@@ -0,0 +1,28 @@
+package org.opsli.plugins.redisson.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @Description: 基于注解的分布式式锁
+ *
+ * @author xub
+ * @date 2019/6/19 下午9:22
+ */
+@Documented
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface DistributedLock {
+
+ /**
+ * 锁的名称
+ */
+ String value() default "redisson";
+
+ /**
+ * 锁的有效时间
+ */
+ int leaseTime() default 10;
+}
+
+
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/annotation/DistributedLockHandler.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/annotation/DistributedLockHandler.java
new file mode 100644
index 0000000..641268d
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/annotation/DistributedLockHandler.java
@@ -0,0 +1,55 @@
+package org.opsli.plugins.redisson.annotation;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+
+
+import org.opsli.plugins.redisson.RedissonLock;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * @Description: Redisson分布式锁注解解析器
+ *
+ * @author xub
+ * @date 2019/6/20 下午9:34
+ */
+@Aspect
+@Component
+@Slf4j
+public class DistributedLockHandler {
+
+ @Autowired
+ private RedissonLock redissonLock;
+
+ @Around("@annotation(distributedLock)")
+ public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
+ Object returnValue = null;
+
+ log.info("[开始]执行RedisLock环绕通知,获取Redis分布式锁开始");
+ //获取锁名称
+ String lockName = distributedLock.value();
+ //获取超时时间,默认10秒
+ int leaseTime = distributedLock.leaseTime();
+ redissonLock.lock(lockName, leaseTime);
+ try {
+ log.info("获取Redis分布式锁[成功],加锁完成,开始执行业务逻辑...");
+ returnValue = joinPoint.proceed();
+ } catch (Throwable throwable) {
+ log.error("获取Redis分布式锁[异常],加锁失败", throwable);
+ throwable.printStackTrace();
+ } finally {
+ //如果该线程还持有该锁,那么释放该锁。如果该线程不持有该锁,说明该线程的锁已到过期时间,自动释放锁
+ if (redissonLock.isHeldByCurrentThread(lockName)) {
+ redissonLock.unlock(lockName);
+ }
+ }
+ log.info("释放Redis分布式锁[成功],解锁完成,结束业务逻辑...");
+
+ return returnValue;
+ }
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/constant/GlobalConstant.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/constant/GlobalConstant.java
new file mode 100644
index 0000000..99a4b73
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/constant/GlobalConstant.java
@@ -0,0 +1,29 @@
+package org.opsli.plugins.redisson.constant;
+
+
+/**
+ * @author xub
+ * @Description: 全局常量枚举 用来拼接完整的URL
+ * @date 2019/6/19 下午9:09
+ */
+public enum GlobalConstant {
+
+ /** 前缀 */
+ REDIS_CONNECTION_PREFIX("redis://", "Redis地址配置前缀");
+
+ private final String constant_value;
+ private final String constant_desc;
+
+ GlobalConstant(String constant_value, String constant_desc) {
+ this.constant_value = constant_value;
+ this.constant_desc = constant_desc;
+ }
+
+ public String getConstant_value() {
+ return constant_value;
+ }
+
+ public String getConstant_desc() {
+ return constant_desc;
+ }
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/entity/RedissonProperties.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/entity/RedissonProperties.java
new file mode 100644
index 0000000..f68a7bf
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/entity/RedissonProperties.java
@@ -0,0 +1,56 @@
+package org.opsli.plugins.redisson.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @Description: 读取redis配置信息,封装到当前实体中
+ *
+ * @author xub
+ * @date 2019/6/19 下午9:35
+ */
+@ConfigurationProperties(prefix = "redisson.lock.server")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class RedissonProperties {
+
+ /**
+ * 是否启用
+ */
+ private boolean enable;
+
+ /**
+ * redis主机地址,ip:port,有多个用半角逗号分隔
+ */
+ private String address;
+
+ /**
+ * 连接类型,支持standalone-单机节点,sentinel-哨兵,cluster-集群,masterslave-主从
+ */
+ private RedissonType type = RedissonType.STANDALONE;
+
+ /**
+ * redis 连接密码
+ */
+ private String password;
+
+ /**
+ * 选取那个数据库
+ */
+ private int database;
+
+ public RedissonProperties setPassword(String password) {
+ this.password = password;
+ return this;
+ }
+
+ public RedissonProperties setDatabase(int database) {
+ this.database = database;
+ return this;
+ }
+
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/enums/RedissonType.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/enums/RedissonType.java
new file mode 100644
index 0000000..92cd610
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/enums/RedissonType.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.plugins.redisson.enums;
+
+
+/**
+ * @BelongsProject: opsli-boot
+ * @BelongsPackage: org.opsli.common.enums
+ * @Author: Parker
+ * @CreateTime: 2020-09-17 23:40
+ * @Description: Redisson 类型
+ */
+public enum RedissonType {
+
+ /** 类型 */
+ STANDALONE("standalone", "单节点部署方式"),
+ SENTINEL("sentinel", "哨兵部署方式"),
+ CLUSTER("cluster", "集群方式"),
+ MASTER_SLAVE("master_slave", "主从部署方式");
+
+ ;
+
+
+ private final String type;
+ private final String desc;
+
+ public static RedissonType getType(String type) {
+ RedissonType[] var1 = values();
+ int var2 = var1.length;
+
+ for (RedissonType e : var1) {
+ if (e.type.equalsIgnoreCase(type)) {
+ return e;
+ }
+ }
+
+ return null;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public String getDesc() {
+ return this.desc;
+ }
+
+ // ================
+
+ RedissonType(final String type, final String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/RedissonConfigService.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/RedissonConfigService.java
new file mode 100644
index 0000000..9827d9a
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/RedissonConfigService.java
@@ -0,0 +1,28 @@
+package org.opsli.plugins.redisson.strategy;
+
+
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.redisson.config.Config;
+
+/**
+ * @Description: Redisson配置构建接口
+ *
+ * @author xub
+ * @date 2019/6/20 下午3:35
+ */
+public interface RedissonConfigService {
+
+ /**
+ * 获得类型
+ * @return type
+ */
+ RedissonType getType();
+
+ /**
+ * 根据不同的Redis配置策略创建对应的Config
+ * @param redissonProperties
+ * @return Config
+ */
+ Config createRedissonConfig(RedissonProperties redissonProperties);
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/ClusterConfigImpl.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/ClusterConfigImpl.java
new file mode 100644
index 0000000..de3bf7a
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/ClusterConfigImpl.java
@@ -0,0 +1,51 @@
+package org.opsli.plugins.redisson.strategy.impl;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.opsli.plugins.redisson.constant.GlobalConstant;
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.opsli.plugins.redisson.strategy.RedissonConfigService;
+import org.redisson.config.Config;
+
+/**
+ * @Description: 集群方式Redisson部署
+ * 地址格式:
+ * cluster方式至少6个节点(3主3从,3主做sharding,3从用来保证主宕机后可以高可用)
+ * 格式为: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
+ *
+ * @author xub
+ * @date 2019/6/19 下午4:24
+ */
+@Slf4j
+public class ClusterConfigImpl implements RedissonConfigService {
+
+ @Override
+ public RedissonType getType() {
+ return RedissonType.CLUSTER;
+ }
+
+ @Override
+ public Config createRedissonConfig(RedissonProperties redissonProperties) {
+ Config config = new Config();
+ try {
+ String address = redissonProperties.getAddress();
+ String password = redissonProperties.getPassword();
+ String[] addrTokens = address.split(",");
+ //设置cluster节点的服务IP和端口
+ for (String addrToken : addrTokens) {
+ config.useClusterServers()
+ .addNodeAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrToken);
+ if (StringUtils.isNotBlank(password)) {
+ config.useClusterServers().setPassword(password);
+ }
+ }
+ log.info("初始化[集群部署]方式Config,redisAddress:" + address);
+ } catch (Exception e) {
+ log.error("集群部署 Redisson init error", e);
+ e.printStackTrace();
+ }
+ return config;
+ }
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/MasterslaveConfigImpl.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/MasterslaveConfigImpl.java
new file mode 100644
index 0000000..1f3b2e6
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/MasterslaveConfigImpl.java
@@ -0,0 +1,65 @@
+package org.opsli.plugins.redisson.strategy.impl;
+
+
+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.plugins.redisson.constant.GlobalConstant;
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.opsli.plugins.redisson.strategy.RedissonConfigService;
+import org.redisson.config.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Description: 主从部署Redisson配置
+ * 连接方式: 主节点,子节点,子节点
+ * 格式为: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381
+ * @author xub
+ * @date 2019/6/19 下午9:21
+ */
+
+@Slf4j
+public class MasterslaveConfigImpl implements RedissonConfigService {
+
+ @Override
+ public RedissonType getType() {
+ return RedissonType.MASTER_SLAVE;
+ }
+
+ @Override
+ public Config createRedissonConfig(RedissonProperties redissonProperties) {
+ Config config = new Config();
+ try {
+ String address = redissonProperties.getAddress();
+ String password = redissonProperties.getPassword();
+ int database = redissonProperties.getDatabase();
+ String[] addrTokens = address.split(",");
+ String masterNodeAddr = addrTokens[0];
+ //设置主节点ip
+ config.useMasterSlaveServers().setMasterAddress(masterNodeAddr);
+ if (StringUtils.isNotBlank(password)) {
+ config.useMasterSlaveServers().setPassword(password);
+ }
+ config.useMasterSlaveServers().setDatabase(database);
+ //设置从节点,移除第一个节点,默认第一个为主节点
+ List slaveList = Lists.newArrayList();
+ for (String addrToken : addrTokens) {
+ slaveList.add(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrToken);
+ }
+ slaveList.remove(0);
+
+ config.useMasterSlaveServers().addSlaveAddress(
+ Convert.toStrArray(slaveList));
+ log.info("初始化[主从部署]方式Config,redisAddress:" + address);
+ } catch (Exception e) {
+ log.error("主从部署 Redisson init error", e);
+ e.printStackTrace();
+ }
+ return config;
+ }
+
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/SentinelConfigImpl.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/SentinelConfigImpl.java
new file mode 100644
index 0000000..b2ba29f
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/SentinelConfigImpl.java
@@ -0,0 +1,53 @@
+package org.opsli.plugins.redisson.strategy.impl;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.opsli.plugins.redisson.constant.GlobalConstant;
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.opsli.plugins.redisson.strategy.RedissonConfigService;
+import org.redisson.config.Config;
+
+
+/**
+ * @Description: 哨兵集群部署Redis连接配置
+ *
+ * @author xub
+ * @date 2019/6/19 下午9:17
+ */
+@Slf4j
+public class SentinelConfigImpl implements RedissonConfigService {
+
+ @Override
+ public RedissonType getType() {
+ return RedissonType.SENTINEL;
+ }
+
+ @Override
+ public Config createRedissonConfig(RedissonProperties redissonProperties) {
+ Config config = new Config();
+ try {
+ String address = redissonProperties.getAddress();
+ String password = redissonProperties.getPassword();
+ int database = redissonProperties.getDatabase();
+ String[] addrTokens = address.split(",");
+ String sentinelAliasName = addrTokens[0];
+ //设置redis配置文件sentinel.conf配置的sentinel别名
+ config.useSentinelServers().setMasterName(sentinelAliasName);
+ config.useSentinelServers().setDatabase(database);
+ if (StringUtils.isNotBlank(password)) {
+ config.useSentinelServers().setPassword(password);
+ }
+ //设置sentinel节点的服务IP和端口
+ for (int i = 1; i < addrTokens.length; i++) {
+ config.useSentinelServers().addSentinelAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrTokens[i]);
+ }
+ log.info("初始化[哨兵部署]方式Config,redisAddress:" + address);
+ } catch (Exception e) {
+ log.error("哨兵部署 Redisson init error", e);
+
+ }
+ return config;
+ }
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/StandaloneConfigImpl.java b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/StandaloneConfigImpl.java
new file mode 100644
index 0000000..70b648d
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/java/org/opsli/plugins/redisson/strategy/impl/StandaloneConfigImpl.java
@@ -0,0 +1,47 @@
+package org.opsli.plugins.redisson.strategy.impl;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.opsli.plugins.redisson.constant.GlobalConstant;
+import org.opsli.plugins.redisson.entity.RedissonProperties;
+import org.opsli.plugins.redisson.enums.RedissonType;
+import org.opsli.plugins.redisson.strategy.RedissonConfigService;
+import org.redisson.config.Config;
+
+/**
+ * @Description: 单机部署Redisson配置
+ *
+ * @author xub
+ * @date 2019/6/19 下午10:04
+ */
+@Slf4j
+public class StandaloneConfigImpl implements RedissonConfigService {
+
+ @Override
+ public RedissonType getType() {
+ return RedissonType.STANDALONE;
+ }
+
+
+ @Override
+ public Config createRedissonConfig(RedissonProperties redissonProperties) {
+ Config config = new Config();
+ try {
+ String address = redissonProperties.getAddress();
+ String password = redissonProperties.getPassword();
+ int database = redissonProperties.getDatabase();
+ String redisAddr = GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + address;
+ config.useSingleServer().setAddress(redisAddr);
+ config.useSingleServer().setDatabase(database);
+ //密码可以为空
+ if (StringUtils.isNotBlank(password)) {
+ config.useSingleServer().setPassword(password);
+ }
+ log.info("初始化[单机部署]方式Config,redisAddress:" + address);
+ } catch (Exception e) {
+ log.error("单机部署 Redisson init error", e);
+ }
+ return config;
+ }
+}
diff --git a/opsli-plugins/opsli-plugins-redisson/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/opsli-plugins/opsli-plugins-redisson/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 0000000..180c941
--- /dev/null
+++ b/opsli-plugins/opsli-plugins-redisson/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,36 @@
+{
+ "properties": [
+ {
+ "name": "redisson.lock.server.enable",
+ "sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties",
+ "type": "java.lang.Boolean",
+ "defaultValue": false,
+ "description": "redissonLock 是否启用."
+ },
+ {
+ "name": "redisson.lock.server.address",
+ "sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties",
+ "type": "java.lang.String",
+ "defaultValue": "127.0.0.1:6379",
+ "description": "redis主机地址,ip:port,有多个用半角逗号分隔."
+ },
+ {
+ "name": "redisson.lock.server.type",
+ "sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties",
+ "description": "连接类型,支持standalone-单机节点,sentinel-哨兵,cluster-集群,masterslave-主从."
+ },
+ {
+ "name": "redisson.lock.server.password",
+ "sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties",
+ "type": "java.lang.String",
+ "description": "redis 连接密码."
+ },
+ {
+ "name": "redisson.lock.server.database",
+ "sourceType": "org.opsli.plugins.redisson.entity.RedissonProperties",
+ "type": "java.lang.Integer",
+ "defaultValue": 0,
+ "description": "选取那个数据库 ."
+ }
+ ]
+}
diff --git a/opsli-plugins/pom.xml b/opsli-plugins/pom.xml
index 57afe84..57f2a6a 100644
--- a/opsli-plugins/pom.xml
+++ b/opsli-plugins/pom.xml
@@ -20,6 +20,7 @@
opsli-plugins-redis
opsli-plugins-ehcache
opsli-plugins-excel
+ opsli-plugins-redisson
diff --git a/opsli-starter/src/main/resources/application-beta.yaml b/opsli-starter/src/main/resources/application-beta.yaml
index 1fce5ee..88aa0fa 100644
--- a/opsli-starter/src/main/resources/application-beta.yaml
+++ b/opsli-starter/src/main/resources/application-beta.yaml
@@ -44,6 +44,15 @@ spring:
#password: 12345678
#driver-class-name: com.mysql.cj.jdbc.Driver
+# Redisson 分布式锁
+redisson:
+ lock:
+ server:
+ enable: true
+ type: standalone
+ address: "127.0.0.1:6379"
+ password: 123456
+ database: 0
# knife4j 文档 配置
knife4j:
@@ -59,7 +68,6 @@ knife4j:
production: false
-
# opsli 自定义配置
opsli:
# 演示模式
@@ -71,3 +79,4 @@ opsli:
# 系统日志
log:
path: /var/log
+
diff --git a/opsli-starter/src/main/resources/application-release.yaml b/opsli-starter/src/main/resources/application-release.yaml
index 7c67bfa..1c79f77 100644
--- a/opsli-starter/src/main/resources/application-release.yaml
+++ b/opsli-starter/src/main/resources/application-release.yaml
@@ -44,6 +44,15 @@ spring:
#password: 12345678
#driver-class-name: com.mysql.cj.jdbc.Driver
+# Redisson 分布式锁
+redisson:
+ lock:
+ server:
+ enable: true
+ type: standalone
+ address: "127.0.0.1:6379"
+ password: 123456
+ database: 0
# knife4j 文档 配置
knife4j:
diff --git a/pom.xml b/pom.xml
index 0ad7dcc..159fdb4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -116,6 +116,13 @@
${jwt.version}
+
+