Commit 5bbff7b3 by 吕明尚

修改验券幂等

parent a35eee80
......@@ -177,11 +177,6 @@
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package share.common.utils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Objects;
/**
* @ClassName RedisLockUtil
* @Description 使用redis做锁
* @Author Wangyujie
* @Version V1.1.0
*/
@Component
public class RedisLockUtil {
@Resource
RedisTemplate<String, Object> redisTemplate;
/**
* 获取锁Key
*
* @param prefix 前缀
* @param name 名称
* @return
*/
public static String getFullKey(String prefix, String name) {
return prefix + "_" + name;
}
/**
* 获取锁,true 则得到锁,false 已被锁定
*
* @param lockName 锁名称
* @param lockExoire 锁时间毫秒
* @return
*/
public Boolean getLock(String lockName, Integer lockExoire) {
return (Boolean) redisTemplate.execute((RedisCallback<?>) connection -> {
// 获取时间毫秒值
long expireAt = System.currentTimeMillis() + lockExoire + 1;
// 获取锁
Boolean acquire = connection.setNX(lockName.getBytes(), String.valueOf(expireAt).getBytes());
if (acquire) {
return true;
} else {
byte[] bytes = connection.get(lockName.getBytes());
// 非空判断
if (Objects.nonNull(bytes) && bytes.length > 0) {
long expireTime = Long.parseLong(new String(bytes));
// 如果锁已经过期
if (expireTime < System.currentTimeMillis()) {
// 重新加锁,防止死锁
byte[] set = connection.getSet(lockName.getBytes(),
String.valueOf(System.currentTimeMillis() + lockExoire + 1).getBytes());
return Long.parseLong(new String(set)) < System.currentTimeMillis();
}
}
}
return false;
});
}
/**
* 删除锁
*
* @param lockName
*/
public void delLock(String lockName) {
redisTemplate.delete(lockName);
}
}
package share.common.utils.aop;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RepeatSubmit {
String key() default "";
}
package share.common.utils.aop;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
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.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class RepeatSubmitAspect {
private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()
// 最大缓存 设置为1000个
.maximumSize(1000)
// 设置写缓存后1s过期
.expireAfterWrite(1, TimeUnit.SECONDS)
.build();
@Around("execution(public * *(..)) && @annotation(share.common.utils.aop.RepeatSubmit))")
public Object interceptor(ProceedingJoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
RepeatSubmit repeatSubmit = method.getAnnotation(RepeatSubmit.class);
String key = getKey(repeatSubmit.key(), pjp.getArgs());
if (StringUtils.isNotBlank(key)) {
if (CACHES.getIfPresent(key) != null) {
throw new RuntimeException("请勿重复请求");
}
// 如果是第一次请求,就将key 当前对象压入缓存中
CACHES.put(key, key);
}
try {
return pjp.proceed();
} catch (Throwable throwable) {
throw new RuntimeException("服务器异常!");
}
}
/**
* key 的生成策略
*
* @param keyExpress 表达式
* @param args 参数
* @return 生成的key
*/
private String getKey(String keyExpress, Object[] args) {
for (int i = 0; i < args.length; i++) {
keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
}
return keyExpress;
}
}
......@@ -32,7 +32,7 @@ import share.common.core.redis.RedisUtil;
import share.common.enums.*;
import share.common.exception.base.BaseException;
import share.common.utils.DateUtils;
import share.common.utils.aop.RepeatSubmit;
import share.common.utils.RedisLockUtil;
import share.system.domain.SConsumer;
import share.system.domain.SConsumerCoupon;
import share.system.domain.SCoupon;
......@@ -78,6 +78,9 @@ public class QPServiceImpl implements QPService {
private RedisUtil redisUtil;
@Autowired
private RedisLockUtil redisLockUtil;
@Autowired
private ISStoreService storeService;
//默认门槛时长
......@@ -101,13 +104,14 @@ public class QPServiceImpl implements QPService {
* 用户验卷接口
*/
@Override
@RepeatSubmit(key = "美团验卷")
public String consumeByUser(String code, String storeId, String status) throws Exception {
//获取用户信息
SConsumer user = FrontTokenComponent.getWxSConsumerEntry();
if (ObjectUtil.isNull(user)) {
throw new BaseException("您的登录已过期,请先登录");
}
Boolean lock = redisLockUtil.getLock(String.valueOf(user.getId()), 1000);
if (lock) {
LambdaQueryWrapper<SStore> sStoreLambdaQueryWrapper = new LambdaQueryWrapper<>();
sStoreLambdaQueryWrapper.eq(SStore::getId, storeId);
SStore sStore = storeService.getOne(sStoreLambdaQueryWrapper);
......@@ -117,8 +121,6 @@ public class QPServiceImpl implements QPService {
if (StringUtils.isEmpty(sStore.getOpenShopUuid())) {
throw new Exception("门店未授权,请联系客服");
}
//验券准备
TuangouReceiptPrepareResponseEntity prepare = prepare(code.trim(), sStore.getOpenShopUuid(), status);
//查询领取记录表
LambdaQueryWrapper<SConsumerCoupon> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SConsumerCoupon::getCouponCode, code);
......@@ -128,6 +130,8 @@ public class QPServiceImpl implements QPService {
if (ObjectUtils.isNotEmpty(unUsedCoupon)) {
throw new Exception("该券码已被使用");
}
//验券准备
TuangouReceiptPrepareResponseEntity prepare = prepare(code.trim(), sStore.getOpenShopUuid(), status);
//根据优惠卷名称查询优惠劵配置 查询list,取第一个
SConsumerCoupon sConsumerCoupon = new SConsumerCoupon();
sConsumerCoupon.setConsumerId(user.getId());
......@@ -208,9 +212,11 @@ public class QPServiceImpl implements QPService {
}
isConsumerCouponService.insertSConsumerCoupon(sConsumerCoupon);
//核销美团券
// qpService.consume(code.trim(), 1, sStore.getOpenShopUuid(), status);
qpService.consume(code.trim(), 1, sStore.getOpenShopUuid(), status);
return "验劵成功";
}
throw new RuntimeException("验劵失败");
}
@Override
public List<TuangouReceiptReverseConsumeResponseEntity> reverseconsumeByUser(Long id) {
......
......@@ -20,7 +20,7 @@ import org.springframework.util.CollectionUtils;
import share.common.core.redis.RedisUtil;
import share.common.enums.*;
import share.common.exception.base.BaseException;
import share.common.utils.aop.RepeatSubmit;
import share.common.utils.RedisLockUtil;
import share.system.domain.SConsumer;
import share.system.domain.SConsumerCoupon;
import share.system.domain.SCoupon;
......@@ -55,6 +55,9 @@ public class TiktokServiceImpl implements TiktokService {
private RedisUtil redisUtil;
@Autowired
private RedisLockUtil redisLockUtil;
@Autowired
private ISStoreService storeService;
@Autowired
......@@ -352,12 +355,13 @@ public class TiktokServiceImpl implements TiktokService {
}
@Override
@RepeatSubmit(key = "抖音验卷")
public String consumeByUser(String code, String storeId) throws Exception {
SConsumer user = FrontTokenComponent.getWxSConsumerEntry();
if (ObjectUtil.isNull(user)) {
throw new BaseException("您的登录已过期,请先登录");
}
Boolean lock = redisLockUtil.getLock(String.valueOf(user.getId()), 1000);
if (lock) {
LambdaQueryWrapper<SStore> sStoreLambdaQueryWrapper = new LambdaQueryWrapper<>();
sStoreLambdaQueryWrapper.eq(SStore::getId, storeId);
SStore sStore = storeService.getOne(sStoreLambdaQueryWrapper);
......@@ -482,6 +486,8 @@ public class TiktokServiceImpl implements TiktokService {
}
return "验卷成功";
}
throw new RuntimeException("验劵失败");
}
@Override
public List<TiktokPoi> poiList() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment