当前位置: 首页 > news >正文

尚品汇-秒杀成功下单接口、秒杀结束定时任务-清空缓存数据(五十四)

目录:

(1)下单页面

(2)service-activity-client添加接口

(3)web-all 编写去下单控制器

(4)service-order模块提供秒杀下单接口

 (5)service-order-client模块暴露接口

(6)service-activity模块秒杀下单

(7)秒杀结束清空redis缓存

(1)下单页面

我们已经把下单信息记录到redis缓存中,所以接下来我们要组装下单页数据

 下单页数据数据接口SeckillGoodsApiController

@Autowired
private RedisTemplate redisTemplate;
/*** 秒杀确认订单* @param request* @return*/
@GetMapping("auth/trade")
public Result trade(HttpServletRequest request) {// 获取到用户IdString userId = AuthContextHolder.getUserId(request);// 先得到用户想要购买的商品!OrderRecode orderRecode = (OrderRecode) redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).get(userId);if (null == orderRecode) {return Result.fail().message("非法操作");}//获取商品SeckillGoods seckillGoods = orderRecode.getSeckillGoods();//获取用户地址List<UserAddress> userAddressList = userFeignClient.findUserAddressListByUserId(userId);// 声明一个集合来存储订单明细ArrayList<OrderDetail> detailArrayList = new ArrayList<>();OrderDetail orderDetail = new OrderDetail();orderDetail.setSkuId(seckillGoods.getSkuId());orderDetail.setSkuName(seckillGoods.getSkuName());orderDetail.setImgUrl(seckillGoods.getSkuDefaultImg());orderDetail.setSkuNum(orderRecode.getNum());orderDetail.setOrderPrice(seckillGoods.getCostPrice());// 添加到集合detailArrayList.add(orderDetail);// 计算总金额  创建订单对象,计算订单价格OrderInfo orderInfo = new OrderInfo();orderInfo.setOrderDetailList(detailArrayList);orderInfo.sumTotalAmount();Map<String, Object> result = new HashMap<>();result.put("userAddressList", userAddressList);result.put("detailArrayList", detailArrayList);result.put("totalNum", 1);// 保存总金额result.put("totalAmount", orderInfo.getTotalAmount());return Result.ok(result);
}

(2)service-activity-client添加接口

ActivityFeignClient
/*** 秒杀确认订单* @return*/
@GetMapping("/api/activity/seckill/auth/trade")
Result<Map<String, Object>> trade();

ActivityDegradeFeignClient 


@Override
public Result<Map<String, Object>> trade() {return Result.fail();
}

(3)web-all 编写去下单控制器

SeckillController

/*** 确认订单* @param model* @return*/
@GetMapping("seckill/trade.html")
public String trade(Model model) {Result<Map<String, Object>> result = activityFeignClient.trade();if(result.isOk()) {model.addAllAttributes(result.getData());return "seckill/trade";} else {model.addAttribute("message",result.getMessage());return "seckill/fail";}
}

Result

package com.atguigu.gmall.common.result;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** 全局统一返回结果类**/
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")private T data;public Result(){}// 返回数据protected static <T> Result<T> build(T data) {Result<T> result = new Result<T>();if (data != null)result.setData(data);return result;}public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {Result<T> result = build(body);result.setCode(resultCodeEnum.getCode());result.setMessage(resultCodeEnum.getMessage());return result;}public static<T> Result<T> ok(){return Result.ok(null);}/*** 操作成功* @param data* @param <T>* @return*/public static<T> Result<T> ok(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.SUCCESS);}public static<T> Result<T> fail(){return Result.fail(null);}/*** 操作失败* @param data* @param <T>* @return*/public static<T> Result<T> fail(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.FAIL);}public Result<T> message(String msg){this.setMessage(msg);return this;}public Result<T> code(Integer code){this.setCode(code);return this;}public boolean isOk() {if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {return true;}return false;}
}

 

下单确认页面

该页面与正常下单页面类似,只是下单提交接口不一样,因为秒杀下单不需要正常下单的各种判断,因此我们要在订单服务提供一个秒杀下单接口,直接下单

(4)service-order模块提供秒杀下单接口

 

OrderApiController :提供一个重载的下单方法       
/*** 秒杀提交订单,秒杀订单不需要做前置判断,直接下单* @param orderInfo* @return*/
@PostMapping("inner/seckill/submitOrder")
public Long submitOrder(@RequestBody OrderInfo orderInfo) {Long orderId = orderService.saveOrderInfo(orderInfo);return orderId;
}

  (5)service-order-client模块暴露接口

OrderFeignClient
/*** 提交秒杀订单* @param orderInfo* @return*/
@PostMapping("/api/order/inner/seckill/submitOrder")
Long submitOrder(@RequestBody OrderInfo orderInfo);

OrderDegradeFeignClient 


@Override
public Long submitOrder(OrderInfo orderInfo) {return null;
}

(6)service-activity模块秒杀下单

SeckillGoodsApiController
@Autowired
private OrderFeignClient orderFeignClient;@PostMapping("auth/submitOrder")
public Result submitOrder(@RequestBody OrderInfo orderInfo, HttpServletRequest request) {String userId = AuthContextHolder.getUserId(request);orderInfo.setUserId(Long.parseLong(userId));Long orderId = orderFeignClient.submitOrder(orderInfo);if (null == orderId) {return Result.fail().message("下单失败,请重新操作");}//删除下单信息 临时订单
redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).delete(userId);//添加一个用户订单记录  下单记录  总订单
redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).put(userId, orderId.toString());return Result.ok(orderId);
}

页面提交订单代码片段

submitOrder() {seckill.submitOrder(this.order).then(response => {if (response.data.code == 200) {window.location.href = 'http://payment.gmall.com/pay.html?orderId=' + response.data.data} else {alert(response.data.message)}})
},

 

 

 

说明:下单成功后,后续流程与正常订单一致

(7)秒杀结束清空redis缓存

秒杀过程中我们写入了大量redis缓存,我们可以在秒杀结束或每天固定时间清楚缓存

,释放缓存空间;

实现思路:假如根据业务,我们确定每天18点所有秒杀业务结束,那么我们编写定时任务,每天18点发送mq消息,service-activity模块监听消息清理缓存

Service-task发送消息

添加常量MqConst

/*** 定时任务*/
public static final String ROUTING_TASK_18 = "seckill.task.18";
//队列
public static final String QUEUE_TASK_18  = "queue.task.18";

 

编写定时任务发送消息

/*** 每天下午18点执行*/
//@Scheduled(cron = "0/35 * * * * ?")
@Scheduled(cron = "0 0 18 * * ?")
public void task18() {rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_TASK, MqConst.ROUTING_TASK_18, "");
}

接收消息并处理

Service-activity接收消息

SeckillReceiver

//  监听删除消息!每天18点清空数据
@SneakyThrows
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_TASK_18,durable = "true",autoDelete = "false"),exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),key = {MqConst.ROUTING_TASK_18}
))
public void deleteRedisData(Message message, Channel channel){try {//  查询哪些商品是秒杀结束的!end_time , status = 1//  select * from seckill_goods where status = 1 and end_time < new Date();QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();seckillGoodsQueryWrapper.eq("status",1);seckillGoodsQueryWrapper.le("end_time",new Date());List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);//  对应将秒杀结束缓存中的数据删除!for (SeckillGoods seckillGoods : seckillGoodsList) {//  seckill:stock:46 删除库存对应key  删除List集合redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId());//   删除预热// redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).delete(seckillGoods.getSkuId());}//  删除预热等数据! 主要针对于预热数据删除! 我们项目只针对一个商品的秒杀! 如果是多个秒杀商品,则不能这样直接删除预热秒杀商品的key!//  46 : 10:00 -- 10:30 | 47 : 18:10 -- 18:30redisTemplate.delete(RedisConst.SECKILL_GOODS);//  预下单  临时订单redisTemplate.delete(RedisConst.SECKILL_ORDERS);//  删除真正下单数据 总订单记录redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);//  修改数据库秒杀对象的状态!SeckillGoods seckillGoods = new SeckillGoods();//  1:表示审核通过 ,2:表示秒杀结束seckillGoods.setStatus("2");seckillGoodsMapper.update(seckillGoods,seckillGoodsQueryWrapper);} catch (Exception e) {e.printStackTrace();}//  手动确认消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}

用户是否抢单信息我们这里在前面存储的时候可以设置超时时间就行了,这里就不用清楚了,因为这里不好获取用户id

说明:情况redis缓存,同时更改秒杀商品活动结束

行秒杀下单,提交成功,页面通过轮询后台方法查询秒杀状态

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • html文件指什么
  • 使用k8s搭建mariadb+nginx+wordpress
  • 【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第一篇-原理】
  • 【大模型教程】基于 InternLM 和 LangChain 搭建知识库助手
  • Java后端框架---Spring
  • R18 NES 之SSB-less SCell operation for inter-band CA
  • [ IDE ] SEGGER Embedded Studio for RISC-V
  • C#为任意组件开发登录功能的记录
  • SpringBoot 数据库表结构文档生成
  • mysql mha高可用集群搭建
  • 【多线程】CAS的原理及应用,看这篇文章就够啦
  • Elasticsearch集群的运维与管理
  • Kafka 为什么这么快?
  • 黑客是如何绕过ssh登录目标站点
  • 【linux】4张卡,坏了1张,怎么办?
  • $translatePartialLoader加载失败及解决方式
  • classpath对获取配置文件的影响
  • es6
  • ESLint简单操作
  • exif信息对照
  • JavaScript的使用你知道几种?(上)
  • Javascript基础之Array数组API
  • Java多线程(4):使用线程池执行定时任务
  • Js基础——数据类型之Null和Undefined
  • magento 货币换算
  • nodejs调试方法
  • 对象管理器(defineProperty)学习笔记
  • 模型微调
  • 如何实现 font-size 的响应式
  • 使用docker-compose进行多节点部署
  • 跳前端坑前,先看看这个!!
  • 网络应用优化——时延与带宽
  • 微信小程序设置上一页数据
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • #100天计划# 2013年9月29日
  • #stm32驱动外设模块总结w5500模块
  • (35)远程识别(又称无人机识别)(二)
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (笔试题)合法字符串
  • (二)斐波那契Fabonacci函数
  • (二)构建dubbo分布式平台-平台功能导图
  • (二开)Flink 修改源码拓展 SQL 语法
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (七)Java对象在Hibernate持久化层的状态
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (一)kafka实战——kafka源码编译启动
  • (转)EOS中账户、钱包和密钥的关系
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .net 8 发布了,试下微软最近强推的MAUI
  • .NET MVC第五章、模型绑定获取表单数据
  • .Net Web项目创建比较不错的参考文章