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

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

View File

@ -7,7 +7,12 @@
JEECG BOOT 低代码开发平台(前后端分离版本)
===============
当前最新版本: 3.3.0发布日期2022-07-25
当前最新版本: 3.4.0发布日期2022-08-06
> **重大升级说明**
> - 升级[Spring Cloud Alibaba 2021.0.1.0](https://github.com/alibaba/spring-cloud-alibaba/blob/2021.x/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sca-upgrade-guide.adoc),使用 spring.config.import 方式引入nacos配置
> - 拆分jeecg-boot-starter出来使用独立项目维护 [jeecg-boot-starter项目新地址](https://gitee.com/jeecg/jeecg-boot-starter)
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)

View File

@ -1,7 +1,7 @@
Jeecg-Boot 低代码开发平台
===============
当前最新版本: 3.3.0发布日期20220725
当前最新版本: 3.4.0发布日期20220808
## 后端技术架构

File diff suppressed because one or more lines are too long

View File

@ -1,51 +0,0 @@
#### 镜像上传
# 仓库私服: 81.70.17.111:5000
# 第一步上传镜像到docker仓库
#docker tag jeecg-boot-mysql 81.70.17.111:5000/jeecg-boot-mysql:1.1
#docker tag jeecg-boot-system 81.70.17.111:5000/jeecg-boot-system:1.0
#docker tag nginxhtml:jeecgboot 81.70.17.111:5000/nginxhtml:1.2
#docker push 81.70.17.111:5000/jeecg-boot-mysql:1.1
#docker push 81.70.17.111:5000/jeecg-boot-system:1.0
#docker push 81.70.17.111:5000/nginxhtml:1.2
# 第二步将此yml文件上传服务器执行启动命令 docker-compose -f ./docker-compose-server.yml up
version: '2'
services:
jeecg-boot-mysql:
image: 81.70.17.111:5000/jeecg-boot-mysql:1.0
environment:
MYSQL_ROOT_PASSWORD: root
restart: always
container_name: jeecg-boot-mysql
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
ports:
- 3306:3306
jeecg-boot-redis:
image: redis:5.0
ports:
- 6379:6379
restart: always
container_name: jeecg-boot-redis
jeecg-boot-system:
image: 81.70.17.111:5000/jeecg-boot-system:1.0
restart: always
container_name: jeecg-boot-system
volumes:
- /data/config:/jeecg-boot/config
ports:
- 8080:8080
jeecg-boot-nginx:
image: 81.70.17.111:5000/nginxhtml
restart: always
container_name: jeecg-boot-nginx
ports:
- 80:80

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;
/**
* 使SpringURL
* @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";
/**
* onlinekey
*/
public static final String ONLINE_LIST = "sys:cache:online:list";
/**
* onlinekey
*/
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 () time0 time0
* @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=============================
/**
* keySet
*
* @param key
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* valueset,
*
* @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;
}
}
/**
* Nvalue
*
* @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
* 使scankeys, Redis线keysKEY
* 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;
/**
* ApplicationContextAwarecontext, .
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
// NOSONAR
SpringContextHolder.applicationContext = applicationContext;
}
/**
* ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/**
* ApplicationContextBean, .
*/
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
/**
* ApplicationContextBean, .
*/
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;
}
/**
* ApplicationContextBean, .
*/
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>

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>
@ -18,30 +18,4 @@
</dependency>
</dependencies>
<profiles>
<profile>
<id>SpringCloud</id>
<!-- 引入springboot独立启动-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- 引入微服务Starter依赖 -->
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-starter-cloud</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-starter-job</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -1,35 +0,0 @@
//package org.jeecg;
//
//import org.jeecg.common.base.BaseMap;
//import org.jeecg.common.constant.GlobalConstants;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.boot.CommandLineRunner;
//import org.springframework.boot.SpringApplication;
//import org.springframework.boot.autoconfigure.SpringBootApplication;
//import org.springframework.cloud.openfeign.EnableFeignClients;
//import org.springframework.data.redis.core.RedisTemplate;
//
//@SpringBootApplication
//@EnableFeignClients
//public class JeecgDemoCloudApplication implements CommandLineRunner {
// @Autowired
// private RedisTemplate<String, Object> redisTemplate;
//
// public static void main(String[] args) {
// SpringApplication.run(JeecgDemoCloudApplication.class, args);
// }
//
// /**
// * 启动的时候触发下gateway网关刷新
// *
// * 解决: 先启动gateway后启动服务Swagger接口文档访问不通的问题
// * @param args
// */
// @Override
// public void run(String... args) {
// BaseMap params = new BaseMap();
// params.put(GlobalConstants.HANDLER_NAME, GlobalConstants.LODER_ROUDER_HANDLER);
// //刷新网关
// redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
// }
//}

View File

@ -1,5 +0,0 @@
server:
port: 7002
spring:
application:
name: jeecg-demo

View File

@ -11,6 +11,6 @@ WORKDIR /jeecg-boot
EXPOSE 8080
ADD ./src/main/resources/jeecg ./config/jeecg
ADD ./target/jeecg-boot-module-system-3.3.0.jar ./
ADD ./target/jeecg-boot-module-system-3.4.0.jar ./
CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.3.0.jar
CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.4.0.jar

View File

@ -4,31 +4,12 @@
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-parent</artifactId>
<version>3.3.0</version>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-module-system</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>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
@ -74,32 +55,4 @@
</plugin>
</plugins>
</build>
<profiles>
<!-- SpringCloud运行环境 -->
<profile>
<id>SpringCloud</id>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<!-- SpringCloud运行环境的配置排除system模块jar里的yaml -->
<excludes>
<exclude>application.yml</exclude>
<exclude>application-*.yml</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.json</include>
<include>**/*.ftl</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
</project>

View File

@ -15,14 +15,12 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
/**
*
* :
* 1.mongodb exclude={MongoAutoConfiguration.class}
* 2. profileSpringCloud
*
* : mongo exclude={MongoAutoConfiguration.class}
*/
@Slf4j
@SpringBootApplication
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class})
//@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class})
public class JeecgSystemApplication extends SpringBootServletInitializer {
@Override

View File

@ -48,6 +48,8 @@ public class LoginController {
@Autowired
private ISysUserService sysUserService;
@Autowired
private ISysPermissionService sysPermissionService;
@Autowired
private SysBaseApiImpl sysBaseApi;
@Autowired
private ISysLogService logService;
@ -492,6 +494,17 @@ public class LoginController {
}
return res;
}
/**
* vue3
*/
@GetMapping(value = "/switchVue3Menu")
public Result<String> switchVue3Menu(HttpServletResponse response) {
Result<String> res = new Result<String>();
sysPermissionService.switchVue3Menu();
return res;
}
/**
* app

View File

@ -25,6 +25,14 @@ public interface SysPermissionMapper extends BaseMapper<SysPermission> {
* @return
*/
public List<TreeModel> queryListByParentId(@Param("parentId") String parentId);
/**
* vue3
*/
@Update("alter table sys_permission rename to sys_permission_v2")
public void backupVue2Menu();
@Update("alter table sys_permission_v3 rename to sys_permission")
public void changeVue3Menu();
/**
*

View File

@ -18,7 +18,11 @@ import com.baomidou.mybatisplus.extension.service.IService;
* @since 2018-12-21
*/
public interface ISysPermissionService extends IService<SysPermission> {
/**
* vue3
*/
public void switchVue3Menu();
/**
* id
* @param parentId id

View File

@ -60,6 +60,12 @@ public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, S
return sysPermissionMapper.queryListByParentId(parentId);
}
@Override
public void switchVue3Menu() {
sysPermissionMapper.backupVue2Menu();
sysPermissionMapper.changeVue3Menu();
}
/**
*
*/

View File

@ -183,6 +183,8 @@ jeecg:
safeMode: false
# 签名密钥串(前后端要一致,正式发布请自行修改)
signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
# 签名拦截接口
signUrls: /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
# 本地local\Miniominio\阿里云alioss
uploadType: local
# 前端访问地址

View File

@ -183,6 +183,8 @@ jeecg:
safeMode: false
# 签名密钥串(前后端要一致,正式发布请自行修改)
signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
# 签名拦截接口
signUrls: /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
# 本地local\Miniominio\阿里云alioss
uploadType: alioss
# 前端访问地址

View File

@ -183,6 +183,8 @@ jeecg:
safeMode: false
# 签名密钥串(前后端要一致,正式发布请自行修改)
signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
# 签名拦截接口
signUrls: /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
# 本地local\Miniominio\阿里云alioss
uploadType: local
# 前端访问地址

View File

@ -9,6 +9,6 @@ ${AnsiColor.BRIGHT_BLUE}
${AnsiColor.BRIGHT_GREEN}
Jeecg Boot Version: 3.3.0
Jeecg Boot Version: 3.4.0
Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
${AnsiColor.BLACK}

View File

@ -1,212 +0,0 @@
spring:
datasource:
druid:
stat-view-servlet:
enabled: true
loginUsername: admin
loginPassword: 123456
allow:
web-stat-filter:
enabled: true
dynamic:
druid: # 全局druid参数绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置)
# 连接池的配置信息
# 初始化大小,最小,最大
initial-size: 5
min-idle: 5
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters去掉后监控界面sql无法统计'wall'用于防火墙
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
datasource:
master:
url: jdbc:mysql://${MYSQL-HOST:jeecg-boot-mysql}:${MYSQL-PORT:3306}/${MYSQL-DB:jeecg-boot}?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: ${MYSQL-USER:root}
password: ${MYSQL-PWD:root}
driver-class-name: com.mysql.cj.jdbc.Driver
# 多数据源配置
#multi-datasource1:
#url: jdbc:mysql://localhost:3306/jeecg-boot2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
#username: root
#password: root
#driver-class-name: com.mysql.cj.jdbc.Driver
#redis 配置
redis:
database: 0
host: jeecg-boot-redis
lettuce:
pool:
max-active: 8 #最大连接数据库连接数,设 0 为没有限制
max-idle: 8 #最大等待连接中的数量,设 0 为没有限制
max-wait: -1ms #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
min-idle: 0 #最小等待连接中的数量,设 0 为没有限制
shutdown-timeout: 100ms
password:
port: 6379
#rabbitmq配置
rabbitmq:
host: jeecg-boot-rabbitmq
username: guest
password: guest
port: 5672
publisher-confirms: true
publisher-returns: true
virtual-host: /
listener:
simple:
acknowledge-mode: manual
#消费者的最小数量
concurrency: 1
#消费者的最大数量
max-concurrency: 1
#是否支持重试
retry:
enabled: true
#minidao
minidao :
base-package: org.jeecg.modules.jmreport.*
#jeecg专用配置
jeecg :
# 本地local\Miniominio\阿里云alioss
uploadType: local
path :
#文件上传根目录 设置
upload: D://opt//upFiles
#webapp文件路径
webapp: D://opt//webapp
shiro:
excludeUrls: /test/jeecgDemo/demo3,/test/jeecgDemo/redisDemo/**,/category/**,/map/**,/jmreport/bigscreen2/**
#阿里云oss存储配置
oss:
endpoint: oss-cn-beijing.aliyuncs.com
accessKey: ??
secretKey: ??
bucketName: jeecgdev
staticDomain: ??
# ElasticSearch 6设置
elasticsearch:
cluster-name: jeecg-ES
cluster-nodes: 127.0.0.1:9200
check-enabled: false
# 表单设计器配置
desform:
# 主题颜色(仅支持 16进制颜色代码
theme-color: "#1890ff"
# 文件、图片上传方式可选项qiniu七牛云、system跟随系统配置
upload-type: system
map:
# 配置百度地图的AK申请地址https://lbs.baidu.com/apiconsole/key?application=key#/home
baidu: ??
# 在线预览文件服务器地址配置
file-view-domain: 127.0.0.1:8012
# minio文件上传
minio:
minio_url: http://minio.jeecg.com
minio_name: ??
minio_pass: ??
bucketName: otatest
#大屏报表参数设置
jmreport:
mode: dev
#是否需要校验token
is_verify_token: false
#必须校验方法
verify_methods: remove,delete,save,add,update
#Wps在线文档
wps:
domain: https://wwo.wps.cn/office/
appid: ??
appsecret: ??
#xxl-job配置
xxljob:
enabled: false
adminAddresses: http://jeecg-boot-xxljob:9080/xxl-job-admin
appname: ${spring.application.name}
accessToken: ''
logPath: logs/jeecg/job/jobhandler/
logRetentionDays: 30
#自定义路由配置 yml nacos database
route:
config:
data-id: jeecg-gateway-router
group: DEFAULT_GROUP
data-type: yml
#分布式锁配置
redisson:
address: jeecg-boot-redis:6379
password:
type: STANDALONE
enabled: true
#Mybatis输出sql日志
logging:
level:
org.jeecg.modules.system.mapper : info
#cas单点登录
cas:
prefixUrl: http://localhost:8888/cas
#swagger
knife4j:
production: false
basic:
enable: true
username: jeecg
password: jeecg1314
#第三方登录
justauth:
enabled: true
type:
GITHUB:
client-id: ??
client-secret: ??
redirect-uri: http://sso.test.com:8080/jeecg-boot/thirdLogin/github/callback
WECHAT_ENTERPRISE:
client-id: ??
client-secret: ??
redirect-uri: http://sso.test.com:8080/jeecg-boot/thirdLogin/wechat_enterprise/callback
agent-id: 1000002
DINGTALK:
client-id: ??
client-secret: ??
redirect-uri: http://sso.test.com:8080/jeecg-boot/thirdLogin/dingtalk/callback
cache:
type: default
prefix: 'demo::'
timeout: 1h
#第三方APP对接
third-app:
enabled: false
type:
#企业微信
WECHAT_ENTERPRISE:
enabled: false
#CORP_ID
client-id: ??
#SECRET
client-secret: ??
agent-id: ??
#自建应用秘钥(新版企微需要配置)
# agent-app-secret: ??
#钉钉
DINGTALK:
enabled: false
# appKey
client-id: ??
# appSecret
client-secret: ??
agent-id: ??

View File

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-cloud</artifactId>
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-cloud-api</artifactId>
</dependency>
<!-- Nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- sentinel限流熔断降级 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--sentinel持久化 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- springboot up 2.6.6 -->
<!-- Alibaba Nacos 配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- SpringCloud 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- springboot up 2.6.6 -->
</dependencies>
</project>

View File

@ -1,195 +0,0 @@
package org.jeecg.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.SortedMap;
import javax.servlet.http.HttpServletRequest;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.PathMatcherUtil;
import org.jeecg.common.config.mqtoken.UserTokenContext;
import org.jeecg.config.mybatis.TenantContext;
import org.jeecg.config.sign.interceptor.SignAuthConfiguration;
import org.jeecg.config.sign.util.HttpUtils;
import org.jeecg.config.sign.util.SignUtil;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer;
import feign.Feign;
import feign.Logger;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import lombok.extern.slf4j.Slf4j;
/**
* @Description: FeignConfig
* @author: JeecgBoot
*/
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Slf4j
@Configuration
public class FeignConfig {
/**
* feign header
* X_ACCESS_TOKENX_SIGNX_TIMESTAMP
* @return
*/
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (null != attributes) {
HttpServletRequest request = attributes.getRequest();
log.debug("Feign request: {}", request.getRequestURI());
// 将token信息放入header中
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
if(token==null || "".equals(token)){
token = request.getParameter("token");
}
log.info("Feign Login Request token: {}", token);
requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
//update-begin-author:taoyan date:2022-6-23 for: issues/I5AO20 多租户微服务之间调用找不到tenant-id自定义页面
// 将tenantId信息放入header中
String tenantId = request.getHeader(CommonConstant.TENANT_ID);
if(tenantId==null || "".equals(tenantId)){
tenantId = request.getParameter(CommonConstant.TENANT_ID);
}
log.info("Feign Login Request tenantId: {}", tenantId);
requestTemplate.header(CommonConstant.TENANT_ID, tenantId);
//update-end-author:taoyan date:2022-6-23 for: issues/I5AO20 多租户微服务之间调用找不到tenant-id自定义页面
}else{
String token = UserTokenContext.getToken();
log.info("Feign no Login token: {}", token);
requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
//update-begin-author:taoyan date:2022-6-23 for: issues/I5AO20 多租户微服务之间调用找不到tenant-id自定义页面
String tenantId = TenantContext.getTenant();
log.info("Feign no Login tenantId: {}", tenantId);
requestTemplate.header(CommonConstant.TENANT_ID, tenantId);
//update-end-author:taoyan date:2022-6-23 for: issues/I5AO20 多租户微服务之间调用找不到tenant-id自定义页面
}
//================================================================================================================
//针对特殊接口,进行加签验证 ——根据URL地址过滤请求 【字典表参数签名验证】
if (PathMatcherUtil.matches(Arrays.asList(SignAuthConfiguration.SIGN_URL_LIST),requestTemplate.path())) {
try {
log.info("============================ [begin] fegin starter url ============================");
log.info(requestTemplate.path());
log.info(requestTemplate.method());
String queryLine = requestTemplate.queryLine();
if(queryLine!=null && queryLine.startsWith("?")){
queryLine = queryLine.substring(1);
}
log.info(queryLine);
if(requestTemplate.body()!=null){
log.info(new String(requestTemplate.body()));
}
SortedMap<String, String> allParams = HttpUtils.getAllParams(requestTemplate.path(),queryLine,requestTemplate.body(),requestTemplate.method());
String sign = SignUtil.getParamsSign(allParams);
log.info(" Feign request params sign: {}",sign);
log.info("============================ [end] fegin starter url ============================");
requestTemplate.header(CommonConstant.X_SIGN, sign);
//update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
requestTemplate.header(CommonConstant.X_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
//update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
} catch (IOException e) {
e.printStackTrace();
}
}
//================================================================================================================
};
}
/**
* Feign NONE
* Logger.Level
* NONE
* BASICURL
* HEADERS BASIC
* FULL
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
/**
* Feign
* @param messageConverters
* @return
*/
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
// update-begin--Author:sunjianlei Date:20210604 for 给 Feign 添加 FastJson 的解析支持 ----------
@Bean
public Encoder feignEncoder() {
return new SpringEncoder(feignHttpMessageConverter());
}
@Bean
public Decoder feignDecoder() {
return new SpringDecoder(feignHttpMessageConverter());
}
/**
* fastjson
*
* @return
*/
private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter());
return () -> httpMessageConverters;
}
private FastJsonHttpMessageConverter getFastJsonConverter() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList<>();
MediaType mediaTypeJson = MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE);
supportedMediaTypes.add(mediaTypeJson);
converter.setSupportedMediaTypes(supportedMediaTypes);
FastJsonConfig config = new FastJsonConfig();
config.getSerializeConfig().put(JSON.class, new SwaggerJsonSerializer());
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
return converter;
}
// update-end--Author:sunjianlei Date:20210604 for 给 Feign 添加 FastJson 的解析支持 ----------
}

View File

@ -1,31 +0,0 @@
package org.jeecg.starter.cloud.config;
/**
* @Description: (SpringBoot2.6.6)
* @author: zyf
* @date: 2022/02/21
* @version: V1.0
*/
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.util.pattern.PathPatternParser;
@Configuration
public class GwCorsFilter {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(18000L);
org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source =
new org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}

View File

@ -1,24 +0,0 @@
//package org.jeecg.starter.cloud.config;
//
//import feign.Client;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
//import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
//import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
//import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//@Configuration
//public class PersonBeanConfiguration {
//
// /**
// * 创建FeignClient
// */
// @Bean
// @ConditionalOnMissingBean
// public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
// SpringClientFactory clientFactory) {
// return new LoadBalancerFeignClient(new Client.Default(null, null),
// cachingFactory, clientFactory);
// }
//}

View File

@ -1,6 +0,0 @@
//package org.jeecg.starter.cloud.feign;
//
//public interface IJeecgFeignService {
//
// <T> T newInstance(Class<T> apiType, String name);
//}

View File

@ -1,60 +0,0 @@
//package org.jeecg.starter.cloud.feign.impl;
//
//import feign.*;
//import feign.codec.Decoder;
//import feign.codec.Encoder;
//import lombok.extern.slf4j.Slf4j;
//import org.jeecg.common.constant.CommonConstant;
//import org.jeecg.starter.cloud.feign.IJeecgFeignService;
//import org.springframework.boot.autoconfigure.AutoConfigureBefore;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
//import org.springframework.cloud.openfeign.FeignAutoConfiguration;
//import org.springframework.cloud.openfeign.FeignClientsConfiguration;
//import org.springframework.context.annotation.Import;
//import org.springframework.stereotype.Service;
//import org.springframework.web.context.request.RequestContextHolder;
//import org.springframework.web.context.request.ServletRequestAttributes;
//
//import javax.servlet.http.HttpServletRequest;
//
//@Service
//@Slf4j
//@ConditionalOnClass(Feign.class)
//@AutoConfigureBefore(FeignAutoConfiguration.class)
//@Import(FeignClientsConfiguration.class)
//public class JeecgFeignService implements IJeecgFeignService {
//
//
// //Feign 原生构造器
// Feign.Builder builder;
//
// //创建构造器
// public JeecgFeignService(Decoder decoder, Encoder encoder, Client client, Contract contract) {
// this.builder = Feign.builder()
// .client(client)
// .encoder(encoder)
// .decoder(decoder)
// .contract(contract);
//
// builder.requestInterceptor(requestTemplate -> {
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// if (null != attributes) {
// HttpServletRequest request = attributes.getRequest();
// log.info("Feign request: {}", request.getRequestURI());
// // 将token信息放入header中
// String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
// if(token==null){
// token = request.getParameter("token");
// }
// log.info("Feign request token: {}", token);
// requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
// }
// });
// }
//
//
// @Override
// public <T> T newInstance(Class<T> clientClass, String serviceName) {
// return builder.target(clientClass, String.format("http://%s/", serviceName));
// }
//}

View File

@ -1,55 +0,0 @@
package org.jeecg.starter.cloud.handler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: Sentinel(Sentinel)
* @author: zyf
* @date: 2022/02/18
* @version: V1.0
*/
@Configuration
public class CustomSentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws Exception {
String msg = null;
if (ex instanceof FlowException) {
msg = "访问频繁,请稍候再试";
} else if (ex instanceof DegradeException) {
msg = "系统降级";
} else if (ex instanceof ParamFlowException) {
msg = "热点参数限流";
} else if (ex instanceof SystemBlockException) {
msg = "系统规则限流或降级";
} else if (ex instanceof AuthorityException) {
msg = "授权规则不通过";
} else {
msg = "未知限流降级";
}
// http状态码
response.setStatus(200);
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"code\":500,\"message\":"+msg+"}");
}
}

View File

@ -1,31 +0,0 @@
package org.jeecg.starter.cloud.interceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.IpUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* sentinel ip()
* 1. origin
* 2. ip
*
* @author zyf
*/
@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
//基于请求参数,origin对应授权规则中的流控应用名称,也可通过getHeader传参
String origin = request.getParameter("origin");
if (StringUtils.isNotEmpty(origin)) {
return origin;
} else {
//当参数为空使用ip拦截模式
String ip = IpUtils.getIpAddr(request);
return ip;
}
}
}

View File

@ -1,59 +0,0 @@
spring:
#升级SpringBoot2.6.6,允许循环依赖
main:
allow-circular-references: true
profiles:
# 当前激活环境
active: '@profile.name@'
cloud:
#配置Bus id(远程推送事件)
bus:
id: ${spring.application.name}:${server.port}
nacos:
config:
# Nacos 认证用户
username: @config.username@
# Nacos 认证密码
password: @config.password@
# 命名空间 常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等
namespace: @config.namespace@
# 配置中心地址
server-addr: @config.server-addr@
# 配置对应的分组
group: @config.group@
# 配置文件后缀
file-extension: yaml
prefix: @prefix.name@
# 支持多个共享 Data Id 的配置优先级小于extension-configs,自定义 Data Id 配置 属性是个集合,内部由 Config POJO 组成。Config 有 3 个属性,分别是 dataId, group 以及 refresh
# shared-configs[0]:
# data-id: @prefix.name@-sharding.yaml #分库分表配置
# group: @config.group@
# refresh: false
# shared-configs[1]:
# data-id: @prefix.name@-common.yaml # 配置文件名-Data Id
# group: @config.group@ # 默认为DEFAULT_GROUP
# refresh: false # 是否动态刷新默认为false
discovery:
namespace: @config.namespace@
server-addr: @config.server-addr@
watch:
enabled: false
# feign启用sentinel
feign:
sentinel:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
client:
config:
default:
#不设置connectTimeout会导致readTimeout设置不生效
connectTimeout: 5000
readTimeout: 10000
compression:
request:
enabled: true
response:
enabled: true

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-job</artifactId>
<description>jeecg-boot-starter-定时任务</description>
<dependencies>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job-core.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,228 +0,0 @@
package com.xxl.job.core.executor;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.client.AdminBizClient;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.server.EmbedServer;
import com.xxl.job.core.thread.JobLogFileCleanThread;
import com.xxl.job.core.thread.JobThread;
import com.xxl.job.core.thread.TriggerCallbackThread;
import com.xxl.job.core.util.IpUtil;
import com.xxl.job.core.util.NetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 999910000
*/
public class XxlJobExecutor {
private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
// ---------------------- param ----------------------
private String adminAddresses;
private String accessToken;
private String appname;
private String address;
private String ip;
private int port;
private String logPath;
private int logRetentionDays;
public void setAdminAddresses(String adminAddresses) {
this.adminAddresses = adminAddresses;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public void setAppname(String appname) {
this.appname = appname;
}
public void setAddress(String address) {
this.address = address;
}
public void setIp(String ip) {
this.ip = ip;
}
public void setPort(int port) {
this.port = port;
}
public void setLogPath(String logPath) {
this.logPath = logPath;
}
public void setLogRetentionDays(int logRetentionDays) {
this.logRetentionDays = logRetentionDays;
}
// ---------------------- start + stop ----------------------
public void start() throws Exception {
// init logpath
XxlJobFileAppender.initLogPath(logPath);
// init invoker, admin-client
initAdminBizList(adminAddresses, accessToken);
// init JobLogFileCleanThread
JobLogFileCleanThread.getInstance().start(logRetentionDays);
// init TriggerCallbackThread
TriggerCallbackThread.getInstance().start();
// init executor-server
initEmbedServer(address, ip, port, appname, accessToken);
}
public void destroy() {
// destory executor-server
stopEmbedServer();
// destory jobThreadRepository
if (jobThreadRepository.size() > 0) {
for (Map.Entry<Integer, JobThread> item : jobThreadRepository.entrySet()) {
JobThread oldJobThread = removeJobThread(item.getKey(), "web container destroy and kill the job.");
// wait for job thread push result to callback queue
if (oldJobThread != null) {
try {
oldJobThread.join();
} catch (InterruptedException e) {
logger.error(">>>>>>>>>>> xxl-job, JobThread destroy(join) error, jobId:{}", item.getKey(), e);
}
}
}
jobThreadRepository.clear();
}
jobHandlerRepository.clear();
// destory JobLogFileCleanThread
JobLogFileCleanThread.getInstance().toStop();
// destory TriggerCallbackThread
TriggerCallbackThread.getInstance().toStop();
}
// ---------------------- admin-client (rpc invoker) ----------------------
private static List<AdminBiz> adminBizList;
private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
if (adminAddresses != null && adminAddresses.trim().length() > 0) {
for (String address : adminAddresses.trim().split(",")) {
if (address != null && address.trim().length() > 0) {
AdminBiz adminBiz = new AdminBizClient(address.trim(), accessToken);
if (adminBizList == null) {
adminBizList = new ArrayList<AdminBiz>();
}
adminBizList.add(adminBiz);
}
}
}
}
public static List<AdminBiz> getAdminBizList() {
return adminBizList;
}
// ---------------------- executor-server (rpc provider) ----------------------
private EmbedServer embedServer = null;
private void initEmbedServer(String address, String ip, int port, String appname, String accessToken) throws Exception {
// fill ip port 修改默认端口
port = port > 0 ? port : NetUtil.findAvailablePort(10000);
ip = (ip != null && ip.trim().length() > 0) ? ip : IpUtil.getIp();
// generate address
if (address == null || address.trim().length() == 0) {
String ip_port_address = IpUtil.getIpPort(ip, port); // registry-addressdefault use address to registry , otherwise use ip:port if address is null
address = "http://{ip_port}/".replace("{ip_port}", ip_port_address);
}
// accessToken
if (accessToken == null || accessToken.trim().length() == 0) {
logger.warn(">>>>>>>>>>> xxl-job accessToken is empty. To ensure system security, please set the accessToken.");
}
// start
embedServer = new EmbedServer();
embedServer.start(address, port, appname, accessToken);
}
private void stopEmbedServer() {
// stop provider factory
if (embedServer != null) {
try {
embedServer.stop();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
// ---------------------- job handler repository ----------------------
private static ConcurrentMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
public static IJobHandler loadJobHandler(String name) {
return jobHandlerRepository.get(name);
}
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler) {
logger.info(">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
return jobHandlerRepository.put(name, jobHandler);
}
// ---------------------- job thread repository ----------------------
private static ConcurrentMap<Integer, JobThread> jobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();
public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason) {
JobThread newJobThread = new JobThread(jobId, handler);
newJobThread.start();
logger.info(">>>>>>>>>>> xxl-job regist JobThread success, jobId:{}, handler:{}", new Object[]{jobId, handler});
JobThread oldJobThread = jobThreadRepository.put(jobId, newJobThread); // putIfAbsent | oh my god, map's put method return the old value!!!
if (oldJobThread != null) {
oldJobThread.toStop(removeOldReason);
oldJobThread.interrupt();
}
return newJobThread;
}
public static JobThread removeJobThread(int jobId, String removeOldReason) {
JobThread oldJobThread = jobThreadRepository.remove(jobId);
if (oldJobThread != null) {
oldJobThread.toStop(removeOldReason);
oldJobThread.interrupt();
return oldJobThread;
}
return null;
}
public static JobThread loadJobThread(int jobId) {
JobThread jobThread = jobThreadRepository.get(jobId);
return jobThread;
}
}

View File

@ -1,18 +0,0 @@
package org.jeecg.boot.starter.job.annotation;
import org.jeecg.boot.starter.job.config.XxlJobConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* @author zyf
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({ XxlJobConfiguration.class })
public @interface EnableXxlJob {
}

View File

@ -1,48 +0,0 @@
package org.jeecg.boot.starter.job.config;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.job.prop.XxlJobProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
*
* @author jeecg
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(value = XxlJobProperties.class)
@ConditionalOnProperty(value = "jeecg.xxljob.enabled", havingValue = "true", matchIfMissing = true)
public class XxlJobConfiguration {
@Autowired
private XxlJobProperties xxlJobProperties;
//@Bean(initMethod = "start", destroyMethod = "destroy")
@Bean
@ConditionalOnClass()
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init.");
//log.info(">>>> ip="+xxlJobProperties.getIp()+"Port="+xxlJobProperties.getPort()+"address="+xxlJobProperties.getAdminAddresses());
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(xxlJobProperties.getAdminAddresses());
xxlJobSpringExecutor.setAppname(xxlJobProperties.getAppname());
//update-begin--Author:scott -- Date:20210305 -- forsystem服务和demo服务有办法同时使用xxl-job吗 #2313---
//xxlJobSpringExecutor.setIp(xxlJobProperties.getIp());
//xxlJobSpringExecutor.setPort(xxlJobProperties.getPort());
//update-end--Author:scott -- Date:20210305 -- forsystem服务和demo服务有办法同时使用xxl-job吗 #2313---
xxlJobSpringExecutor.setAccessToken(xxlJobProperties.getAccessToken());
xxlJobSpringExecutor.setLogPath(xxlJobProperties.getLogPath());
xxlJobSpringExecutor.setLogRetentionDays(xxlJobProperties.getLogRetentionDays());
return xxlJobSpringExecutor;
}
}

View File

@ -1,35 +0,0 @@
package org.jeecg.boot.starter.job.prop;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "jeecg.xxljob")
public class XxlJobProperties {
private String adminAddresses;
private String appname;
private String ip;
private int port;
private String accessToken;
private String logPath;
private int logRetentionDays;
/**
* xxljob
*/
private Boolean enable = true;
}

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.jeecg.boot.starter.job.config.XxlJobConfiguration

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-lock</artifactId>
<description>jeecg-boot-starter-分布式锁</description>
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-tools</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,57 +0,0 @@
package org.jeecg.boot.starter.lock.annotation;
import org.jeecg.boot.starter.lock.enums.LockModel;
import java.lang.annotation.*;
/**
* Redisson
*
* @author zyf
* @date 2020-11-11
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface JLock {
/**
* :,,.使 REENTRANT MULTIPLE
*/
LockModel lockModel() default LockModel.AUTO;
/**
* keys,,使
* @return
*/
String[] lockKey() default {};
/**
* key:keyspelLIST,使+spel
* @return
*/
String keyConstant() default "";
/**
* ,30000
*
* @return int
*/
long expireSeconds() default 30000L;
/**
* ,10000 -1
*
* @return int
*/
long waitTime() default 10000L;
/**
*
*
* @return
*/
String failMsg() default "获取锁失败,请稍后重试";
}

View File

@ -1,36 +0,0 @@
package org.jeecg.boot.starter.lock.annotation;
/**
* @author zyf
*/
import java.lang.annotation.*;
/**
*
*
* @author 2019618
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface JRepeat {
/**
*
*
* @return
*/
int lockTime();
/**
* redis key
*
* @return redis key
*/
String lockKey() default "";
}

View File

@ -1,72 +0,0 @@
package org.jeecg.boot.starter.lock.annotation;
/**
* @author zyf
* @date 2019/10/26 18:26
*/
/**
*
* @author zyf
*/
public enum LockConstant {
/**
*
*/
COMMON("commonLock:", 1, 500, "请勿重复点击");
/**
*
*/
private String keyPrefix;
/**
*
*/
private int waitTime;
/**
*
*/
private int leaseTime;
/**
*
*/
private String message;
LockConstant(String keyPrefix, int waitTime, int leaseTime, String message) {
this.keyPrefix = keyPrefix;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
this.message = message;
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public int getWaitTime() {
return waitTime;
}
public void setWaitTime(int waitTime) {
this.waitTime = waitTime;
}
public int getLeaseTime() {
return leaseTime;
}
public void setLeaseTime(int leaseTime) {
this.leaseTime = leaseTime;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -1,67 +0,0 @@
package org.jeecg.boot.starter.lock.aspect;
import lombok.extern.slf4j.Slf4j;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.util.ArrayList;
import java.util.List;
/**
* @author zyf
*/
@Slf4j
public class BaseAspect {
/**
* spring SpEL
*
* @param key key # :#user
* @param parameterNames
* @param values
* @param keyConstant key
* @return
*/
public List<String> getValueBySpEL(String key, String[] parameterNames, Object[] values, String keyConstant) {
List<String> keys = new ArrayList<>();
if (!key.contains("#")) {
String s = "redis:lock:" + key + keyConstant;
log.debug("lockKey:" + s);
keys.add(s);
return keys;
}
//spel解析器
ExpressionParser parser = new SpelExpressionParser();
//spel上下文
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], values[i]);
}
Expression expression = parser.parseExpression(key);
Object value = expression.getValue(context);
if (value != null) {
if (value instanceof List) {
List value1 = (List) value;
for (Object o : value1) {
addKeys(keys, o, keyConstant);
}
} else if (value.getClass().isArray()) {
Object[] obj = (Object[]) value;
for (Object o : obj) {
addKeys(keys, o, keyConstant);
}
} else {
addKeys(keys, value, keyConstant);
}
}
log.info("表达式key={},value={}", key, keys);
return keys;
}
private void addKeys(List<String> keys, Object o, String keyConstant) {
keys.add("redis:lock:" + o.toString() + keyConstant);
}
}

View File

@ -1,167 +0,0 @@
package org.jeecg.boot.starter.lock.aspect;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.boot.starter.lock.annotation.JLock;
import org.jeecg.boot.starter.lock.enums.LockModel;
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
@Aspect
@Component
public class DistributedLockHandler extends BaseAspect{
@Autowired(required = false)
private RedissonClient redissonClient;
/**
*
*
* @param joinPoint
* @param jLock
* @return Object
*/
@SneakyThrows
@Around("@annotation(jLock)")
public Object around(ProceedingJoinPoint joinPoint, JLock jLock) {
Object obj = null;
log.info("进入RedisLock环绕通知...");
RLock rLock = getLock(joinPoint, jLock);
boolean res = false;
//获取超时时间
long expireSeconds = jLock.expireSeconds();
//等待多久,n秒内获取不到锁则直接返回
long waitTime = jLock.waitTime();
//执行aop
if (rLock != null) {
try {
if (waitTime == -1) {
res = true;
//一直等待加锁
rLock.lock(expireSeconds, TimeUnit.MILLISECONDS);
} else {
res = rLock.tryLock(waitTime, expireSeconds, TimeUnit.MILLISECONDS);
}
if (res) {
obj = joinPoint.proceed();
} else {
log.error("获取锁异常");
}
} finally {
if (res) {
rLock.unlock();
}
}
}
log.info("结束RedisLock环绕通知...");
return obj;
}
@SneakyThrows
private RLock getLock(ProceedingJoinPoint joinPoint, JLock jLock) {
String[] keys = jLock.lockKey();
if (keys.length == 0) {
throw new RuntimeException("keys不能为空");
}
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
Object[] args = joinPoint.getArgs();
LockModel lockModel = jLock.lockModel();
RLock rLock = null;
String keyConstant = jLock.keyConstant();
if (lockModel.equals(LockModel.AUTO)) {
if (keys.length > 1) {
lockModel = LockModel.REDLOCK;
} else {
lockModel = LockModel.REENTRANT;
}
}
if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
}
switch (lockModel) {
case FAIR:
rLock = redissonClient.getFairLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0));
break;
case REDLOCK:
List<RLock> rLocks = new ArrayList<>();
for (String key : keys) {
List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
for (String s : valueBySpEL) {
rLocks.add(redissonClient.getLock(s));
}
}
RLock[] locks = new RLock[rLocks.size()];
int index = 0;
for (RLock r : rLocks) {
locks[index++] = r;
}
rLock = new RedissonRedLock(locks);
break;
case MULTIPLE:
rLocks = new ArrayList<>();
for (String key : keys) {
List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
for (String s : valueBySpEL) {
rLocks.add(redissonClient.getLock(s));
}
}
locks = new RLock[rLocks.size()];
index = 0;
for (RLock r : rLocks) {
locks[index++] = r;
}
rLock = new RedissonMultiLock(locks);
break;
case REENTRANT:
List<String> valueBySpEL = getValueBySpEL(keys[0], parameterNames, args, keyConstant);
//如果spel表达式是数组或者LIST 则使用红锁
if (valueBySpEL.size() == 1) {
rLock = redissonClient.getLock(valueBySpEL.get(0));
} else {
locks = new RLock[valueBySpEL.size()];
index = 0;
for (String s : valueBySpEL) {
locks[index++] = redissonClient.getLock(s);
}
rLock = new RedissonRedLock(locks);
}
break;
case READ:
rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).readLock();
break;
case WRITE:
rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).writeLock();
break;
}
return rLock;
}
}

View File

@ -1,81 +0,0 @@
package org.jeecg.boot.starter.lock.aspect;
/**
* @author zyf
*/
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.boot.starter.lock.annotation.JRepeat;
import org.jeecg.boot.starter.lock.client.RedissonLockClient;
import org.jeecg.common.exception.JeecgCloudException;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author 2019618
*/
@Aspect
@Component
public class RepeatSubmitAspect extends BaseAspect{
@Resource
private RedissonLockClient redissonLockClient;
/***
* controllerJRepeat
*/
@Pointcut("@annotation(jRepeat)")
public void pointCut(JRepeat jRepeat) {
}
/**
* AOP
*
* @param joinPoint
* @return
* @throws Exception
*/
@Around("pointCut(jRepeat)")
public Object repeatSubmit(ProceedingJoinPoint joinPoint,JRepeat jRepeat) throws Throwable {
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
if (Objects.nonNull(jRepeat)) {
// 获取参数
Object[] args = joinPoint.getArgs();
// 进行一些参数的处理比如获取订单号操作人id等
StringBuffer lockKeyBuffer = new StringBuffer();
String key =getValueBySpEL(jRepeat.lockKey(), parameterNames, args,"RepeatSubmit").get(0);
// 公平加锁lockTime后锁自动释放
boolean isLocked = false;
try {
isLocked = redissonLockClient.fairLock(key, TimeUnit.SECONDS, jRepeat.lockTime());
// 如果成功获取到锁就继续执行
if (isLocked) {
// 执行进程
return joinPoint.proceed();
} else {
// 未获取到锁
throw new JeecgCloudException("请勿重复提交");
}
} finally {
// 如果锁还存在,在方法执行完成后,释放锁
if (isLocked) {
redissonLockClient.unlock(key);
}
}
}
return joinPoint.proceed();
}
}

View File

@ -1,126 +0,0 @@
package org.jeecg.boot.starter.lock.client;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* Redisson
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
@Component
public class RedissonLockClient {
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
*
*/
public RLock getLock(String lockKey) {
return redissonClient.getLock(lockKey);
}
/**
*
*
* @return boolean
*/
public boolean tryLock(String lockName, long expireSeconds) {
return tryLock(lockName, 0, expireSeconds);
}
/**
*
*
* @return boolean
*/
public boolean tryLock(String lockName, long waitTime, long expireSeconds) {
RLock rLock = getLock(lockName);
boolean getLock = false;
try {
getLock = rLock.tryLock(waitTime, expireSeconds, TimeUnit.SECONDS);
if (getLock) {
log.info("获取锁成功,lockName={}", lockName);
} else {
log.info("获取锁失败,lockName={}", lockName);
}
} catch (InterruptedException e) {
log.error("获取式锁异常lockName=" + lockName, e);
getLock = false;
}
return getLock;
}
public boolean fairLock(String lockKey, TimeUnit unit, int leaseTime) {
RLock fairLock = redissonClient.getFairLock(lockKey);
try {
boolean existKey = existKey(lockKey);
// 已经存在了,就直接返回
if (existKey) {
return false;
}
return fairLock.tryLock(3, leaseTime, unit);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
public boolean existKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* lockKey
*
* @param lockKey
* @return
*/
public RLock lock(String lockKey) {
RLock lock = getLock(lockKey);
lock.lock();
return lock;
}
/**
* lockKey
*
* @param lockKey
* @param leaseTime
* @return
*/
public RLock lock(String lockKey, long leaseTime) {
RLock lock = getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
return lock;
}
/**
*
*
* @param lockName
*/
public void unlock(String lockName) {
try {
redissonClient.getLock(lockName).unlock();
} catch (Exception e) {
log.error("解锁异常lockName=" + lockName, e);
}
}
}

View File

@ -1,36 +0,0 @@
package org.jeecg.boot.starter.lock.config;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.lock.core.RedissonManager;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Redisson
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
@Configuration
@ConditionalOnClass(RedissonProperties.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfiguration {
@Bean
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redissonClient(RedissonProperties redissonProperties) {
RedissonManager redissonManager = new RedissonManager(redissonProperties);
log.info("RedissonManager初始化完成,当前连接方式:" + redissonProperties.getType() + ",连接地址:" + redissonProperties.getAddress());
return redissonManager.getRedisson();
}
}

View File

@ -1,100 +0,0 @@
package org.jeecg.boot.starter.lock.core;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.jeecg.boot.starter.lock.core.strategy.impl.ClusterRedissonConfigStrategyImpl;
import org.jeecg.boot.starter.lock.core.strategy.impl.MasterslaveRedissonConfigStrategyImpl;
import org.jeecg.boot.starter.lock.core.strategy.impl.SentinelRedissonConfigStrategyImpl;
import org.jeecg.boot.starter.lock.core.strategy.impl.StandaloneRedissonConfigStrategyImpl;
import org.jeecg.boot.starter.lock.enums.RedisConnectionType;
import org.redisson.Redisson;
import org.redisson.config.Config;
/**
* Redissonredisson
*
* @author zyf
* @date 2020-11-12
*/
@Slf4j
public class RedissonManager {
private Config config = new Config();
private Redisson redisson = null;
public RedissonManager() {
}
public RedissonManager(RedissonProperties redissonProperties) {
//装配开关
Boolean enabled = redissonProperties.getEnabled();
if (enabled) {
try {
config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
redisson = (Redisson) Redisson.create(config);
} catch (Exception e) {
log.error("Redisson初始化错误", e);
}
}
}
public Redisson getRedisson() {
return redisson;
}
/**
* Redisson
*
*/
static class RedissonConfigFactory {
private RedissonConfigFactory() {
}
private static volatile RedissonConfigFactory factory = null;
public static RedissonConfigFactory getInstance() {
if (factory == null) {
synchronized (Object.class) {
if (factory == null) {
factory = new RedissonConfigFactory();
}
}
}
return factory;
}
/**
*
*
* @param redissonProperties
* @return Config
*/
Config createConfig(RedissonProperties redissonProperties) {
Preconditions.checkNotNull(redissonProperties);
Preconditions.checkNotNull(redissonProperties.getAddress(), "redis地址未配置");
RedisConnectionType connectionType = redissonProperties.getType();
// 声明连接方式
RedissonConfigStrategy redissonConfigStrategy;
if (connectionType.equals(RedisConnectionType.SENTINEL)) {
redissonConfigStrategy = new SentinelRedissonConfigStrategyImpl();
} else if (connectionType.equals(RedisConnectionType.CLUSTER)) {
redissonConfigStrategy = new ClusterRedissonConfigStrategyImpl();
} else if (connectionType.equals(RedisConnectionType.MASTERSLAVE)) {
redissonConfigStrategy = new MasterslaveRedissonConfigStrategyImpl();
} else {
redissonConfigStrategy = new StandaloneRedissonConfigStrategyImpl();
}
Preconditions.checkNotNull(redissonConfigStrategy, "连接方式创建异常");
return redissonConfigStrategy.createRedissonConfig(redissonProperties);
}
}
}

View File

@ -1,21 +0,0 @@
package org.jeecg.boot.starter.lock.core.strategy;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.redisson.config.Config;
/**
* Redisson
*
* @author zyf
* @date 2020-11-11
*/
public interface RedissonConfigStrategy {
/**
* RedisConfig
*
* @param redissonProperties
* @return Config
*/
Config createRedissonConfig(RedissonProperties redissonProperties);
}

View File

@ -1,43 +0,0 @@
package org.jeecg.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.jeecg.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
/**
* Redisson
* cluster6(33)
* :127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class ClusterRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
String[] addrTokens = address.split(",");
// 设置集群(cluster)节点的服务IP和端口
for (int i = 0; i < addrTokens.length; i++) {
config.useClusterServers().addNodeAddress(GlobalConstant.REDIS_CONNECTION_PREFIX + addrTokens[i]);
if (StringUtils.isNotBlank(password)) {
config.useClusterServers().setPassword(password);
}
}
log.info("初始化集群方式Config,连接地址:" + address);
} catch (Exception e) {
log.error("集群Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}

View File

@ -1,54 +0,0 @@
package org.jeecg.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.jeecg.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
import java.util.ArrayList;
import java.util.List;
/**
* Redisson
* <p>: 127.0.0.1:6379(),127.0.0.1:6380(),127.0.0.1:6381()</p>
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class MasterslaveRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String[] addrTokens = address.split(",");
String masterNodeAddr = addrTokens[0];
// 设置主节点ip
config.useMasterSlaveServers().setMasterAddress(masterNodeAddr);
if (StringUtils.isNotBlank(password)) {
config.useMasterSlaveServers().setPassword(password);
}
config.useMasterSlaveServers().setDatabase(database);
// 设置从节点,移除第一个节点,默认第一个为主节点
List<String> slaveList = new ArrayList<>();
for (String addrToken : addrTokens) {
slaveList.add(GlobalConstant.REDIS_CONNECTION_PREFIX + addrToken);
}
slaveList.remove(0);
config.useMasterSlaveServers().addSlaveAddress((String[]) slaveList.toArray());
log.info("初始化主从方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("主从Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}

View File

@ -1,47 +0,0 @@
package org.jeecg.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.jeecg.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
/**
* Redis
* sentinel.confsentinel monitor my-sentinel-name 127.0.0.1 6379 2,my-sentinel-name
* :my-sentinel-name,127.0.0.1:26379,127.0.0.1:26389,127.0.0.1:26399
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class SentinelRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String[] addrTokens = address.split(",");
String sentinelAliasName = addrTokens[0];
// 设置redis配置文件sentinel.conf配置的sentinel别名
config.useSentinelServers().setMasterName(sentinelAliasName);
config.useSentinelServers().setDatabase(database);
if (StringUtils.isNotBlank(password)) {
config.useSentinelServers().setPassword(password);
}
// 设置哨兵节点的服务IP和端口
for (int i = 1; i < addrTokens.length; i++) {
config.useSentinelServers().addSentinelAddress(GlobalConstant.REDIS_CONNECTION_PREFIX+ addrTokens[i]);
}
log.info("初始化哨兵方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("哨兵Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}

View File

@ -1,40 +0,0 @@
package org.jeecg.boot.starter.lock.core.strategy.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.boot.starter.lock.core.strategy.RedissonConfigStrategy;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.jeecg.boot.starter.lock.enums.GlobalConstant;
import org.redisson.config.Config;
/**
* Redisson
*
* @author zyf
* @date 2020-11-11
*/
@Slf4j
public class StandaloneRedissonConfigStrategyImpl implements RedissonConfigStrategy {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String redisAddr = GlobalConstant.REDIS_CONNECTION_PREFIX + address;
config.useSingleServer().setAddress(redisAddr);
config.useSingleServer().setDatabase(database);
if (StringUtils.isNotBlank(password)) {
config.useSingleServer().setPassword(password);
}
log.info("初始化Redisson单机配置,连接地址:" + address);
} catch (Exception e) {
log.error("单机Redisson初始化错误", e);
e.printStackTrace();
}
return config;
}
}

View File

@ -1,17 +0,0 @@
package org.jeecg.boot.starter.lock.enums;
/**
*
*
* @author zyf
* @date 2020-11-11
*/
public interface GlobalConstant {
/**
* Redis
*/
String REDIS_CONNECTION_PREFIX = "redis://";
}

View File

@ -1,22 +0,0 @@
package org.jeecg.boot.starter.lock.enums;
/**
*
* @author jeecg
*/
public enum LockModel {
//可重入锁
REENTRANT,
//公平锁
FAIR,
//联锁(可以把一组锁当作一个锁来加锁和释放)
MULTIPLE,
//红锁
REDLOCK,
//读锁
READ,
//写锁
WRITE,
//自动模式,当参数只有一个.使用 REENTRANT 参数多个 REDLOCK
AUTO
}

View File

@ -1,39 +0,0 @@
package org.jeecg.boot.starter.lock.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Redis
* @author zyf
* @date 2020-11-11
*/
@Getter
@AllArgsConstructor
public enum RedisConnectionType {
/**
* ()
*/
STANDALONE("standalone", "单机部署方式"),
/**
*
*/
SENTINEL("sentinel", "哨兵部署方式"),
/**
*
*/
CLUSTER("cluster", "集群方式"),
/**
*
*/
MASTERSLAVE("masterslave", "主从部署方式");
/**
*
*/
private final String code;
/**
*
*/
private final String name;
}

View File

@ -1,39 +0,0 @@
package org.jeecg.boot.starter.lock.prop;
import lombok.Data;
import org.jeecg.boot.starter.lock.enums.RedisConnectionType;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Redisson
*
* @author zyf
* @date 2020-11-11
*/
@Data
@ConfigurationProperties(prefix = "jeecg.redisson")
public class RedissonProperties {
/**
* redisipport(,)
*/
private String address;
/**
*
*/
private RedisConnectionType type;
/**
*
*/
private String password;
/**
* (0)
*/
private int database;
/**
* redisson
*/
private Boolean enabled = true;
}

View File

@ -1,4 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.jeecg.boot.starter.lock.config.RedissonConfiguration

View File

@ -1,59 +0,0 @@
package org.jeecg.boot.starter.lock.test;
import org.jeecg.boot.starter.lock.annotation.JLock;
import org.jeecg.boot.starter.lock.annotation.JRepeat;
import org.jeecg.boot.starter.lock.annotation.LockConstant;
import org.jeecg.boot.starter.lock.client.RedissonLockClient;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class LockService {
@Resource
private RedissonLockClient redissonLockClient;
int n = 10;
/**
* ()
*/
@JLock(lockKey = "#productId", expireSeconds = 5000)
public void seckill(String productId) {
if (n <= 0) {
System.out.println("活动已结束,请下次再来");
return;
}
System.out.println(Thread.currentThread().getName() + ":秒杀到了商品");
System.out.println(--n);
}
/**
* ()
*/
public void seckill2(String productId) {
redissonLockClient.tryLock(productId, 5000);
if (n <= 0) {
System.out.println("活动已结束,请下次再来");
return;
}
System.out.println(Thread.currentThread().getName() + ":秒杀到了商品");
System.out.println(--n);
redissonLockClient.unlock(productId);
}
/**
*
*/
@JRepeat(lockKey = "#name", lockTime = 5)
public void reSubmit(String name) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("提交成功" + name);
}
}

View File

@ -1,67 +0,0 @@
package org.jeecg.boot.starter.lock.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = LockTestApplication.class)
public class LockTest {
@Autowired
LockService lockService;
/**
* ()
*/
@Test
public void test1() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(6);
IntStream.range(0, 30).forEach(i -> executorService.submit(() -> {
try {
lockService.seckill("20120508784");
} catch (Exception e) {
e.printStackTrace();
}
}));
executorService.awaitTermination(30, TimeUnit.SECONDS);
}
/**
* ()
*/
@Test
public void test2() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(6);
IntStream.range(0, 30).forEach(i -> executorService.submit(() -> {
try {
lockService.seckill2("20120508784");
} catch (Exception e) {
e.printStackTrace();
}
}));
executorService.awaitTermination(30, TimeUnit.SECONDS);
}
/**
* ()
*/
@Test
public void test3() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(6);
IntStream.range(0, 20).forEach(i -> executorService.submit(() -> {
try {
lockService.reSubmit("test");
} catch (Exception e) {
e.printStackTrace();
}
}));
executorService.awaitTermination(30, TimeUnit.SECONDS);
}
}

View File

@ -1,15 +0,0 @@
package org.jeecg.boot.starter.lock.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication(scanBasePackages = "org.jeecg")
@EnableAspectJAutoProxy
public class LockTestApplication {
public static void main(String[] args) {
SpringApplication.run(LockTestApplication.class, args);
}
}

View File

@ -1,9 +0,0 @@
package org.jeecg.boot.starter.lock.test;
import lombok.Data;
@Data
public class TestUser {
private String userId;
private String userName;
}

View File

@ -1,19 +0,0 @@
spring:
redis:
database: 0
host: 127.0.0.1
lettuce:
pool:
max-active: 8 #最大连接数据库连接数,设 0 为没有限制
max-idle: 8 #最大等待连接中的数量,设 0 为没有限制
max-wait: -1ms #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
min-idle: 0 #最小等待连接中的数量,设 0 为没有限制
shutdown-timeout: 100ms
password: jeecg
port: 6379
jeecg :
redisson:
address: 127.0.0.1:6379
password: jeecg
type: STANDALONE
enabled: true

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-rabbitmq</artifactId>
<description>jeecg-boot-starter-消息队列</description>
<dependencies>
<!-- 消息总线 rabbitmq -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,359 +0,0 @@
package org.jeecg.boot.starter.rabbitmq.client;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.rabbitmq.event.EventObj;
import org.jeecg.boot.starter.rabbitmq.event.JeecgRemoteApplicationEvent;
import org.jeecg.boot.starter.rabbitmq.exchange.DelayExchangeBuilder;
import org.jeecg.common.annotation.RabbitComponent;
import org.jeecg.common.base.BaseMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.bus.BusProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
*
*/
@Slf4j
@Configuration
public class RabbitMqClient {
private static final Logger logger = LoggerFactory.getLogger(RabbitMqClient.class);
private final RabbitAdmin rabbitAdmin;
private final RabbitTemplate rabbitTemplate;
@Resource
private SimpleMessageListenerContainer messageListenerContainer;
@Resource
BusProperties busProperties;
@Resource
private ApplicationEventPublisher publisher;
@Resource
private ApplicationContext applicationContext;
@Bean
public void initQueue() {
Map<String, Object> beansWithRqbbitComponentMap = this.applicationContext.getBeansWithAnnotation(RabbitComponent.class);
Class<? extends Object> clazz = null;
for (Map.Entry<String, Object> entry : beansWithRqbbitComponentMap.entrySet()) {
log.info("初始化队列............");
//获取到实例对象的class信息
clazz = entry.getValue().getClass();
Method[] methods = clazz.getMethods();
RabbitListener rabbitListener = clazz.getAnnotation(RabbitListener.class);
if (ObjectUtil.isNotEmpty(rabbitListener)) {
createQueue(rabbitListener);
}
for (Method method : methods) {
RabbitListener methodRabbitListener = method.getAnnotation(RabbitListener.class);
if (ObjectUtil.isNotEmpty(methodRabbitListener)) {
createQueue(methodRabbitListener);
}
}
}
}
/**
*
*
* @param rabbitListener
*/
private void createQueue(RabbitListener rabbitListener) {
String[] queues = rabbitListener.queues();
DirectExchange directExchange = createExchange(DelayExchangeBuilder.DELAY_EXCHANGE);
//创建交换机
rabbitAdmin.declareExchange(directExchange);
if (ObjectUtil.isNotEmpty(queues)) {
for (String queueName : queues) {
Properties result = rabbitAdmin.getQueueProperties(queueName);
if (ObjectUtil.isEmpty(result)) {
Queue queue = new Queue(queueName);
addQueue(queue);
Binding binding = BindingBuilder.bind(queue).to(directExchange).with(queueName);
rabbitAdmin.declareBinding(binding);
log.info("创建队列:" + queueName);
}else{
log.info("已有队列:" + queueName);
}
}
}
}
private Map sentObj = new HashMap<>();
@Autowired
public RabbitMqClient(RabbitAdmin rabbitAdmin, RabbitTemplate rabbitTemplate) {
this.rabbitAdmin = rabbitAdmin;
this.rabbitTemplate = rabbitTemplate;
}
/**
*
*
* @param handlerName
* @param baseMap
*/
public void publishEvent(String handlerName, BaseMap baseMap) {
EventObj eventObj = new EventObj();
eventObj.setHandlerName(handlerName);
eventObj.setBaseMap(baseMap);
publisher.publishEvent(new JeecgRemoteApplicationEvent(eventObj, busProperties.getId()));
}
/**
* Message
*
* @param messageType MessageProperties
* @param msg
* @return
*/
public Message getMessage(String messageType, Object msg) {
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType(messageType);
Message message = new Message(msg.toString().getBytes(), messageProperties);
return message;
}
/**
* KeyExchange
*
* @param routingKey
* @param msg
*/
public void sendMessageToExchange(TopicExchange topicExchange, String routingKey, Object msg) {
Message message = getMessage(MessageProperties.CONTENT_TYPE_JSON, msg);
rabbitTemplate.send(topicExchange.getName(), routingKey, message);
}
/**
* KEYExchange
*
* @param exchange
* @param msg
*/
public void sendMessageToExchange(TopicExchange topicExchange, AbstractExchange exchange, String msg) {
addExchange(exchange);
logger.info("RabbitMQ send " + exchange.getName() + "->" + msg);
rabbitTemplate.convertAndSend(topicExchange.getName(), msg);
}
/**
*
*
* @param queueName
* @param params map
*/
public void sendMessage(String queueName, Object params) {
log.info("发送消息到mq");
try {
rabbitTemplate.convertAndSend(DelayExchangeBuilder.DELAY_EXCHANGE, queueName, params, message -> {
return message;
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
*
* @param queueName
*/
public void sendMessage(String queueName) {
this.send(queueName, this.sentObj, 0);
this.sentObj.clear();
}
public RabbitMqClient put(String key, Object value) {
this.sentObj.put(key, value);
return this;
}
/**
*
*
* @param queueName
* @param params params
* @param expiration
*/
public void sendMessage(String queueName, Object params, Integer expiration) {
this.send(queueName, params, expiration);
}
private void send(String queueName, Object params, Integer expiration) {
Queue queue = new Queue(queueName);
addQueue(queue);
CustomExchange customExchange = DelayExchangeBuilder.buildExchange();
rabbitAdmin.declareExchange(customExchange);
Binding binding = BindingBuilder.bind(queue).to(customExchange).with(queueName).noargs();
rabbitAdmin.declareBinding(binding);
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.debug("发送时间:" + sf.format(new Date()));
rabbitTemplate.convertAndSend(DelayExchangeBuilder.DEFAULT_DELAY_EXCHANGE, queueName, params, message -> {
if (expiration != null && expiration > 0) {
message.getMessageProperties().setHeader("x-delay", expiration);
}
return message;
});
}
/**
* queue
*
* @param queueName
*/
public String receiveFromQueue(String queueName) {
return receiveFromQueue(DirectExchange.DEFAULT, queueName);
}
/**
* directqueue
*
* @param directExchange
* @param queueName
*/
public String receiveFromQueue(DirectExchange directExchange, String queueName) {
Queue queue = new Queue(queueName);
addQueue(queue);
Binding binding = BindingBuilder.bind(queue).to(directExchange).withQueueName();
rabbitAdmin.declareBinding(binding);
String messages = (String) rabbitTemplate.receiveAndConvert(queueName);
System.out.println("Receive:" + messages);
return messages;
}
/**
* Exchange
*
* @param exchange
*/
public void addExchange(AbstractExchange exchange) {
rabbitAdmin.declareExchange(exchange);
}
/**
* Exchange
*
* @param exchangeName
*/
public boolean deleteExchange(String exchangeName) {
return rabbitAdmin.deleteExchange(exchangeName);
}
/**
* exclusive=trueautoDelete=true durable = false
*
* @return Queue
*/
public Queue addQueue() {
return rabbitAdmin.declareQueue();
}
/**
* Queue
*
* @param queue
* @return queueName
*/
public String addQueue(Queue queue) {
return rabbitAdmin.declareQueue(queue);
}
/**
*
*
* @param queueName the name of the queue.
* @param unused true if the queue should be deleted only if not in use.
* @param empty true if the queue should be deleted only if empty.
*/
public void deleteQueue(String queueName, boolean unused, boolean empty) {
rabbitAdmin.deleteQueue(queueName, unused, empty);
}
/**
*
*
* @param queueName
* @return true if the queue existed and was deleted.
*/
public boolean deleteQueue(String queueName) {
return rabbitAdmin.deleteQueue(queueName);
}
/**
* 使routingKey
*
* @param queue
* @param exchange
* @param routingKey
*/
public void addBinding(Queue queue, TopicExchange exchange, String routingKey) {
Binding binding = BindingBuilder.bind(queue).to(exchange).with(routingKey);
rabbitAdmin.declareBinding(binding);
}
/**
* ExchangeExchange 使routingKey
*
* @param exchange
* @param topicExchange
* @param routingKey
*/
public void addBinding(Exchange exchange, TopicExchange topicExchange, String routingKey) {
Binding binding = BindingBuilder.bind(exchange).to(topicExchange).with(routingKey);
rabbitAdmin.declareBinding(binding);
}
/**
* binding
*
* @param binding
*/
public void removeBinding(Binding binding) {
rabbitAdmin.removeBinding(binding);
}
/**
*
*
* @param exchangeName
* @return
*/
public DirectExchange createExchange(String exchangeName) {
return new DirectExchange(exchangeName, true, false);
}
}

View File

@ -1,67 +0,0 @@
package org.jeecg.boot.starter.rabbitmq.config;
import java.util.UUID;
import org.jeecg.boot.starter.rabbitmq.event.JeecgRemoteApplicationEvent;
import org.jeecg.common.config.mqtoken.TransmitUserTokenFilter;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.ConsumerTagStrategy;
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
*
* @author zyf
*/
@Configuration
@RemoteApplicationEventScan(basePackageClasses = JeecgRemoteApplicationEvent.class)
public class RabbitMqConfig {
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
//设置忽略声明异常
rabbitAdmin.setIgnoreDeclarationExceptions(true);
return rabbitAdmin;
}
/**
* token
* @return
*/
@Bean
public TransmitUserTokenFilter transmitUserInfoFromHttpHeader(){
return new TransmitUserTokenFilter();
}
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
//手动确认
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//当前的消费者数量
container.setConcurrentConsumers(1);
//最大的消费者数量
container.setMaxConcurrentConsumers(1);
//是否重回队列
container.setDefaultRequeueRejected(true);
//消费端的标签策略
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID().toString();
}
});
return container;
}
}

View File

@ -1,40 +0,0 @@
package org.jeecg.boot.starter.rabbitmq.core;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.rabbitmq.listenter.MqListener;
import org.jeecg.common.config.mqtoken.UserTokenContext;
import java.io.IOException;
/**
*
* @author zyf
*/
@Slf4j
public class BaseRabbiMqHandler<T> {
private String token= UserTokenContext.getToken();
public void onMessage(T t, Long deliveryTag, Channel channel, MqListener mqListener) {
try {
UserTokenContext.setToken(token);
mqListener.handler(t, channel);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.info("接收消息失败,重新放回队列");
try {
/**
* deliveryTag:index
* multiple.true:deliveryTag
* requeue
*/
channel.basicNack(deliveryTag, false, true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}

View File

@ -1,39 +0,0 @@
package org.jeecg.boot.starter.rabbitmq.core;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.Map;
public class MapMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(object.toString().getBytes(), messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
String contentType = message.getMessageProperties().getContentType();
if (null != contentType && contentType.contains("text")) {
return new String(message.getBody());
} else {
ObjectInputStream objInt = null;
try {
ByteArrayInputStream byteInt = new ByteArrayInputStream(message.getBody());
objInt = new ObjectInputStream(byteInt);
//byte[]转map
Map map = (HashMap) objInt.readObject();
return map;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}

View File

@ -1,28 +0,0 @@
package org.jeecg.boot.starter.rabbitmq.event;
import cn.hutool.core.util.ObjectUtil;
import org.jeecg.common.util.SpringContextHolder;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* ,
*/
@Component
public class BaseApplicationEvent implements ApplicationListener<JeecgRemoteApplicationEvent> {
@Override
public void onApplicationEvent(JeecgRemoteApplicationEvent jeecgRemoteApplicationEvent) {
EventObj eventObj = jeecgRemoteApplicationEvent.getEventObj();
if (ObjectUtil.isNotEmpty(eventObj)) {
//获取业务模块消息处理器
JeecgBusEventHandler busEventHandler = SpringContextHolder.getHandler(eventObj.getHandlerName(), JeecgBusEventHandler.class);
if (ObjectUtil.isNotEmpty(busEventHandler)) {
//通知业务模块
busEventHandler.onMessage(eventObj);
}
}
}
}

View File

@ -1,21 +0,0 @@
package org.jeecg.boot.starter.rabbitmq.event;
import lombok.Data;
import org.jeecg.common.base.BaseMap;
import java.io.Serializable;
/**
*
*/
@Data
public class EventObj implements Serializable {
/**
*
*/
private BaseMap baseMap;
/**
* beanName
*/
private String handlerName;
}

Some files were not shown because too many files have changed in this diff Show More