org.apache.commons
diff --git a/src/main/java/com/WisdomSiteApplication.java b/src/main/java/com/WisdomSiteApplication.java
index 6f9810001..0d013108a 100644
--- a/src/main/java/com/WisdomSiteApplication.java
+++ b/src/main/java/com/WisdomSiteApplication.java
@@ -2,6 +2,7 @@ package com;
import cn.xuyanwu.spring.file.storage.EnableFileStorage;
+import com.zhgd.redis.lock.redisson.EnableDistributedLock;
import org.apache.catalina.connector.Connector;
import org.junit.Test;
import org.mybatis.spring.annotation.MapperScan;
@@ -35,6 +36,7 @@ import org.springframework.security.web.firewall.StrictHttpFirewall;
//@EnableConfigurationProperties({FileStorageProperties.class})
@PropertySource(value = "classpath:application.properties", encoding = "utf-8")
@SpringBootApplication
+@EnableDistributedLock
public class WisdomSiteApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
diff --git a/src/main/java/com/zhgd/redis/lock/redisson/DistributedLock.java b/src/main/java/com/zhgd/redis/lock/redisson/DistributedLock.java
new file mode 100644
index 000000000..bc90250a0
--- /dev/null
+++ b/src/main/java/com/zhgd/redis/lock/redisson/DistributedLock.java
@@ -0,0 +1,47 @@
+package com.zhgd.redis.lock.redisson;
+
+import java.lang.annotation.*;
+import java.util.concurrent.TimeUnit;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DistributedLock {
+
+ /**
+ * 保证业务接口的key的唯一性,否则失去了分布式锁的意义 锁key
+ * 支持使用spEl表达式
+ */
+ String key();
+
+ /**
+ * 保证业务接口的key的唯一性,否则失去了分布式锁的意义 锁key 前缀
+ */
+ String keyPrefix() default "";
+
+ /**
+ * 是否在等待时间内获取锁,如果在等待时间内无法获取到锁,则返回失败
+ */
+ boolean tryLok() default false;
+
+ /**
+ * 获取锁的最大尝试时间 ,会尝试tryTime时间获取锁,在该时间内获取成功则返回,否则抛出获取锁超时异常,tryLok=true时,该值必须大于0。
+ *
+ */
+ long tryTime() default 0;
+
+ /**
+ * 加锁的时间,超过这个时间后锁便自动解锁
+ */
+ long lockTime() default 30;
+
+ /**
+ * tryTime 和 lockTime的时间单位
+ */
+ TimeUnit unit() default TimeUnit.SECONDS;
+
+ /**
+ * 是否公平锁,false:非公平锁,true:公平锁
+ */
+ boolean fair() default false;
+}
diff --git a/src/main/java/com/zhgd/redis/lock/redisson/DistributedLockAspect.java b/src/main/java/com/zhgd/redis/lock/redisson/DistributedLockAspect.java
new file mode 100644
index 000000000..014fcbdda
--- /dev/null
+++ b/src/main/java/com/zhgd/redis/lock/redisson/DistributedLockAspect.java
@@ -0,0 +1,174 @@
+package com.zhgd.redis.lock.redisson;
+
+import com.zhgd.jeecg.common.execption.OpenAlertException;
+import com.zhgd.jeecg.common.execption.OpenPromptException;
+import lombok.extern.slf4j.Slf4j;
+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.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.common.TemplateParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+
+import javax.annotation.Resource;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+@Aspect
+@Slf4j
+public class DistributedLockAspect {
+
+ @Resource
+ private IDistributedLock distributedLock;
+
+ /**
+ * SpEL表达式解析
+ */
+ private SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
+
+ /**
+ * 用于获取方法参数名字
+ */
+ private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
+
+ @Pointcut("@annotation(com.zhgd.redis.lock.redisson.DistributedLock)")
+ public void distributorLock() {
+ }
+
+ @Around("distributorLock()")
+ public Object around(ProceedingJoinPoint pjp) throws Throwable {
+ // 获取DistributedLock
+ DistributedLock distributedLock = this.getDistributedLock(pjp);
+ // 获取 lockKey
+ String lockKey = this.getLockKey(pjp, distributedLock);
+ ILock lockObj = null;
+ try {
+ // 加锁,tryLok = true,并且tryTime > 0时,尝试获取锁,获取不到超时异常
+ if (distributedLock.tryLok()) {
+ if(distributedLock.tryTime() < 0){
+ throw new OpenAlertException("tryTime must be greater than 0");
+ }
+ lockObj = this.distributedLock.tryLock(lockKey, distributedLock.tryTime(), distributedLock.lockTime(), distributedLock.unit(), distributedLock.fair());
+ } else {
+ lockObj = this.distributedLock.lock(lockKey, distributedLock.lockTime(), distributedLock.unit(), distributedLock.fair());
+ }
+
+ if (Objects.isNull(lockObj)) {
+ throw new OpenPromptException("正在处理中,请稍等");
+ }
+
+ return pjp.proceed();
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ // 解锁
+ this.unLock(lockObj);
+ }
+ }
+
+ /**
+ * @param pjp
+ * @return
+ * @throws NoSuchMethodException
+ */
+ private DistributedLock getDistributedLock(ProceedingJoinPoint pjp) throws NoSuchMethodException {
+ String methodName = pjp.getSignature().getName();
+ Class clazz = pjp.getTarget().getClass();
+ Class>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
+ Method lockMethod = clazz.getMethod(methodName, par);
+ DistributedLock distributedLock = lockMethod.getAnnotation(DistributedLock.class);
+ return distributedLock;
+ }
+
+ /**
+ * 解锁
+ *
+ * @param lockObj
+ */
+ private void unLock(ILock lockObj) {
+ if (Objects.isNull(lockObj)) {
+ return;
+ }
+
+ try {
+ this.distributedLock.unLock(lockObj);
+ } catch (Exception e) {
+ log.error("分布式锁解锁异常", e);
+ }
+ }
+
+ /**
+ * 获取 lockKey
+ *
+ * @param pjp
+ * @param distributedLock
+ * @return
+ */
+ private String getLockKey(ProceedingJoinPoint pjp, DistributedLock distributedLock) {
+ String lockKey = distributedLock.key();
+ String keyPrefix = distributedLock.keyPrefix();
+ if (StringUtils.isBlank(lockKey)) {
+ throw new OpenAlertException("Lok key cannot be empty");
+ }
+ if (lockKey.contains("#")) {
+ this.checkSpEL(lockKey);
+ MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
+ // 获取方法参数值
+ Object[] args = pjp.getArgs();
+ lockKey = getValBySpEL(lockKey, methodSignature, args);
+ }
+ lockKey = StringUtils.isBlank(keyPrefix) ? lockKey : keyPrefix + lockKey;
+ return lockKey;
+ }
+
+ /**
+ * 解析spEL表达式
+ *
+ * @param spEL
+ * @param methodSignature
+ * @param args
+ * @return
+ */
+ private String getValBySpEL(String spEL, MethodSignature methodSignature, Object[] args) {
+ // 获取方法形参名数组
+ String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod());
+ if (paramNames == null || paramNames.length < 1) {
+ throw new OpenAlertException("Lok key cannot be empty");
+ }
+ Expression expression = spelExpressionParser.parseExpression(spEL);
+ // spring的表达式上下文对象
+ EvaluationContext context = new StandardEvaluationContext();
+ // 给上下文赋值
+ for (int i = 0; i < args.length; i++) {
+ context.setVariable(paramNames[i], args[i]);
+ }
+ Object value = expression.getValue(context);
+ if (value == null) {
+ throw new OpenAlertException("The parameter value cannot be null");
+ }
+ return value.toString();
+ }
+
+ /**
+ * SpEL 表达式校验
+ *
+ * @param spEL
+ * @return
+ */
+ private void checkSpEL(String spEL) {
+ try {
+ ExpressionParser parser = new SpelExpressionParser();
+ parser.parseExpression(spEL, new TemplateParserContext());
+ } catch (Exception e) {
+ log.error("spEL表达式解析异常", e);
+ throw new OpenAlertException("Invalid SpEL expression [" + spEL + "]");
+ }
+ }
+}
diff --git a/src/main/java/com/zhgd/redis/lock/redisson/EnableDistributedLock.java b/src/main/java/com/zhgd/redis/lock/redisson/EnableDistributedLock.java
new file mode 100644
index 000000000..d982d014f
--- /dev/null
+++ b/src/main/java/com/zhgd/redis/lock/redisson/EnableDistributedLock.java
@@ -0,0 +1,12 @@
+package com.zhgd.redis.lock.redisson;
+
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Import({DistributedLockAspect.class})
+public @interface EnableDistributedLock {
+}
diff --git a/src/main/java/com/zhgd/redis/lock/redisson/IDistributedLock.java b/src/main/java/com/zhgd/redis/lock/redisson/IDistributedLock.java
new file mode 100644
index 000000000..8e64a1348
--- /dev/null
+++ b/src/main/java/com/zhgd/redis/lock/redisson/IDistributedLock.java
@@ -0,0 +1,70 @@
+package com.zhgd.redis.lock.redisson;
+
+import java.util.concurrent.TimeUnit;
+
+public interface IDistributedLock {
+ /**
+ * 获取锁,默认30秒失效,失败一直等待直到获取锁
+ *
+ * @param key 锁的key
+ * @return 锁对象
+ */
+ ILock lock(String key);
+
+ /**
+ * 获取锁,失败一直等待直到获取锁
+ *
+ * @param key 锁的key
+ * @param lockTime 加锁的时间,超过这个时间后锁便自动解锁; 如果lockTime为-1,则保持锁定直到显式解锁
+ * @param unit {@code lockTime} 参数的时间单位
+ * @param fair 是否公平锁
+ * @return 锁对象
+ */
+ ILock lock(String key, long lockTime, TimeUnit unit, boolean fair);
+
+ /**
+ * 尝试获取锁,30秒获取不到超时异常,锁默认30秒失效
+ *
+ * @param key 锁的key
+ * @param tryTime 获取锁的最大尝试时间
+ * @return
+ * @throws Exception
+ */
+ ILock tryLock(String key, long tryTime) throws Exception;
+
+ /**
+ * 尝试获取锁,获取不到超时异常
+ *
+ * @param key 锁的key
+ * @param tryTime 获取锁的最大尝试时间
+ * @param lockTime 加锁的时间
+ * @param unit {@code tryTime @code lockTime} 参数的时间单位
+ * @param fair 是否公平锁
+ * @return
+ * @throws Exception
+ */
+ ILock tryLock(String key, long tryTime, long lockTime, TimeUnit unit, boolean fair) throws Exception;
+
+ /**
+ * 解锁
+ *
+ * @param lock
+ * @throws Exception
+ */
+ void unLock(Object lock);
+
+
+ /**
+ * 释放锁
+ *
+ * @param lock
+ * @throws Exception
+ */
+ default void unLock(ILock lock) {
+ if (lock != null) {
+ unLock(lock.getLock());
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/zhgd/redis/lock/redisson/ILock.java b/src/main/java/com/zhgd/redis/lock/redisson/ILock.java
new file mode 100644
index 000000000..5d7937996
--- /dev/null
+++ b/src/main/java/com/zhgd/redis/lock/redisson/ILock.java
@@ -0,0 +1,33 @@
+package com.zhgd.redis.lock.redisson;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Objects;
+
+/**
+ *
+ * RedissonLock 包装的锁对象 实现AutoCloseable接口,在java7的try(with resource)语法,不用显示调用close方法
+ *
+ * @since 2023-06-08 16:57
+ */
+@AllArgsConstructor
+public class ILock implements AutoCloseable {
+ /**
+ * 持有的锁对象
+ */
+ @Getter
+ private Object lock;
+ /**
+ * 分布式锁接口
+ */
+ @Getter
+ private IDistributedLock distributedLock;
+
+ @Override
+ public void close() throws Exception {
+ if(Objects.nonNull(lock)){
+ distributedLock.unLock(lock);
+ }
+ }
+}
diff --git a/src/main/java/com/zhgd/redis/lock/redisson/RedissonDistributedLock.java b/src/main/java/com/zhgd/redis/lock/redisson/RedissonDistributedLock.java
new file mode 100644
index 000000000..cdf13f20e
--- /dev/null
+++ b/src/main/java/com/zhgd/redis/lock/redisson/RedissonDistributedLock.java
@@ -0,0 +1,99 @@
+package com.zhgd.redis.lock.redisson;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Component
+public class RedissonDistributedLock implements IDistributedLock {
+
+ @Resource
+ private RedissonClient redissonClient;
+ /**
+ * 统一前缀
+ */
+ @Value("${redisson.lock.prefix:bi:distributed:lock}")
+ private String prefix;
+
+ @Override
+ public ILock lock(String key) {
+ return this.lock(key, 0L, TimeUnit.SECONDS, false);
+ }
+
+ @Override
+ public ILock lock(String key, long lockTime, TimeUnit unit, boolean fair) {
+ RLock lock = getLock(key, fair);
+ // 获取锁,失败一直等待,直到获取锁,不支持自动续期
+ if (lockTime > 0L) {
+ lock.lock(lockTime, unit);
+ } else {
+ // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s
+ lock.lock();
+ }
+ return new ILock(lock, this);
+ }
+
+ @Override
+ public ILock tryLock(String key, long tryTime) throws Exception {
+ return this.tryLock(key, tryTime, 0L, TimeUnit.SECONDS, false);
+ }
+
+ @Override
+ public ILock tryLock(String key, long tryTime, long lockTime, TimeUnit unit, boolean fair)
+ throws Exception {
+ RLock lock = getLock(key, fair);
+ boolean lockAcquired;
+ // 尝试获取锁,获取不到超时异常,不支持自动续期
+ if (lockTime > 0L) {
+ lockAcquired = lock.tryLock(tryTime, lockTime, unit);
+ } else {
+ // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s
+ lockAcquired = lock.tryLock(tryTime, unit);
+ }
+ if (lockAcquired) {
+ return new ILock(lock, this);
+ }
+ return null;
+ }
+
+ /**
+ * 获取锁
+ *
+ * @param key
+ * @param fair
+ * @return
+ */
+ private RLock getLock(String key, boolean fair) {
+ RLock lock;
+ String lockKey = prefix + ":" + key;
+ if (fair) {
+ // 获取公平锁
+ lock = redissonClient.getFairLock(lockKey);
+ } else {
+ // 获取普通锁
+ lock = redissonClient.getLock(lockKey);
+ }
+ return lock;
+ }
+
+ @Override
+ public void unLock(Object lock) {
+ if (!(lock instanceof RLock)) {
+ throw new IllegalArgumentException("Invalid lock object");
+ }
+ RLock rLock = (RLock) lock;
+ if (rLock.isLocked()) {
+ try {
+ rLock.unlock();
+ } catch (IllegalMonitorStateException e) {
+ log.error("释放分布式锁异常", e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/zhgd/xmgl/modules/quality/controller/QualityRectifyRecordController.java b/src/main/java/com/zhgd/xmgl/modules/quality/controller/QualityRectifyRecordController.java
index 509adf909..a049cce3a 100644
--- a/src/main/java/com/zhgd/xmgl/modules/quality/controller/QualityRectifyRecordController.java
+++ b/src/main/java/com/zhgd/xmgl/modules/quality/controller/QualityRectifyRecordController.java
@@ -2,7 +2,6 @@ package com.zhgd.xmgl.modules.quality.controller;
import com.zhgd.annotation.OperLog;
import com.zhgd.jeecg.common.api.vo.Result;
-import com.zhgd.jeecg.common.mybatis.EntityMap;
import com.zhgd.xmgl.modules.quality.entity.QualityRectifyRecord;
import com.zhgd.xmgl.modules.quality.service.IQualityRectifyRecordService;
import io.swagger.annotations.Api;
@@ -54,7 +53,7 @@ public class QualityRectifyRecordController {
@OperLog(operModul = "质量管理", operType = "添加质量检查整改/复查记录信息", operDesc = "添加质量检查整改/复查记录信息")
@ApiOperation(value = "添加质量检查-整改/复查记录信息", notes = "添加质量检查-整改/复查记录信息", httpMethod = "POST")
@PostMapping(value = "/add")
- public Result add(@RequestBody QualityRectifyRecord qualityRectifyRecord) {
+ public Result add(@RequestBody QualityRectifyRecord qualityRectifyRecord) throws Exception {
qualityRectifyRecordService.saveQualityRectifyRecord(qualityRectifyRecord);
return Result.ok();
}
diff --git a/src/main/java/com/zhgd/xmgl/modules/quality/service/IQualityRectifyRecordService.java b/src/main/java/com/zhgd/xmgl/modules/quality/service/IQualityRectifyRecordService.java
index 41d47fdf9..a1cfe6712 100644
--- a/src/main/java/com/zhgd/xmgl/modules/quality/service/IQualityRectifyRecordService.java
+++ b/src/main/java/com/zhgd/xmgl/modules/quality/service/IQualityRectifyRecordService.java
@@ -19,7 +19,7 @@ public interface IQualityRectifyRecordService extends IService selectRectifyRecordList(Map map);
- void saveQualityRectifyRecord(QualityRectifyRecord qualityRectifyRecord);
+ void saveQualityRectifyRecord(QualityRectifyRecord qualityRectifyRecord) throws Exception;
void qualityInspectionRecordRectifyExportExcel(Map map, HttpServletResponse response) throws IOException;
}
diff --git a/src/main/java/com/zhgd/xmgl/modules/quality/service/impl/QualityRectifyRecordServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/quality/service/impl/QualityRectifyRecordServiceImpl.java
index 6009e66df..158389470 100644
--- a/src/main/java/com/zhgd/xmgl/modules/quality/service/impl/QualityRectifyRecordServiceImpl.java
+++ b/src/main/java/com/zhgd/xmgl/modules/quality/service/impl/QualityRectifyRecordServiceImpl.java
@@ -11,6 +11,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gexin.fastjson.JSON;
import com.gexin.fastjson.JSONArray;
import com.gexin.fastjson.JSONObject;
+import com.zhgd.redis.lock.redisson.DistributedLock;
+import com.zhgd.redis.lock.redisson.RedissonDistributedLock;
import com.zhgd.xmgl.call.SanjiangDataCall;
import com.zhgd.xmgl.modules.basicdata.service.INoticeService;
import com.zhgd.xmgl.modules.quality.entity.QualityInspectionRecord;
@@ -68,8 +70,12 @@ public class QualityRectifyRecordServiceImpl extends ServiceImpl