From 49efdbac662dce5758b46cbb9b68d6cc574062ee Mon Sep 17 00:00:00 2001 From: yuajs Date: Sat, 21 Sep 2024 17:59:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/interceptor/LoginInterceptor.java | 7 ++++- .../coupon/controller/CouponController.java | 23 ++++++++++++++- .../cn/nla/coupon/mq/CouponMQListener.java | 16 +++++----- .../service/impl/CouponServiceImpl.java | 29 ++++++++++++------- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/nla-common/src/main/java/cn/nla/common/interceptor/LoginInterceptor.java b/nla-common/src/main/java/cn/nla/common/interceptor/LoginInterceptor.java index ab0d19d..5d016e2 100644 --- a/nla-common/src/main/java/cn/nla/common/interceptor/LoginInterceptor.java +++ b/nla-common/src/main/java/cn/nla/common/interceptor/LoginInterceptor.java @@ -21,7 +21,10 @@ import javax.servlet.http.HttpServletResponse; public class LoginInterceptor implements HandlerInterceptor { public static ThreadLocal threadLocal = new ThreadLocal<>(); - + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + threadLocal.remove(); + } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { try { @@ -57,4 +60,6 @@ public class LoginInterceptor implements HandlerInterceptor { CommonUtil.sendJsonMessage(response, JsonData.buildError("token不存在,请重新登录")); return false; } + + } diff --git a/nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponController.java b/nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponController.java index ad308cf..fd2af1d 100644 --- a/nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponController.java +++ b/nla-coupon-service/src/main/java/cn/nla/coupon/controller/CouponController.java @@ -1,12 +1,19 @@ package cn.nla.coupon.controller; +import cn.nla.common.enums.BizCodeEnum; import cn.nla.common.enums.CouponCategoryEnum; +import cn.nla.common.exception.BizException; +import cn.nla.common.interceptor.LoginInterceptor; +import cn.nla.common.model.LoginUser; import cn.nla.common.util.JsonData; import cn.nla.coupon.model.request.NewUserCouponRequest; import cn.nla.coupon.service.CouponService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -20,12 +27,16 @@ import javax.annotation.Resource; * @since 2024-08-08 */ @Api(tags = "优惠券控制器") +@Slf4j @RestController @RequestMapping("/cop/coupon/v1") public class CouponController { @Resource private CouponService couponService; + @Resource + private RedissonClient redissonClient; + @ApiOperation("分页查询优惠券") @GetMapping("page_coupon") public JsonData pageCouponList( @@ -40,7 +51,17 @@ public class CouponController { @ApiOperation("领取优惠券") @GetMapping("/add/promotion/{coupon_id}") public JsonData addPromotionCoupon(@ApiParam(value = "优惠券id", required = true) @PathVariable("coupon_id") long couponId) { - return couponService.addCoupon(couponId, CouponCategoryEnum.NEW_USER); + LoginUser loginUser = LoginInterceptor.threadLocal.get(); + String lockKey = "lock:coupon:" + couponId+":"+loginUser.getId(); + RLock rLock = redissonClient.getLock(lockKey); + //多个线程进入,会阻塞等待释放锁 + rLock.lock(); + try { + return couponService.addCoupon(couponId, CouponCategoryEnum.NEW_USER); + } finally { + rLock.unlock(); + log.info("解锁成功"); + } } /** * 新用户注册发放优惠券接口 diff --git a/nla-coupon-service/src/main/java/cn/nla/coupon/mq/CouponMQListener.java b/nla-coupon-service/src/main/java/cn/nla/coupon/mq/CouponMQListener.java index a529489..bee4e95 100644 --- a/nla-coupon-service/src/main/java/cn/nla/coupon/mq/CouponMQListener.java +++ b/nla-coupon-service/src/main/java/cn/nla/coupon/mq/CouponMQListener.java @@ -4,6 +4,7 @@ import cn.nla.common.model.CouponRecordMessage; import cn.nla.coupon.service.CouponRecordService; import com.rabbitmq.client.Channel; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RedissonClient; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; @@ -11,6 +12,7 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.io.IOException; +import java.util.concurrent.locks.Lock; @Slf4j @Component @@ -20,8 +22,8 @@ public class CouponMQListener { @Resource private CouponRecordService couponRecordService; -// @Resource -// private RedissonClient redissonClient; + @Resource + private RedissonClient redissonClient; /** * 重复消费-幂等性 @@ -34,8 +36,8 @@ public class CouponMQListener { @RabbitHandler public void releaseCouponRecord(CouponRecordMessage recordMessage, Message message, Channel channel) throws IOException { //防止同个解锁任务并发进入;如果是串行消费不用加锁;加锁有利也有弊,看项目业务逻辑而定 - //Lock lock = redissonClient.getLock("lock:coupon_record_release:"+recordMessage.getTaskId()); - //lock.lock(); + Lock lock = redissonClient.getLock("lock:coupon_record_release:"+recordMessage.getTaskId()); + lock.lock(); log.info("监听到消息:releaseCouponRecord消息内容:{}", recordMessage); long msgTag = message.getMessageProperties().getDeliveryTag(); boolean flag = couponRecordService.releaseCouponRecord(recordMessage); @@ -51,9 +53,9 @@ public class CouponMQListener { log.error("释放优惠券记录异常:{},msg:{}", e, recordMessage); channel.basicReject(msgTag, true); } -// finally { -// lock.unlock(); -// } + finally { + lock.unlock(); + } } diff --git a/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java b/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java index a41e497..c32eba9 100644 --- a/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java +++ b/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java @@ -50,8 +50,8 @@ import java.util.stream.Collectors; @Service public class CouponServiceImpl extends ServiceImpl implements CouponService { - @Resource - private RedissonClient redissonClient; +// @Resource +// private RedissonClient redissonClient; @Resource private CouponRecordMapper couponRecordMapper; @@ -78,12 +78,12 @@ public class CouponServiceImpl extends ServiceImpl i @Override public JsonData addCoupon(Long couponId, CouponCategoryEnum category) { LoginUser loginUser = LoginInterceptor.threadLocal.get(); - String lockKey = "lock:coupon:" + couponId; - RLock rLock = redissonClient.getLock(lockKey); - //多个线程进入,会阻塞等待释放锁 - rLock.lock(); +// String lockKey = "lock:coupon:" + couponId+":"+loginUser.getId(); +// RLock rLock = redissonClient.getLock(lockKey); +// //多个线程进入,会阻塞等待释放锁 +// rLock.lock(); log.info("领劵接口加锁成功:{}", Thread.currentThread().getId()); - try { +// try { CouponEntity coupon = baseMapper.selectOne( Wrappers.lambdaQuery() .eq(CouponEntity::getId, couponId).eq(CouponEntity::getCategory, category.name())); @@ -108,10 +108,17 @@ public class CouponServiceImpl extends ServiceImpl i log.warn("发放优惠券失败:{},⽤户:{}", coupon, loginUser); throw new BizException(BizCodeEnum.COUPON_NO_STOCK); } - } finally { - rLock.unlock(); - log.info("解锁成功"); - } +// } finally { +// rLock.unlock(); +// log.info("解锁成功"); +// } + +// try { +// TimeUnit.SECONDS.sleep(10L); +// } catch (InterruptedException e) { +// throw new RuntimeException(e); +// } + return JsonData.buildSuccess(); }