订单令牌防重提交开发

This commit is contained in:
jieyuu 2024-11-09 16:57:38 +08:00
parent 760dc505cc
commit ee4dcde935
3 changed files with 53 additions and 1 deletions

View File

@ -10,4 +10,9 @@ public class CacheKey {
* 购物车 hash 结果 , key是用户唯一标识
*/
public final static String CART_KEY = "cart:%s";
/**
* 提交表单的token key
*/
public final static String SUBMIT_ORDER_TOKEN_KEY = "order:submit:%s";
}

View File

@ -10,9 +10,12 @@ import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import net.jieyuu.config.AlipayConfig;
import net.jieyuu.config.PayUrlConfig;
import net.jieyuu.constant.CacheKey;
import net.jieyuu.enums.BizCodeEnum;
import net.jieyuu.enums.ClientType;
import net.jieyuu.enums.ProductOrderPayTypeEnum;
import net.jieyuu.interceptor.LoginInterceptor;
import net.jieyuu.model.LoginUser;
import net.jieyuu.request.ConfirmOrderRequest;
import net.jieyuu.request.RepayOrderRequest;
import net.jieyuu.service.ProductOrderService;
@ -20,14 +23,15 @@ import net.jieyuu.utils.CommonUtil;
import net.jieyuu.utils.JsonData;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* <p>
@ -49,6 +53,26 @@ public class ProductOrderController {
@Autowired
private PayUrlConfig payUrlConfig;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 避免重复下单操作
* 下单前请求接口获取令牌
*
* @return
*/
@ApiOperation("获取提交订单令牌")
@GetMapping("get_token")
public JsonData getOrderToken() {
LoginUser loginUser = LoginInterceptor.threadLocal.get();
String key = String.format(CacheKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getId());
String token = CommonUtil.getStringNumRandom(32);
redisTemplate.opsForValue().set(key, token, 30, TimeUnit.MINUTES);
return JsonData.buildSuccess(token);
}
/**
* 分页查询商品列表
*

View File

@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.jieyuu.component.PayFactory;
import net.jieyuu.config.RabbitMQConfig;
import net.jieyuu.constant.CacheKey;
import net.jieyuu.constant.TimeConstant;
import net.jieyuu.enums.*;
import net.jieyuu.exception.BizException;
@ -29,6 +30,8 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -72,6 +75,9 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
@Autowired
private PayFactory payFactory;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* * 防重提交
* * 用户微服务-确认收货地址
@ -93,6 +99,23 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
@Transactional
public JsonData confirmOrder(ConfirmOrderRequest orderRequest) {
LoginUser loginUser = LoginInterceptor.threadLocal.get();
String orderToken = orderRequest.getToken();
if (StringUtils.isBlank(orderToken)) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_NOT_EXIST);
}
// lua原子操作校验令牌
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
Arrays.asList(String.format(CacheKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getId())), orderToken);
if(result == 0L){
throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
}
// 32位uuid订单号
String orderOutTradeNo = CommonUtil.getStringNumRandom(32);
// 获取收货地址