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

目录:

(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) {
    // 获取到用户Id
    String 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:30
        redisTemplate.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缓存,同时更改秒杀商品活动结束

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/881286.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安全基础学习-AES128加密算法

前言 AES&#xff08;Advanced Encryption Standard&#xff09;是对称加密算法的一个标准&#xff0c;主要用于保护电子数据的安全。AES 支持128、192、和256位密钥长度&#xff0c;其中AES-128是最常用的一种&#xff0c;它使用128位&#xff08;16字节&#xff09;的密钥进…

推荐系统-电商直播 多目标排序算法探秘

前言&#xff1a; 电商直播已经成为电商平台流量的主要入口&#xff0c;今天我们一起探讨推荐算法在直播中所面临的核心问题和解决方案。以下内容参考阿里1688的技术方案整理完成。 一、核心问题介绍 在电商网站中&#xff0c;用户的主要行为是在商品上的行为&#xff0c;直播…

机器学习笔记(一)初识机器学习

1.定义 机器学习是一门多学科交叉专业&#xff0c;涵盖概率论知识&#xff0c;统计学知识&#xff0c;近似理论知识和复杂算法知识&#xff0c;使用计算机作为工具并致力于真实实时的模拟人类学习方式&#xff0c;并将现有内容进行知识结构划分来有效提高学习效率。 机器学习有…

JUC学习笔记(三)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 八、共享模型之工具--JUC8.1 AQS 原理1. 概述2 实现不可重入锁自定义同步器自定义锁 3.心得起源目标设计1) state 设计2&#xff09;阻塞恢复设计3&#xff09;队列…

Stable Diffusion不同部件拆分详解

看到很多文章对Stable Diffusion各种原理、详解等&#xff0c;但是么有看到有文章细拆里面各个子模块在做啥&#xff0c;怎么做的&#xff0c;所以就会遇到整体原理理解很透传&#xff0c;问到细节就卡住&#xff0c;这段时间细看了一下文章&#xff0c;对各个部分做一个拆解详…

网络基础,协议,OSI分层,TCP/IP模型

网络的产生是数据交流的必然趋势&#xff0c;计算机之间的独立的个体&#xff0c;想要进行数据交互&#xff0c;一开始是使用磁盘进行数据拷贝&#xff0c;可是这样的数据拷贝效率很低&#xff0c;于是网络交互便出现了&#xff1b; 1.网络是什么 网络&#xff0c;顾名思义是…

【SQL Server】清除日志文件ERRORLOG、tempdb.mdf

数据库再使用一段时间后&#xff0c;日志文件会增大&#xff0c;特别是在磁盘容量不足的情况下&#xff0c;更是需要缩减&#xff0c;以下为缩减方法&#xff1a; 如果可以停止 SQL Server 服务&#xff0c;那么可以采取更直接的方式来缩减 ERRORLOG 和 tempdb.mdf 文件的大小…

【IoTDB 线上小课 07】多类写入接口,快速易懂的“说明书”!

【IoTDB 视频小课】稳定更新中&#xff01;第七期来啦~ 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源... 一个问题重点&#xff0c;3-5 分钟&#xff0c;我们讲给你听&#xff1a; 一条视频了解写入接口 了解我们的友友们&#xff0c;应该…

centos 安装VNC,实现远程连接

centos 安装VNC&#xff0c;实现远程连接 VNC(Virtual Network Computing)是一种远程控制软件&#xff0c;可以实现通过网络远程连接计算机的图形界面。 服务器安装VNC服务 yum install -y tigervnc-server*启动VNC服务&#xff0c;过程中需要输入连接密码 vncserver :1查看…

【chromedriver编译-绕过selenium机器人检测】

有小伙伴说使用selenium没能绕过机器人检测&#xff0c;盘他。 selenium机器人检测有2种&#xff0c;一是cdp检测&#xff0c;二是webdriver特征检测。cdp检测前面的博客已写过&#xff0c;这里就提下webdriver特征检测。一、selenium简介 Selenium 是一个强大的工具&#xff…

硬件工程师笔试面试——开关

目录 11、开关 11.1 基础 开关原理图 开关实物图 11.1.1 概念 11.1.2 常见的开关类型及其应用 11.2 相关问题 11.2.1 开关的工作原理是什么? 11.2.2 在设计一个电子系统时,如何选择最适合的开关类型? 11.2.3 不同类型的开关在实际应用中有哪些优势和局限性? 11.…

css设置overflow:hiden行内元素会发生偏移的现象

父级元素包含几个行内元素 <div id"box"><p><span>按钮</span><span>测试文字文字文字测试文字文字文字</span><span>看这里</span></p></div>#box p{width: 800px;font-size: 30px;}#box p span{disp…

Android 如何使用jdk命令给应用/APK重新签名。

写在前面&#xff1a;本篇文章介绍Windows命令行中&#xff0c;如何使用jdk命令给已经签过名的apk重新签名。 使用工具&#xff1a;jarsigner。jarsigner是jdk自带的工具&#xff0c;签名之前确保Windows电脑中已安装jdk。我的环境如下&#xff1a;   后续操作步骤如下&…

【MySQL】了解并操作MySQL的缓存配置与信息

目录 一、查看缓存配置 二、查看缓存信息 查询MySQL的缓存相关信息&#xff0c;一般我们用两个命令&#xff1a; show variables like %query_cache%; show status like %qcache%; 一、查看缓存配置 查看缓存配置的相关的系统变量变量&#xff0c;返回给我们服务器缓存的配置…

Vue(13)——router-link

router-link vue-router提供了一个全局组件router-link(取代a标签) 能跳转&#xff0c;配置to属性指定路径&#xff08;必须&#xff09;。本质还是a标签。默认会提供高亮类名&#xff0c;可以直接设置高亮样式 右键检查&#xff0c;发现多了两个类&#xff1a; 可以直接写样式…

【React】React18.2.0核心源码解读

前言 本文使用 React18.2.0 的源码&#xff0c;如果想回退到某一版本执行git checkout tags/v18.2.0即可。如果打开源码发现js文件报ts类型错误请看本人另一篇文章&#xff1a;VsCode查看React源码全是类型报错如何解决。 阅读源码的过程&#xff1a; 下载源码 观察 package…

IPD流程体系:IPD在硬件产品开发中的应用

目录 1、内容简介 2、开发各阶段介绍 3、PVT阶段 4、资源群更新 作者简介 1、内容简介 在硬件类相关产品的开发过程中&#xff0c; 每个阶段的工作都是需要按照一定的流程、规范和标准去进行的。 整体还是相对瀑布化的流程&#xff0c; 每个阶段的输入、输出、准入、准…

第四天旅游线路预览——从贾登峪到喀纳斯景区入口(贾登峪游客服务中心)

第四天&#xff1a;从贾登峪到喀纳斯风景区入口&#xff0c;晚上住宿贾登峪&#xff1b; 从贾登峪到喀纳斯景区入口&#xff08;贾登峪游客服务中心&#xff09;&#xff1a; 搭乘贾登峪①路车&#xff0c;路过三湾到达景区换乘中心&#xff0c;路程时长约40分钟&#xff1b; …

autodl连接xftp

&#xff08;1&#xff09;首先打开xftp&#xff0c;新建会话 &#xff08;2&#xff09;给会话取个名字&#xff0c;然后填写主机和端口号 &#xff08;3&#xff09; 主机和端口号从autodl实例中找&#xff0c;登入指令那里 &#xff08;4&#xff09;点击复制&#xff0c;然…

展锐平台的手机camera 系统开发过程

展锐公司有自己的isp 图像处理引擎&#xff0c;从2012 年底就开始在智能手机上部署应用。最初的时候就几个人做一款isp的从hal 到kernel 驱动的完整软件系统&#xff0c;分工不是很明确&#xff0c;基本是谁擅长哪些就搞哪些&#xff0c;除了架构和编码实现之外&#xff0c;另外…