mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-01-03 12:05:28 +08:00
微服务重大升级说明(暂时只升级后台3.4.0)
-升级Spring Cloud Alibaba 2021.0.1.0,使用 spring.config.import 方式引入nacos配置 -拆分jeecg-boot-starter出来,使用独立项目维护
This commit is contained in:
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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";
|
||||
|
||||
/**
|
||||
* 微服务读取配置文件属性 服务地址
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(","));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
// }
|
||||
//}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 为空
|
||||
|
||||
@ -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>
|
||||
@ -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();
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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";
|
||||
}
|
||||
@ -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";
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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+以后需要实现的方法*
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user