谷粒商城实战笔记-275~276-商城业务-订单服务-订单确认页完成
文章目录
- 一,275-商城业务-订单服务-订单确认页完成
- 1,防止订单重复提交
- 二,276-商城业务-订单服务-原子验令牌
- Lua 脚本
- Java 代码
包括内容:
- 275-商城业务-订单服务-订单确认页完成
- 276-商城业务-订单服务-原子验令牌
一,275-商城业务-订单服务-订单确认页完成
这一节的主要内容是:
- 分析用户点击“提交订单”时,前端发送给后台的数据,包括token,总金额,收货地址,支付方式
public class OrderSubmitVo {
/** 收获地址的id **/
private Long addrId;
/** 支付方式 **/
private Integer payType;
//无需提交要购买的商品,去购物车再获取一遍
//优惠、发票
/** 防重令牌 **/
private String orderToken;
/** 应付价格 **/
private BigDecimal payPrice;
/** 订单备注 **/
private String remarks;
//用户相关的信息,直接去session中取出即可
}
- 前端收集数据,发生提交订单请求
- 后端封装Vo接收请求
1,防止订单重复提交
这一节是订单提交的业务,核心是防止重复提交,防止重复提交的逻辑:
- 防重token,进入结算页之前调用后台接口,生成一个token
- token返回给前端同时保存在redis
- 一定要在进入结算页之前生成,保证刷新结算页不会重新生成token
- 点击“提交订单”时携带token
- 后端有token且和前端一致,说明不是重复提交,允许生成订单
- 同时删除token
- 订单还没创建完成,前端再次提交,因为后端token已经删除,所以不能创建订单
- 生成订单
疑问:删除了token,前端再次提交订单无效,如果第一次创建订单失败,token又被删除了该怎么办?
可能的解决方案:后端创建失败,给前端一个反馈,前端重新去购物车点击“去结算”,重新走生成订单的流程。
二,276-商城业务-订单服务-原子验令牌
这一节的重要内容:
- 封装下定接口响应数据接口,考虑下定成功和识别两种情况,下单成功返回订单信息,下单失败返回错误信息
- 分析下单流程,第一步是验证令牌是否合法
验证令牌合法后,会删除令牌,要保证:
- 从redis获取令牌
- 验证令牌
- 删除令牌
这三个步骤是一个原子操作,需要使用lua脚本。
tring script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
String orderToken = vo.getOrderToken();
//通过lure脚本原子验证令牌和删除令牌
Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
Arrays.asList(USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId()),
orderToken);
if (result == 0L) {
//令牌验证失败
responseVo.setCode(1);
return responseVo;
}
这段代码主要是在使用 Redis 来实现一个基于 Lua 脚本的原子性操作。用于验证并删除一个订单令牌(orderToken
),以确保每个订单只能被处理一次。
Lua 脚本
首先,定义了一个 Lua 脚本 script
,其功能是检查给定的键 (KEYS[1]
) 中存储的值是否与提供的参数 (ARGV[1]
) 相匹配:
- 如果匹配,则删除该键并返回删除操作的结果(通常情况下删除成功会返回 1)。
- 如果不匹配,则返回 0。
Java 代码
接下来是 Java 代码部分,其执行了以下操作:
-
获取令牌:
vo.getOrderToken()
从某个对象vo
中获取orderToken
字符串,这个字符串应该是之前存储在 Redis 中的一个唯一标识符。
-
执行 Lua 脚本:
- 使用
redisTemplate.execute
方法来执行 Lua 脚本。 new DefaultRedisScript<Long>(script, Long.class)
创建一个新的DefaultRedisScript
对象,并设置返回类型为Long
类型。Arrays.asList(USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId())
指定了要操作的 Redis 键名,键名是由前缀USER_ORDER_TOKEN_PREFIX
和用户 ID 组成。orderToken
是作为脚本参数传递给 Lua 脚本的,用于进行比较。
- 使用
-
结果判断:
- 如果 Lua 脚本返回的结果为
0L
,这意味着令牌验证失败(即 Redis 中的值与orderToken
不匹配或者键不存在)。 - 如果令牌验证失败,将
responseVo
的code
属性设置为1
并返回responseVo
。
- 如果 Lua 脚本返回的结果为