微服务重大升级说明(暂时只升级后台3.4.0)

-升级Spring Cloud Alibaba 2021.0.1.0,使用 spring.config.import 方式引入nacos配置
-拆分jeecg-boot-starter出来,使用独立项目维护
This commit is contained in:
zhangdaiscott
2022-08-06 17:02:37 +08:00
parent d4bc1439ad
commit 12c4c8cf9a
158 changed files with 625 additions and 5645 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-base</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -4,37 +4,17 @@
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base</artifactId>
<version>3.3.0</version>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-base-core</artifactId>
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun Repository</name>
<url>https://maven.aliyun.com/repository/public</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>jeecg</id>
<name>jeecg Repository</name>
<url>https://maven.jeecg.org/nexus/content/repositories/jeecg</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<!--jeecg-tools-->
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-tools</artifactId>
<artifactId>jeecg-boot-common</artifactId>
</dependency>
<!--集成springmvc框架并实现自动配置 -->
<dependency>

View File

@ -304,16 +304,21 @@ public interface CommonConstant {
String WPS_TYPE_2="2";
/**===============================================================================================*/
/**
* ::非常重要::
* 注意:这四个常量值如果修改,需要与 jeecg-boot-starter/jeecg-boot-common/org.jeecg.config.FeignConfig 类中的值保持一致。
*/
String X_ACCESS_TOKEN = "X-Access-Token";
String X_SIGN = "X-Sign";
String X_TIMESTAMP = "X-TIMESTAMP";
/** 租户 请求头*/
String TENANT_ID = "tenant-id";
/**===============================================================================================*/
String TOKEN_IS_INVALID_MSG = "Token失效请重新登录!";
String X_FORWARDED_SCHEME = "X-Forwarded-Scheme";
/**
* 多租户 请求头
*/
String TENANT_ID = "tenant-id";
/**
* 微服务读取配置文件属性 服务地址

View File

@ -1,96 +0,0 @@
package org.jeecg.common.util;
import java.util.Collection;
import java.util.Map;
import org.springframework.util.AntPathMatcher;
/**
* 使用Spring自身提供的地址匹配工具匹配URL
* @author: jeecg-boot
*/
public class PathMatcherUtil {
public static void main(String[] args) {
String url = "/sys/dict/loadDictOrderByValue/tree,s2,2";
String p = "/sys/dict/loadDictOrderByValue/*";
System.out.println(PathMatcherUtil.match(p,url));
}
/**
* 实际验证路径匹配权限
*
* @param matchPath 权限url
* @param path 访问路径
* @return 是否拥有权限
*/
public static boolean match(String matchPath, String path) {
SpringAntMatcher springAntMatcher = new SpringAntMatcher(matchPath, true);
return springAntMatcher.matches(path);
}
/**
* 实际验证路径匹配权限
*
* @param list 权限url
* @param path 访问路径
* @return 是否拥有权限
*/
public static boolean matches(Collection<String> list, String path) {
for (String s : list) {
SpringAntMatcher springAntMatcher = new SpringAntMatcher(s, true);
if (springAntMatcher.matches(path)) {
return true;
}
}
return false;
}
/**
* 地址表达式匹配工具
*/
private static class SpringAntMatcher implements Matcher {
private final AntPathMatcher antMatcher;
private final String pattern;
private SpringAntMatcher(String pattern, boolean caseSensitive) {
this.pattern = pattern;
this.antMatcher = createMatcher(caseSensitive);
}
@Override
public boolean matches(String path) {
return this.antMatcher.match(this.pattern, path);
}
@Override
public Map<String, String> extractUriTemplateVariables(String path) {
return this.antMatcher.extractUriTemplateVariables(this.pattern, path);
}
private static AntPathMatcher createMatcher(boolean caseSensitive) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setTrimTokens(false);
matcher.setCaseSensitive(caseSensitive);
return matcher;
}
}
private interface Matcher {
/**
* 实际验证路径匹配权限
* @param var1
* @return
*/
boolean matches(String var1);
/**
* 提取path中匹配到的部分
* @param var1
* @return
*/
Map<String, String> extractUriTemplateVariables(String var1);
}
}

View File

@ -19,6 +19,10 @@ public class JeecgBaseConfig {
* @TODO 降低使用成本加的默认值,实际以 yml配置 为准
*/
private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
/**
* 需要加强校验的接口清单
*/
private String signUrls;
/**
* 是否启用安全模式
@ -79,4 +83,12 @@ public class JeecgBaseConfig {
public void setDomainUrl(DomainUrl domainUrl) {
this.domainUrl = domainUrl;
}
public String getSignUrls() {
return signUrls;
}
public void setSignUrls(String signUrls) {
this.signUrls = signUrls;
}
}

View File

@ -45,11 +45,9 @@ import java.util.List;
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Value("${jeecg.path.upload}")
private String upLoadPath;
@Value("${jeecg.path.webapp}")
private String webAppPath;
@Value("${spring.resource.static-locations}")
@Autowired
JeecgBaseConfig jeecgBaseConfig;
@Value("${spring.resource.static-locations:}")
private String staticLocations;
@Autowired(required = false)
@ -62,8 +60,8 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
//update-begin-author:taoyan date:20211116 for: jeecg.path.webapp配置无效 #3126
.addResourceLocations("file:" + upLoadPath + "//")
.addResourceLocations("file:" + webAppPath + "//")
.addResourceLocations("file:" + jeecgBaseConfig.getPath().getUpload() + "//")
.addResourceLocations("file:" + jeecgBaseConfig.getPath().getWebapp() + "//")
//update-end-author:taoyan date:20211116 for: jeecg.path.webapp配置无效 #3126
.addResourceLocations(staticLocations.split(","));
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.oConvertUtils;
import org.mybatis.spring.annotation.MapperScan;

View File

@ -1,25 +1,25 @@
package org.jeecg.config.mybatis;
import lombok.extern.slf4j.Slf4j;
/**
* 多租户 tenant_id存储器
* @author: jeecg-boot
*/
@Slf4j
public class TenantContext {
private static ThreadLocal<String> currentTenant = new ThreadLocal<>();
public static void setTenant(String tenant) {
log.debug(" setting tenant to " + tenant);
currentTenant.set(tenant);
}
public static String getTenant() {
return currentTenant.get();
}
public static void clear(){
currentTenant.remove();
}
}
//package org.jeecg.config.mybatis;
//
//import lombok.extern.slf4j.Slf4j;
//
///**
// * 多租户 tenant_id存储器
// * @author: jeecg-boot
// */
//@Slf4j
//public class TenantContext {
// private static ThreadLocal<String> currentTenant = new ThreadLocal<>();
//
// public static void setTenant(String tenant) {
// log.debug(" setting tenant to " + tenant);
// currentTenant.set(tenant);
// }
//
// public static String getTenant() {
// return currentTenant.get();
// }
//
// public static void clear(){
// currentTenant.remove();
// }
//}

View File

@ -10,6 +10,7 @@ import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
@ -17,7 +18,6 @@ import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.TenantContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

View File

@ -3,10 +3,10 @@ package org.jeecg.config.shiro.filters;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.TenantContext;
import org.jeecg.config.shiro.JwtToken;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;

View File

@ -1,5 +1,9 @@
package org.jeecg.config.sign.interceptor;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.PathMatcherUtil;
import org.jeecg.common.util.SpringContextHolder;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.filter.RequestBodyReserveFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@ -7,16 +11,19 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
/**
* 签名 拦截器配置
* @author: jeecg-boot
*/
@Configuration
public class SignAuthConfiguration implements WebMvcConfigurer {
public static String[] SIGN_URL_LIST = new String[]{"/sys/dict/getDictItems/*", "/sys/dict/loadDict/*",
"/sys/dict/loadDictOrderByValue/*", "/sys/dict/loadDictItem/*", "/sys/dict/loadTreeData",
"/sys/api/queryTableDictItemsByCode", "/sys/api/queryFilterTableDictInfo", "/sys/api/queryTableDictByKeys",
"/sys/api/translateDictFromTable", "/sys/api/translateDictFromTableByKeys"};
@Resource
JeecgBaseConfig jeecgBaseConfig;
@Bean
public SignAuthInterceptor signAuthInterceptor() {
return new SignAuthInterceptor();
@ -24,7 +31,17 @@ public class SignAuthConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(signAuthInterceptor()).addPathPatterns(SIGN_URL_LIST);
//------------------------------------------------------------
//查询需要进行签名拦截的接口 signUrls
String signUrls = jeecgBaseConfig.getSignUrls();
String[] signUrlsArray = null;
if (StringUtils.isNotBlank(signUrls)) {
signUrlsArray = signUrls.split(",");
} else {
signUrlsArray = PathMatcherUtil.SIGN_URL_LIST;
}
//------------------------------------------------------------
registry.addInterceptor(signAuthInterceptor()).addPathPatterns(signUrlsArray);
}
//update-begin-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空
@ -38,8 +55,18 @@ public class SignAuthConfiguration implements WebMvcConfigurer {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(requestBodyReserveFilter());
registration.setName("requestBodyReserveFilter");
//------------------------------------------------------------
//查询需要进行签名拦截的接口 signUrls
String signUrls = jeecgBaseConfig.getSignUrls();
String[] signUrlsArray = null;
if (StringUtils.isNotBlank(signUrls)) {
signUrlsArray = signUrls.split(",");
} else {
signUrlsArray = PathMatcherUtil.SIGN_URL_LIST;
}
//------------------------------------------------------------
// 建议此处只添加post请求地址而不是所有的都需要走过滤器
registration.addUrlPatterns(SIGN_URL_LIST);
registration.addUrlPatterns(signUrlsArray);
return registration;
}
//update-end-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空

View File

@ -1,45 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base</artifactId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<description>公共模块</description>
<artifactId>jeecg-boot-base-tools</artifactId>
<dependencies>
<!--集成springmvc框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--加载hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-crypto</artifactId>
</dependency>
<!--加载beanutils-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,23 +0,0 @@
package org.jeecg.common.annotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* @Author:zyf
* @Date:2019-07-31 10:43
* @Description: 消息队列初始化注解
**/
@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface RabbitComponent {
@AliasFor(
annotation = Component.class
)
String value();
}

View File

@ -1,144 +0,0 @@
package org.jeecg.common.base;
import cn.hutool.core.util.ObjectUtil;
import org.apache.commons.beanutils.ConvertUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* BaseMap
*
* @author: scott
* @date: 2020/01/01 16:17
*/
public class BaseMap extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public BaseMap() {
}
public BaseMap(Map<String, Object> map) {
this.putAll(map);
}
@Override
public BaseMap put(String key, Object value) {
super.put(key, Optional.ofNullable(value).orElse(""));
return this;
}
public BaseMap add(String key, Object value) {
super.put(key, Optional.ofNullable(value).orElse(""));
return this;
}
@SuppressWarnings("unchecked")
public <T> T get(String key) {
Object obj = super.get(key);
if (ObjectUtil.isNotEmpty(obj)) {
return (T) obj;
} else {
return null;
}
}
@SuppressWarnings("unchecked")
public Boolean getBoolean(String key) {
Object obj = super.get(key);
if (ObjectUtil.isNotEmpty(obj)) {
return Boolean.valueOf(obj.toString());
} else {
return false;
}
}
public Long getLong(String key) {
Object v = get(key);
if (ObjectUtil.isNotEmpty(v)) {
return new Long(v.toString());
}
return null;
}
public Long[] getLongs(String key) {
Object v = get(key);
if (ObjectUtil.isNotEmpty(v)) {
return (Long[]) v;
}
return null;
}
public List<Long> getListLong(String key) {
List<String> list = get(key);
if (ObjectUtil.isNotEmpty(list)) {
return list.stream().map(e -> new Long(e)).collect(Collectors.toList());
} else {
return null;
}
}
public Long[] getLongIds(String key) {
Object ids = get(key);
if (ObjectUtil.isNotEmpty(ids)) {
return (Long[]) ConvertUtils.convert(ids.toString().split(","), Long.class);
} else {
return null;
}
}
public Integer getInt(String key, Integer def) {
Object v = get(key);
if (ObjectUtil.isNotEmpty(v)) {
return Integer.parseInt(v.toString());
} else {
return def;
}
}
public Integer getInt(String key) {
Object v = get(key);
if (ObjectUtil.isNotEmpty(v)) {
return Integer.parseInt(v.toString());
} else {
return 0;
}
}
public BigDecimal getBigDecimal(String key) {
Object v = get(key);
if (ObjectUtil.isNotEmpty(v)) {
return new BigDecimal(v.toString());
}
return new BigDecimal("0");
}
@SuppressWarnings("unchecked")
public <T> T get(String key, T def) {
Object obj = super.get(key);
if (ObjectUtil.isEmpty(obj)) {
return def;
}
return (T) obj;
}
public static BaseMap toBaseMap(Map<String, Object> obj) {
BaseMap map = new BaseMap();
map.putAll(obj);
return map;
}
}

View File

@ -1,27 +0,0 @@
package org.jeecg.common.config;
import org.jeecg.common.util.SpringContextHolder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* SpringContextHolder注册用
*
* @author: scott
* @date: 2020/01/01 16:00
*/
@Configuration
public class CommonConfig {
/**
* Spring上下文工具配置
*
* @return
*/
@Bean
@ConditionalOnMissingBean(SpringContextHolder.class)
public SpringContextHolder springContextHolder() {
SpringContextHolder holder = new SpringContextHolder();
return holder;
}
}

View File

@ -1,46 +0,0 @@
package org.jeecg.common.config.mqtoken;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
/**
* 存放临时令牌Token到线程上下文
*
* 供队列、定时任务 feign调用使用解决无会话Token问题
* @author zyf
*/
public class TransmitUserTokenFilter implements Filter {
private static String X_ACCESS_TOKEN="X-Access-Token";
public TransmitUserTokenFilter() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
this.initUserInfo((HttpServletRequest) request);
chain.doFilter(request, response);
}
private void initUserInfo(HttpServletRequest request) {
String token = request.getHeader(X_ACCESS_TOKEN);
if (token!=null) {
try {
//将Token放入当前线程上下文中
UserTokenContext.setToken(token);
} catch (Exception e) {
//e.printStackTrace();
}
}
}
@Override
public void destroy() {
}
}

View File

@ -1,31 +0,0 @@
package org.jeecg.common.config.mqtoken;
/**
* 用户Token线程上下文
*
* 供队列、定时任务 feign调用使用解决无会话Token问题
* @author zyf
*/
public class UserTokenContext {
/**
* 当前线程的TOKEN副本
*/
private static ThreadLocal<String> userToken = new ThreadLocal<String>();
public UserTokenContext() {
}
public static String getToken(){
return userToken.get();
}
public static void setToken(String token){
userToken.set(token);
}
public static void remove() {
userToken.remove();
}
}

View File

@ -1,103 +0,0 @@
package org.jeecg.common.constant;
/**
* @author: huangxutao
* @date: 2019-06-14
* @description: 缓存常量
*/
public interface CacheConstant {
/**
* 字典信息缓存(含禁用的字典项)
*/
public static final String SYS_DICT_CACHE = "sys:cache:dict";
/**
* 字典信息缓存 status为有效的
*/
public static final String SYS_ENABLE_DICT_CACHE = "sys:cache:dictEnable";
/**
* 表字典信息缓存
*/
public static final String SYS_DICT_TABLE_CACHE = "sys:cache:dictTable";
public static final String SYS_DICT_TABLE_BY_KEYS_CACHE = SYS_DICT_TABLE_CACHE + "ByKeys";
/**
* 数据权限配置缓存
*/
public static final String SYS_DATA_PERMISSIONS_CACHE = "sys:cache:permission:datarules";
/**
* 缓存用户信息【加密】
*/
public static final String SYS_USERS_CACHE = "sys:cache:encrypt:user";
/**
* 全部部门信息缓存
*/
public static final String SYS_DEPARTS_CACHE = "sys:cache:depart:alldata";
/**
* 全部部门ids缓存
*/
public static final String SYS_DEPART_IDS_CACHE = "sys:cache:depart:allids";
/**
* 测试缓存key
*/
public static final String TEST_DEMO_CACHE = "test:demo";
/**
* 字典信息缓存
*/
public static final String SYS_DYNAMICDB_CACHE = "sys:cache:dbconnect:dynamic:";
/**
* gateway路由缓存
*/
public static final String GATEWAY_ROUTES = "sys:cache:cloud:gateway_routes";
/**
* gateway路由 reload key
*/
public static final String ROUTE_JVM_RELOAD_TOPIC = "gateway_jvm_route_reload_topic";
/**
* TODO 冗余代码 待删除
*插件商城排行榜
*/
public static final String PLUGIN_MALL_RANKING = "pluginMall::rankingList";
/**
* TODO 冗余代码 待删除
*插件商城排行榜
*/
public static final String PLUGIN_MALL_PAGE_LIST = "pluginMall::queryPageList";
/**
* online列表页配置信息缓存key
*/
public static final String ONLINE_LIST = "sys:cache:online:list";
/**
* online表单页配置信息缓存key
*/
public static final String ONLINE_FORM = "sys:cache:online:form";
/**
* online报表
*/
public static final String ONLINE_RP = "sys:cache:online:rp";
/**
* online图表
*/
public static final String ONLINE_GRAPH = "sys:cache:online:graph";
/**
* 拖拽页面信息缓存
*/
public static final String DRAG_PAGE_CACHE = "drag:cache:page";
}

View File

@ -1,23 +0,0 @@
package org.jeecg.common.constant;
/**
* @Description: GlobalConstants
* @author: scott
* @date: 2020/01/01 16:01
*/
public class GlobalConstants {
/**
* 业务处理器beanName传递参数
*/
public static final String HANDLER_NAME = "handlerName";
/**
* 路由刷新触发器
*/
public static final String LODER_ROUDER_HANDLER = "loderRouderHandler";
/**
* redis消息通道名称
*/
public static final String REDIS_TOPIC_NAME="jeecg_redis_topic";
}

View File

@ -1,108 +0,0 @@
package org.jeecg.common.enums;
/**
* @Description: 异常错误信息定义
* @author: zyf
* @date: 2022/4/14 10:05
*/
public enum SentinelErrorInfoEnum {
/**
* 流控异常
*/
FlowException("访问频繁,请稍候再试"),
/**
* 热点参数异常
*/
ParamFlowException("热点参数限流"),
/**
* 系统规则限流或降级
*/
SystemBlockException("系统规则限流或降级"),
/**
* 授权规则不通过
*/
AuthorityException("授权规则不通过"),
/**
* 授权规则不通过
*/
UnknownError("未知异常"),
/**
* 服务降级
*/
DegradeException("服务降级");
/**
* 错误信息
*/
String error;
/**
* 错误代码
*/
Integer code;
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
/**
* 构造器
*
* @param error 错误信息
* @param code 错误代码
*/
SentinelErrorInfoEnum(String error, Integer code) {
this.error = error;
this.code = code;
}
/**
* 构造器
*
* @param error 错误信息
*/
SentinelErrorInfoEnum(String error) {
this.error = error;
this.code = 500;
}
/**
* 根据异常名称匹配
*
* @param throwable 异常
* @return String 错误信息
*/
public static SentinelErrorInfoEnum getErrorByException(Throwable throwable) {
if(throwable==null){
return null;
}
String exceptionClass = throwable.getClass().getSimpleName();
for (SentinelErrorInfoEnum e : SentinelErrorInfoEnum.values()) {
if (exceptionClass.equals(e.name())) {
return e;
}
}
return null;
}
}

View File

@ -1,15 +0,0 @@
package org.jeecg.common.exception;
/**
* @Description: jeecg-cloud自定义异常
* @Author: zyf
* @Date: 2022-05-30
*/
public class JeecgCloudException extends RuntimeException {
private static final long serialVersionUID = 1L;
public JeecgCloudException(String message) {
super(message);
}
}

View File

@ -1,34 +0,0 @@
package org.jeecg.common.modules.redis.client;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.constant.GlobalConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
/**
* @Description: redis客户端
* @author: scott
* @date: 2020/01/01 16:01
*/
@Configuration
public class JeecgRedisClient {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 发送消息
*
* @param handlerName
* @param params
*/
public void sendMessage(String handlerName, BaseMap params) {
params.put(GlobalConstants.HANDLER_NAME, handlerName);
redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
}
}

View File

@ -1,141 +0,0 @@
package org.jeecg.common.modules.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.GlobalConstants;
import org.jeecg.common.modules.redis.receiver.RedisReceiver;
import org.jeecg.common.modules.redis.writer.JeecgRedisCacheWriter;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.*;
import javax.annotation.Resource;
import java.time.Duration;
import static java.util.Collections.singletonMap;
/**
* 开启缓存支持
* @author zyf
* @Return:
*/
@Slf4j
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Resource
private LettuceConnectionFactory lettuceConnectionFactory;
/**
* RedisTemplate配置
* @param lettuceConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
log.info(" --- redis config init --- ");
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jacksonSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
// key序列化
redisTemplate.setKeySerializer(stringSerializer);
// value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 缓存配置管理器
*
* @param factory
* @return
*/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jacksonSerializer();
// 配置序列化(解决乱码的问题),并且配置缓存默认有效期 6小时
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(6));
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
//.disableCachingNullValues();
// 以锁写入的方式创建RedisCacheWriter对象
//update-begin-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*
RedisCacheWriter writer = new JeecgRedisCacheWriter(factory, Duration.ofMillis(50L));
//RedisCacheWriter.lockingRedisCacheWriter(factory);
// 创建默认缓存配置对象
/* 默认配置,设置缓存有效期 1小时*/
//RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
// 自定义配置test:demo 的超时时间为 5分钟
RedisCacheManager cacheManager = RedisCacheManager.builder(writer).cacheDefaults(redisCacheConfiguration)
.withInitialCacheConfigurations(singletonMap(CacheConstant.SYS_DICT_TABLE_CACHE,
RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)).disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))))
.withInitialCacheConfigurations(singletonMap(CacheConstant.TEST_DEMO_CACHE, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).disableCachingNullValues()))
.withInitialCacheConfigurations(singletonMap(CacheConstant.PLUGIN_MALL_RANKING, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(24)).disableCachingNullValues()))
.withInitialCacheConfigurations(singletonMap(CacheConstant.PLUGIN_MALL_PAGE_LIST, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(24)).disableCachingNullValues()))
.transactionAware().build();
//update-end-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*
return cacheManager;
}
/**
* redis 监听配置
*
* @param redisConnectionFactory redis 配置
* @return
*/
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory, RedisReceiver redisReceiver, MessageListenerAdapter commonListenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener(commonListenerAdapter, new ChannelTopic(GlobalConstants.REDIS_TOPIC_NAME));
return container;
}
@Bean
MessageListenerAdapter commonListenerAdapter(RedisReceiver redisReceiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "onMessage");
messageListenerAdapter.setSerializer(jacksonSerializer());
return messageListenerAdapter;
}
private Jackson2JsonRedisSerializer jacksonSerializer() {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
}

View File

@ -1,18 +0,0 @@
package org.jeecg.common.modules.redis.listener;
import org.jeecg.common.base.BaseMap;
/**
* @Description: 自定义消息监听
* @author: scott
* @date: 2020/01/01 16:02
*/
public interface JeecgRedisListener {
/**
* 接受消息
*
* @param message
*/
void onMessage(BaseMap message);
}

View File

@ -1,33 +0,0 @@
package org.jeecg.common.modules.redis.receiver;
import cn.hutool.core.util.ObjectUtil;
import lombok.Data;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.constant.GlobalConstants;
import org.jeecg.common.modules.redis.listener.JeecgRedisListener;
import org.jeecg.common.util.SpringContextHolder;
import org.springframework.stereotype.Component;
/**
* @author zyf
*/
@Component
@Data
public class RedisReceiver {
/**
* 接受消息并调用业务逻辑处理器
*
* @param params
*/
public void onMessage(BaseMap params) {
Object handlerName = params.get(GlobalConstants.HANDLER_NAME);
JeecgRedisListener messageListener = SpringContextHolder.getHandler(handlerName.toString(), JeecgRedisListener.class);
if (ObjectUtil.isNotEmpty(messageListener)) {
messageListener.onMessage(params);
}
}
}

View File

@ -1,250 +0,0 @@
package org.jeecg.common.modules.redis.writer;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.data.redis.cache.CacheStatistics;
import org.springframework.data.redis.cache.CacheStatisticsCollector;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* 该类参照 DefaultRedisCacheWriter 重写了 remove 方法实现通配符*删除
*
* @author: scott
* @date: 2020/01/01 16:18
*/
@Slf4j
public class JeecgRedisCacheWriter implements RedisCacheWriter {
private final RedisConnectionFactory connectionFactory;
private final Duration sleepTime;
public JeecgRedisCacheWriter(RedisConnectionFactory connectionFactory) {
this(connectionFactory, Duration.ZERO);
}
public JeecgRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
Assert.notNull(sleepTime, "SleepTime must not be null!");
this.connectionFactory = connectionFactory;
this.sleepTime = sleepTime;
}
@Override
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
this.execute(name, (connection) -> {
if (shouldExpireWithin(ttl)) {
connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
} else {
connection.set(key, value);
}
return "OK";
});
}
@Override
public byte[] get(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
return (byte[])this.execute(name, (connection) -> {
return connection.get(key);
});
}
@Override
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
return (byte[])this.execute(name, (connection) -> {
if (this.isLockingCacheWriter()) {
this.doLock(name, connection);
}
Object var7;
try {
boolean put;
if (shouldExpireWithin(ttl)) {
put = connection.set(key, value, Expiration.from(ttl), SetOption.ifAbsent());
} else {
put = connection.setNX(key, value);
}
if (!put) {
byte[] var11 = connection.get(key);
return var11;
}
var7 = null;
} finally {
if (this.isLockingCacheWriter()) {
this.doUnlock(name, connection);
}
}
return (byte[])var7;
});
}
@Override
public void remove(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
String keyString = new String(key);
log.info("redis remove key:" + keyString);
String keyIsAll = "*";
if(keyString!=null && keyString.endsWith(keyIsAll)){
execute(name, connection -> {
// 获取某个前缀所拥有的所有的键,某个前缀开头,后面肯定是*
Set<byte[]> keys = connection.keys(key);
int delNum = 0;
for (byte[] keyByte : keys) {
delNum += connection.del(keyByte);
}
return delNum;
});
}else{
this.execute(name, (connection) -> {
return connection.del(new byte[][]{key});
});
}
}
@Override
public void clean(String name, byte[] pattern) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(pattern, "Pattern must not be null!");
this.execute(name, (connection) -> {
boolean wasLocked = false;
try {
if (this.isLockingCacheWriter()) {
this.doLock(name, connection);
wasLocked = true;
}
byte[][] keys = (byte[][])((Set)Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())).toArray(new byte[0][]);
if (keys.length > 0) {
connection.del(keys);
}
} finally {
if (wasLocked && this.isLockingCacheWriter()) {
this.doUnlock(name, connection);
}
}
return "OK";
});
}
void lock(String name) {
this.execute(name, (connection) -> {
return this.doLock(name, connection);
});
}
void unlock(String name) {
this.executeLockFree((connection) -> {
this.doUnlock(name, connection);
});
}
private Boolean doLock(String name, RedisConnection connection) {
return connection.setNX(createCacheLockKey(name), new byte[0]);
}
private Long doUnlock(String name, RedisConnection connection) {
return connection.del(new byte[][]{createCacheLockKey(name)});
}
boolean doCheckLock(String name, RedisConnection connection) {
return connection.exists(createCacheLockKey(name));
}
private boolean isLockingCacheWriter() {
return !this.sleepTime.isZero() && !this.sleepTime.isNegative();
}
private <T> T execute(String name, Function<RedisConnection, T> callback) {
RedisConnection connection = this.connectionFactory.getConnection();
try {
this.checkAndPotentiallyWaitUntilUnlocked(name, connection);
return callback.apply(connection);
} finally {
connection.close();
}
}
private void executeLockFree(Consumer<RedisConnection> callback) {
RedisConnection connection = this.connectionFactory.getConnection();
try {
callback.accept(connection);
} finally {
connection.close();
}
}
private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
if (this.isLockingCacheWriter()) {
try {
while(this.doCheckLock(name, connection)) {
Thread.sleep(this.sleepTime.toMillis());
}
} catch (InterruptedException var4) {
Thread.currentThread().interrupt();
throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name), var4);
}
}
}
private static boolean shouldExpireWithin(@Nullable Duration ttl) {
return ttl != null && !ttl.isZero() && !ttl.isNegative();
}
private static byte[] createCacheLockKey(String name) {
return (name + "~lock").getBytes(StandardCharsets.UTF_8);
}
//update-begin-author:zyf date:20220216 for:升级springboot版本到2.4.0+以后需要实现的方法*
private final CacheStatisticsCollector statistics = CacheStatisticsCollector.create();
@Override
public CacheStatistics getCacheStatistics(String cacheName) {
return statistics.getCacheStatistics(cacheName);
}
@Override
public void clearStatistics(String name) {
}
@Override
public RedisCacheWriter withStatisticsCollector(CacheStatisticsCollector cacheStatisticsCollector) {
return null;
}
//update-begin-author:zyf date:20220216 for:升级springboot版本到2.4.0+以后需要实现的方法*
}

View File

@ -1,613 +0,0 @@
package org.jeecg.common.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* redis 工具类
* @Author Scott
*
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
//springboot2.4后用法
redisTemplate.delete(Arrays.asList(key));
}
}
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param by 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param by 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时 0 表头1 第二个元素依次类推index<0时-1表尾-2倒数第二个元素依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取指定前缀的一系列key
* 使用scan命令代替keys, Redis是单线程处理keys命令在KEY数量较多时
* 操作效率极低【时间复杂度为O(N)】,该命令一旦执行会严重阻塞线上其它命令的正常请求
* @param keyPrefix
* @return
*/
private Set<String> keys(String keyPrefix) {
String realKey = keyPrefix + "*";
try {
return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> binaryKeys = new HashSet<>();
//springboot2.4后用法
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(realKey).count(Integer.MAX_VALUE).build());
while (cursor.hasNext()) {
binaryKeys.add(new String(cursor.next()));
}
return binaryKeys;
});
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* 删除指定前缀的一系列key
* @param keyPrefix
*/
public void removeAll(String keyPrefix) {
try {
Set<String> keys = keys(keyPrefix);
redisTemplate.delete(keys);
} catch (Throwable e) {
e.printStackTrace();
}
}
}

View File

@ -1,81 +0,0 @@
package org.jeecg.common.util;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.
*
* @author zyf
*/
@Slf4j
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
// NOSONAR
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/**
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getHandler(String name, Class<T> cls) {
T t = null;
if (ObjectUtil.isNotEmpty(name)) {
checkApplicationContext();
try {
t = applicationContext.getBean(name, cls);
} catch (Exception e) {
log.warn("Customize redis listener handle [ " + name + " ], does not exist");
}
}
return t;
}
/**
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return applicationContext.getBean(clazz);
}
/**
* 清除applicationContext静态变量.
*/
public static void cleanApplicationContext() {
applicationContext = null;
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
}
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -15,7 +15,6 @@
<modules>
<module>jeecg-boot-base-api</module>
<module>jeecg-boot-base-core</module>
<module>jeecg-boot-base-tools</module>
</modules>