JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台

This commit is contained in:
zhangdaiscott
2021-01-23 23:59:31 +08:00
parent 41c1572ad8
commit 8b0ee2d0a2
238 changed files with 4660 additions and 35961 deletions

View File

@ -14,7 +14,7 @@
"_genkey_8": "/act/**",
"_genkey_9": "/plug-in/**",
"_genkey_10": "/generic/**",
"_genkey_11": "/druid/**"
"_genkey_11": "/v1/**"
}
}],
"filters": [],

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.0</version>
<version>2.4.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-cloud</artifactId>

View File

@ -2,8 +2,6 @@ spring:
profiles:
# 当前激活环境
active: @profile.name@
main:
allow-bean-definition-overriding: true
cloud:
#配置Bus id(远程推送事件)
bus:

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.0</version>
<version>2.4.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-job</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.0</version>
<version>2.4.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-lock</artifactId>

View File

@ -1,5 +1,7 @@
package org.jeecg.boot.starter.lock.annotation;
import org.jeecg.boot.starter.lock.enums.LockModel;
import java.lang.annotation.*;
/**
@ -15,35 +17,37 @@ import java.lang.annotation.*;
public @interface DistributedLock {
/**
* 锁的参数索引
* 锁的模式:如果不设置,自动模式,当参数只有一个.使用 REENTRANT 参数多个 MULTIPLE
*/
int[] fieldIndexs() default {};
LockModel lockModel() default LockModel.AUTO;
/**
* 要锁的参数的属性名
* 如果keys有多个,如果不设置,则使用 联锁
* @return
*/
String[] fieldNames() default {};
String[] lockKey() default {};
/**
* 分布式锁名称
*
* @return String
* key的静态常量:当key的spel的值是LIST,数组时使用+号连接将会被spel认为这个变量是个字符串,只能产生一把锁,达不到我们的目的,<br />
* 而我们如果又需要一个常量的话.这个参数将会在拼接在每个元素的后面
* @return
*/
String lockKey() default "";
String keyConstant() default "";
/**
* 锁超时时间(单位:秒) 如果超过还没有解锁的话,就强制解锁
* 锁超时时间,默认30000毫秒
*
* @return int
*/
int expireSeconds() default 10;
long expireSeconds() default 30000L;
/**
* 等待多久(单位:秒)-1 则表示一直等待
* 等待加锁超时时间,默认10000毫秒 -1 则表示一直等待
*
* @return int
*/
int waitTime() default 5;
long waitTime() default 10000L;
/**
* 未取到锁时提示信息

View File

@ -2,17 +2,29 @@ package org.jeecg.boot.starter.lock.aspect;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
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.DistributedLock;
import org.jeecg.boot.starter.lock.client.RedissonLockClient;
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;
/**
* 分布式锁解析器
@ -25,8 +37,9 @@ import org.springframework.stereotype.Component;
@Component
public class DistributedLockHandler {
@Autowired
RedissonLockClient redissonLock;
@Autowired(required = false)
private RedissonClient redissonClient;
/**
* 切面环绕通知
@ -35,70 +48,171 @@ public class DistributedLockHandler {
* @param distributedLock
* @return Object
*/
@SneakyThrows
@Around("@annotation(distributedLock)")
public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
log.info("进入RedisLock环绕通知...");
Object obj = null;
//获取锁名称
String lockName = getLockKey(joinPoint, distributedLock);
if (StringUtils.isEmpty(lockName)) {
return null;
}
log.info("进入RedisLock环绕通知...");
RLock rLock = getLock(joinPoint, distributedLock);
boolean res = false;
//获取超时时间
int expireSeconds = distributedLock.expireSeconds();
long expireSeconds = distributedLock.expireSeconds();
//等待多久,n秒内获取不到锁则直接返回
int waitTime = distributedLock.waitTime();
Boolean success = redissonLock.tryLock(lockName, waitTime, expireSeconds);
if (success) {
log.info("获取锁成功....");
long waitTime = distributedLock.waitTime();
//执行aop
if (rLock != null) {
try {
obj = joinPoint.proceed();
} catch (Throwable throwable) {
log.error("获取锁异常", throwable);
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 {
//释放锁
redissonLock.unlock(lockName);
log.info("成功释放锁...");
if (res) {
rLock.unlock();
}
}
} else {
log.error("获取锁失败", distributedLock.failMsg());
}
log.info("结束RedisLock环绕通知...");
return obj;
}
@SneakyThrows
private String getLockKey(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
String lockKey = distributedLock.lockKey();
if (StringUtils.isEmpty(lockKey)) {
int[] fieldIndexs = distributedLock.fieldIndexs();
String[] fieldNames = distributedLock.fieldNames();
//目标方法内的所有参数
Object[] params = joinPoint.getArgs();
//获取目标包名和类名
String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
//获取目标方法名
String methodName = joinPoint.getSignature().getName();
// 锁2个及2个以上参数时fieldNames数量应与fieldIndexs一致
if (fieldNames.length > 1 && fieldIndexs.length != fieldNames.length) {
log.error("fieldIndexs与fieldNames数量不一致");
return null;
}
// 数组为空代表锁整个方法
if (ArrayUtils.isNotEmpty(fieldNames)) {
StringBuffer lockParamsBuffer = new StringBuffer();
for (int i = 0; i < fieldIndexs.length; i++) {
if (fieldNames.length == 0 || fieldNames[i] == null || fieldNames[i].length() == 0) {
lockParamsBuffer.append("." + params[fieldIndexs[i]]);
} else {
Object lockParamValue = PropertyUtils.getSimpleProperty(params[fieldIndexs[i]], fieldNames[i]);
lockParamsBuffer.append("." + lockParamValue);
}
}
lockKey = declaringTypeName + "." + methodName + lockParamsBuffer.toString();
private RLock getLock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
String[] keys = distributedLock.lockKey();
if (keys.length == 0) {
throw new RuntimeException("keys不能为空");
}
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
Object[] args = joinPoint.getArgs();
LockModel lockModel = distributedLock.lockModel();
if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
}
RLock rLock = null;
String keyConstant = distributedLock.keyConstant();
if (lockModel.equals(LockModel.AUTO)) {
if (keys.length > 1) {
lockModel = LockModel.REDLOCK;
} else {
lockModel = LockModel.REENTRANT;
}
}
return lockKey;
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;
}
/**
* 通过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.info("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,12 +1,10 @@
package org.jeecg.boot.starter.lock.client;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.lock.core.RedissonManager;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@ -17,19 +15,17 @@ import java.util.concurrent.TimeUnit;
* @date 2020-11-11
*/
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Component
public class RedissonLockClient {
RedissonManager redissonManager;
@Autowired
private RedissonClient redissonClient;
/**
* 获取锁
*/
public RLock getLock(String lockKey) {
return redissonManager.getRedisson().getLock(lockKey);
return redissonClient.getLock(lockKey);
}
/**
@ -96,7 +92,7 @@ public class RedissonLockClient {
* @param lockName 锁名称
*/
public void unlock(String lockName) {
redissonManager.getRedisson().getLock(lockName).unlock();
redissonClient.getLock(lockName).unlock();
}

View File

@ -1,16 +1,14 @@
package org.jeecg.boot.starter.lock.config;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.lock.client.RedissonLockClient;
import org.jeecg.boot.starter.lock.core.RedissonManager;
import org.jeecg.boot.starter.lock.prop.RedissonProperties;
import org.redisson.Redisson;
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;
import org.springframework.core.annotation.Order;
/**
@ -21,27 +19,18 @@ import org.springframework.core.annotation.Order;
*/
@Slf4j
@Configuration
@ConditionalOnClass(Redisson.class)
@ConditionalOnClass(RedissonProperties.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfiguration {
@Bean
@ConditionalOnMissingBean
@Order(value = 1)
public RedissonManager redissonManager(RedissonProperties redissonProperties) {
RedissonManager redissonManager = new RedissonManager(redissonProperties);
log.info("RedissonManager初始化完成,当前连接方式:" + redissonProperties.getType() + ",连接地址:" + redissonProperties.getAddress());
return redissonManager;
}
@Bean
@ConditionalOnMissingBean
@Order(value = 2)
public RedissonLockClient redissonLock(RedissonManager redissonManager) {
RedissonLockClient redissonLock = new RedissonLockClient();
redissonLock.setRedissonManager(redissonManager);
log.info("RedissonLock初始化完成");
return redissonLock;
@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

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

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.0</version>
<version>2.4.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-rabbitmq</artifactId>

View File

@ -61,7 +61,7 @@ public class RabbitMqClient {
Map<String, Object> beansWithRqbbitComponentMap = this.applicationContext.getBeansWithAnnotation(RabbitComponent.class);
Class<? extends Object> clazz = null;
for (Map.Entry<String, Object> entry : beansWithRqbbitComponentMap.entrySet()) {
log.info("初始化队列............");
log.info("初始化队列............");
//获取到实例对象的class信息
clazz = entry.getValue().getClass();
Method[] methods = clazz.getMethods();

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-starter</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.0</version>
<version>2.4.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter-redis</artifactId>

View File

@ -13,7 +13,8 @@ import java.util.Map;
*/
@Configuration
public class JeecgRedisClient {
@Resource
@Resource(name = "starterRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;

View File

@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.redis.prop.JeecgRedisProperties;
import org.jeecg.boot.starter.redis.service.RedisReceiver;
import org.jeecg.common.constant.GlobalConstants;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@ -39,8 +40,8 @@ public class RedisConfiguration {
* @param lettuceConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
@Bean("starterRedisTemplate")
public RedisTemplate<String, Object> starterRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
log.info(" --- redis config init --- ");
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);

View File

@ -4,15 +4,17 @@
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-parent</artifactId>
<version>2.4.0</version>
<version>2.4.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-starter</artifactId>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>jeecg-boot-starter-cloud</module>
<module>jeecg-boot-starter-job</module>
@ -37,5 +39,4 @@
<optional>true</optional>
</dependency>
</dependencies>
</project>