From 726f1ac3198634adea7a09375f012382bc77b959 Mon Sep 17 00:00:00 2001 From: ZZ Date: Tue, 11 Jan 2022 17:01:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=87=E9=9D=A2+=E6=B3=A8=E8=A7=A3=E9=98=B2?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=8F=90=E4=BA=A4,@NoRepeatSubmit=E9=BB=98?= =?UTF-8?q?=E8=AE=A410=E7=A7=92=E5=86=85=E5=8F=AA=E8=83=BD=E6=8F=90?= =?UTF-8?q?=E4=BA=A41=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/NoRepeatSubmit.java | 19 +++++ .../common/data/redis/StaticBeanUtil.java | 16 +++++ .../com/xhpc/common/util/RequestUtils.java | 16 +++++ .../payment/aspect/RepeatSubmitAspect.java | 71 +++++++++++++++++++ .../controller/XhpcRefundOrderController.java | 2 + 5 files changed, 124 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/xhpc/common/core/annotation/NoRepeatSubmit.java create mode 100644 xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/util/RequestUtils.java create mode 100644 xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/aspect/RepeatSubmitAspect.java diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/xhpc/common/core/annotation/NoRepeatSubmit.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/xhpc/common/core/annotation/NoRepeatSubmit.java new file mode 100644 index 00000000..697fb04b --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/xhpc/common/core/annotation/NoRepeatSubmit.java @@ -0,0 +1,19 @@ +package com.xhpc.common.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface NoRepeatSubmit { + + /* + * 防止重复提交标记注解 + * 设置请求锁定时间 + * @return + */ + int lockTime() default 10; + +} diff --git a/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/data/redis/StaticBeanUtil.java b/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/data/redis/StaticBeanUtil.java index 734b19dc..57a5a0f3 100644 --- a/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/data/redis/StaticBeanUtil.java +++ b/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/data/redis/StaticBeanUtil.java @@ -4,12 +4,14 @@ import cn.hutool.core.date.DateUtil; import com.xhpc.common.api.PileOrderService; import com.xhpc.common.redis.service.RedisService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.support.atomic.RedisAtomicInteger; import org.springframework.data.redis.support.atomic.RedisAtomicLong; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.Calendar; import java.util.Date; +import java.util.concurrent.TimeUnit; @Component public class StaticBeanUtil { @@ -30,6 +32,20 @@ public class StaticBeanUtil { REDIS = redisService; } + public static Boolean tryLock(String key, long expr) { + + System.out.println("try lock..."); + RedisAtomicInteger counter = new RedisAtomicInteger(key, REDIS.redisTemplate.getConnectionFactory()); + counter.expire(expr, TimeUnit.SECONDS); + long result = counter.incrementAndGet(); + return result == 1; + } + + public static Boolean releaseLock(String key) { + + return REDIS.deleteObject(key); + } + public synchronized static String seqHex(String key) { String upperCode = ""; diff --git a/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/util/RequestUtils.java b/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/util/RequestUtils.java new file mode 100644 index 00000000..5dc05a1c --- /dev/null +++ b/xhpc-modules/xhpc-common/src/main/java/com/xhpc/common/util/RequestUtils.java @@ -0,0 +1,16 @@ +package com.xhpc.common.util; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; + +public class RequestUtils { + + public static HttpServletRequest getRequest() { + + ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + return ra.getRequest(); + } + +} diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/aspect/RepeatSubmitAspect.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/aspect/RepeatSubmitAspect.java new file mode 100644 index 00000000..d38a6b6e --- /dev/null +++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/aspect/RepeatSubmitAspect.java @@ -0,0 +1,71 @@ +package com.xhpc.payment.aspect; + +import com.xhpc.common.core.annotation.NoRepeatSubmit; +import com.xhpc.common.core.web.domain.AjaxResult; +import com.xhpc.common.data.redis.StaticBeanUtil; +import com.xhpc.common.util.RequestUtils; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import javax.servlet.http.HttpServletRequest; + +@Aspect +@Component +public class RepeatSubmitAspect { + + private static final Logger LOGGER = LoggerFactory.getLogger(RepeatSubmitAspect.class); + + + @Pointcut("@annotation(noRepeatSubmit)") + public void pointCut(NoRepeatSubmit noRepeatSubmit) { + + } + + @Around("pointCut(noRepeatSubmit)") + public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable { + + int lockSeconds = noRepeatSubmit.lockTime(); + + HttpServletRequest request = RequestUtils.getRequest(); + Assert.notNull(request, "request can't be null"); + + // 此处可以用token或者JSessionId + String token = request.getHeader("Authorization"); + String path = request.getServletPath(); + String key = getKey(token, path); + + boolean isSuccess = StaticBeanUtil.tryLock(key, lockSeconds); + LOGGER.info("tryLock key = [{}]", key); + // 主要逻辑 + if (isSuccess) { + LOGGER.info("tryLock success, key = [{}]", key); + // 获取锁成功 + Object result; +// try { + // 执行进程 + result = pjp.proceed(); +// } finally { + // 解锁 +// StaticBeanUtil.releaseLock(key); +// LOGGER.info("releaseLock success, key = [{}]", key); +// } + return result; + } else { + // 获取锁失败,认为是重复提交的请求。 + LOGGER.info("tryLock fail, key = [{}]", key); + return new AjaxResult(200, "重复请求,请稍后再试", null); + } + } + + private String getKey(String token, String path) { + + return "lock".concat(path.replace("/", ":").concat(token.replaceAll(" ", ""))); + } + +} diff --git a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/XhpcRefundOrderController.java b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/XhpcRefundOrderController.java index 86b29c50..2be40601 100644 --- a/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/XhpcRefundOrderController.java +++ b/xhpc-modules/xhpc-payment/src/main/java/com/xhpc/payment/controller/XhpcRefundOrderController.java @@ -1,5 +1,6 @@ package com.xhpc.payment.controller; +import com.xhpc.common.core.annotation.NoRepeatSubmit; import com.xhpc.common.core.constant.HttpStatus; import com.xhpc.common.core.constant.StatusConstants; import com.xhpc.common.core.utils.StringUtils; @@ -35,6 +36,7 @@ public class XhpcRefundOrderController extends BaseController { * * @return */ + @NoRepeatSubmit @PostMapping("/checkOut") @ApiOperation(value = "申请退款") public AjaxResult enterpriseCheckOut(@RequestBody Map map) {