Laravel8.5+微信小程序实现京东商城秒杀方案

news2024/11/30 13:54:39

一、商品秒杀涉及的知识点

  • 鉴权策略封装
  • 掊口访问频次限制
  • 小程序设计
  • 页面防抖
  • 接口调用
  • 订单创建事务使用
  • 超卖防御

二、订单库存系统方案(3种)

扣库存的集中方案

  1. 下单减库存 优点是库存和订单的强一致性,商品不会卖超,但是可能导致恶意下单,影响正常流程
  2. 支付减库存 优点是避免恶意下单,支付和库存强一致性,但是可能出现订单无法支付,商品库存不足等问题。
  3. 预扣库存 预扣库存是指用户请求之后预扣库存,生成订单,在时效内支付,否则订单失效,库存还原
  4. 代码:itshujia.com 或者wx搜:《IT书架》 回复:秒杀

三、小程序秒杀页面

  • 商品秒杀详情页面页面
  • 该商品秒杀时间未到,则上方进行提醒秒杀商品倒计时,并且立即抢购禁用(按钮置灰)

image.png

  • 商品秒杀时间开始,则把立即秒杀按钮禁用状态改为可以点击
  • 点击立即秒杀按钮要考虑页面防抖,不能重复在同一秒中重复发起N次网络请求
    image.png

四、小程序部分代码展示

  1. 小程序wxml代码
<view>商品秒杀页面</view>
<l-countdown time-type="second" time="{{expire_time}}" bind:linend="changeBtn" />
<l-card type="primary" full="{{true}}" image="{{goods.goods.goods_image}}" title="{{goods.goods.goods_name}}">
     <view>
       价格:{{goods.goods.goods_price}}
     </view>
     <view>
     <!-- <button disabled="true" bindtap="buyGoods" >抢购</button> -->
      <l-button disabled="{{ btn_disable }}" bind:lintap="buyGoods" type="error" data-goods_id="{{ goods.goods.id }}">立即秒杀</l-button>
     </view>
  </l-card>
  1. 小程序js代码
// pages/goods_detail/goods_detail.js
import {
  debounce
} from "../../utils/util"

Page({

  /**
   * 页面的初始数据
   */
  data: {
   goods:{},
   expire_time:0,
   btn_disable:false
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (e) {
     //商品id
     let goods_id = e.goods_id;
     this.getGoodsDetail(goods_id)
  },
  //获取商品详情
  getGoodsDetail(goods_id){
    var token = wx.getStorageSync('token')
    wx.request({
      url: 'http://www.zfw.com/api/v1/goods_detail?goods_id='+goods_id,
      header: {
        'Authorization': `Bearer ${token}`
      },
      success: res => {
        //当前的时间戳
        let now_time = Math.round(new Date().getTime() / 1000).toString();
        let expire_time = res.data.data.start_time-now_time;
        this.setData({
          goods:res.data.data,
          expire_time
        })
        if(expire_time > 0){
          this.setData({
            btn_disable:true
          })
        }
        console.log(this.data.goods)
      }
    })
  },
  //立即抢购   debounce此方法是引入的util工具类的页面防抖函数
  buyGoods:debounce(function (e) {
    let goods_id = e[0].currentTarget.dataset.goods_id
    var token = wx.getStorageSync('token')
    wx.request({
      url: 'http://www.zfw.com/api/v1/snap_up',
      header: {
        'Authorization': `Bearer ${token}`
      },
      method:"POST",
      data:{
        goods_id
      },
      success: res => {
        let code = res.statusCode.toString()
        if (!code.startsWith('2')){
           wx.showToast({
             title: '异常!',
             icon:1
           })
        }
        
        if(res.data.errorCode == 0){
            wx.redirectTo({
              url: '/pages/order/order',
            })
        }else{
          wx.showToast({
            title: res.data.msg,
          })
        }
        console.log(res.data)
      }
    })
  }),
  changeBtn(){
    this.setData({
      btn_disable:false
    })
  }
})
  1. 小程序json代码,引入的自定义组件
{
  "usingComponents": {
    "l-card":"/miniprogram_npm/lin-ui/card",
    "l-button":"/miniprogram_npm/lin-ui/button",
    "l-countdown":"/miniprogram_npm/lin-ui/countdown"
  }
}

五、后台业务逻辑

要考虑订单超卖,这次代码使用的redis队列实现的

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Goods;
use Illuminate\Http\Request;
use App\Models\ActivityGoods;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use Lcobucci\JWT\Exception;

class GoodsController extends Controller
{
    //商品秒杀列表
    public function activityList()
    {
        $result = ActivityGoods::with(['goods'])
            ->get();
        return response()->json(['errorCode' => 0, 'data' => $result, 'msg' => '查询成功']);
    }

    //商品秒杀列表
    public function goodsDetail(Request $request)
    {
        $goods_id = $request->get('goods_id');
        $result = ActivityGoods::with(['goods'])
            ->where('goods_id',$goods_id)
            ->first();
        return response()->json(['errorCode' => 0, 'data' => $result, 'msg' => '查询成功']);
    }

    //同步库存
    public function syncStock()
    {
        //查出所有参与秒杀活动列表
        $result = ActivityGoods::with(['goods'])
            ->get()->toArray();
        //进行把参与秒杀的商品写入到数据库
        foreach ($result as $val){
            //生成对应商品库存队列
            $goods = "activity_goods_".$val['goods_id'];
            for ($i=0; $i < $val['sku_nums']; $i++) {
                Redis::lpush($goods, 1);
            }
        }
    }
    //校验库存
    public function checkStock(Request $request)
    {
        //获取token
        $token = explode(' ',$request->header('authorization'))[1];
        //进行查看
        $userInfo = Cache::get($token);
        //抢购用户id
        $userID = $userInfo->id;
        //商品id
        $goodsID = $request->input("goods_id");
        //对应商品库存队列
        $goods = "activity_goods_".$goodsID;
        //对应商品抢购成功用户集合 {1,3,4}
        $robSuccessUser = "success_user".$goodsID;
        //进行判断当前用户是否在抢成功的队列里面
        $result = Redis::sismember($robSuccessUser,$userID);
        //如果你在这里面,就抢完了
        if ($result) {
            //如果抢购成功 返回状态码,进行下单
            return response()->json(['errorCode' => 20000, 'data' => '', 'msg' => '已经抢购过了']);
        }
        //减库存,把队列里面的数据从左边 头
        $count = Redis::lpop($goods);
        if (!$count) {
            //如果抢购成功 返回状态码,进行下单
            return response()->json(['errorCode' => 20001, 'data' => '', 'msg' => '已经抢光了哦']);
        }
        //把当前这个秒杀的uid存储到中奖的队列里set
        $success = Redis::sadd($robSuccessUser, $userID);
        if(!$success){
            //已经在成功队列里了,加回库存,防止的是同个用户并发请求
            Redis::lpush($goods, 1);
            //如果抢购成功 返回状态码,进行下单
            return response()->json(['errorCode' => 20002, 'data' => '', 'msg' => '已经抢购过了']);
        }

        //如果抢购成功 返回状态码,进行下单
        return response()->json(['errorCode' => 0, 'data' => '', 'msg' => '秒杀成功']);
    }


    //创建订单
    public function createOrder(Request $request)
    {


        //获取token
        $token = explode(' ',$request->header('authorization'))[1];
        //进行查看
        $userInfo = Cache::get($token);
        //抢购用户id
        $userID = $userInfo->id;

        //商品id
        $goodsID = $request->input("goods_id");
        //对应商品抢购成功用户集合 {1,3,4}
        $robSuccessUser = "success_user".$goodsID;
        //进行判断当前用户是否在抢成功的队列里面
        $result = Redis::sismember($robSuccessUser,$userID);
        //如果你在这里面,就抢完了
        if (!$result) {
            //如果抢购成功 返回状态码,进行下单
            return response()->json(['errorCode' => 20003, 'data' => '', 'msg' => '手慢了!']);
        }

        DB::beginTransaction();
        try{
            //减库存

            //生成订单


            DB::commit();
            //下单成功,跳转支付页面
            return response()->json(['errorCode' => 0, 'data' => '', 'msg' => '下单成功!']);
        }catch (\Exception $e){
            DB::rollBack();
        }

    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于单片机设计了居家智能音箱系统(论文+源码)

1系统方案设计 通过需求分析本课题基于单片机的居家智能音箱系统的系统架构如图2.1所示。整个系统采用STM32F103作为控制器&#xff0c;结合LU-ASR01语音识别模块、ESP8266 wifi通信模块、OLED液晶、按键、音乐播放模块、LED灯等构成整个系统。用户可以通过按键、手机APP、语音…

Rook入门:打造云原生Ceph存储的全面学习路径(下)

文章目录 六.Rook部署云原生CephFS文件系统6.1 部署cephfs storageclass6.2 创建容器所需cephfs文件系统6.3创建容器pod使用rook-cephfs提供pvc6.4 查看pod是否使用rook-cephfs 七.Ceph Dashboard界面7.1 启用dashboard开关7.2 ceph-dashboard配置外部访问7.3 Dashboard web ad…

【大数据学习 | Spark-SQL】定义UDF和DUAF,UDTF函数

1. UDF函数&#xff08;用户自定义函数&#xff09; 一般指的是用户自己定义的单行函数。一进一出&#xff0c;函数接受的是一行中的一个或者多个字段值&#xff0c;返回一个值。比如MySQL中的&#xff0c;日期相关的dateDiff函数&#xff0c;字符串相关的substring函数。 先…

vue3 点击按钮,增加和减少input框

需求&#xff1a;手机号的input框默认一个&#xff0c;点击加号&#xff0c;可以增加和减少。 <template><el-form :model"editUserForm" label-width"80px" hide-required-asterisk ref"editUserFormRef"><!-- 手机 --><…

TongRDS分布式内存数据缓存中间件

命令 优势 支持高达10亿级的数据缓冲&#xff0c;内存优化管理&#xff0c;避免GC性能劣化。 高并发系统设计&#xff0c;可充分利用多CPU资源实现并行处理。 数据采用key-value多索引方式存储&#xff0c;字段类型和长度可配置。 支持多台服务并行运行&#xff0c;服务之间可互…

CSP/信奥赛C++语法基础刷题训练(33):洛谷P1055:[NOIP2008 普及组] ISBN 号码

CSP/信奥赛C语法基础刷题训练&#xff08;33&#xff09;&#xff1a;洛谷P1055&#xff1a;[NOIP2008 普及组] ISBN 号码 题目描述 每一本正式出版的图书都有一个 ISBN 号码与之对应&#xff0c;ISBN 码包括 9 9 9 位数字、 1 1 1 位识别码和 3 3 3 位分隔符&#xff0c;其…

算法盒子模型转换步骤+操作命令记录

0、模型转换步骤情 第一步、pt模型转onnx 1) 将要转换的pt模型文件上传到192.168.33.79的 /home/sophonsdk_edge_v1.7_official_release/下 2) 进入docker环境&#xff1a; docker exec -it myname /bin/bash 3) 在workspace目录运行: python3 /usr/local/lib/python3…

重复请求取消(不发请求)

重复请求取消&#xff08;不发请求&#xff09; axios 有自带的取消请求方式&#xff0c; 但是 在请求已发出时&#xff0c;取消只是状态取消&#xff0c; 其实请求已经发出&#xff0c;消耗了服务器资源&#xff08;方式1&#xff09;。本文探究的是 在调用请求A时&#xff0c…

谷歌浏览器Chrome打开百度很慢,其他网页正常的解决办法,试了很多,找到了适合的

最近不知怎么的&#xff0c;Chrome突然间打开百度很慢&#xff0c;甚至打不开。不光我一个人遇到这问题&#xff0c;我同事也遇到这个问题。开发中难免遇到问题&#xff0c;需要百度&#xff0c;现在是百度不了。 作为一名开发人员&#xff0c;习惯了使用Chrome进行开发&#…

【C++】深入探讨基础输入输出及类型转换问题

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目一&#xff1a;整数输入输出代码实现代码分析 &#x1f4af;题目二&#xff1a;ASCII 码转换为字符代码实现代码分析 &#x1f4af;cin 与 char 搭配行为的深入剖析问题…

GB28181系列三:SIP消息格式

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、SIP消息Header字段 二、SIP URI(URL) 三、SIP路由机制 1、路由机制介绍 2、严格路由&#xff08;Strict Routing&#xff09;与松散路由&#xff08;Louse Routing&#xff09; 3、总结 四、SIP消…

mvn-mac操作小记

1.安装brew 如果报错&#xff0c;Warning: /opt/homebrew/bin is not in your PATH. vim ~/.zshrc&#xff0c;最后一行追加 export PATH“/opt/homebrew/bin:$PATH” source ~/.zshrc 2.安装brew install maven mvn -version查看路径 Maven home: /opt/homebrew/Cellar/mav…

算法与数据结构练习——异或

知识点讲解&#xff1a; 一、异或操作定义&#xff1a; 异或是指相同为0&#xff0c;不同为1&#xff0c;也可理解为无进位相加&#xff01;&#xff01; 很重要&#xff01;&#xff01; 二、关于异或运算的几个性质&#xff1a; 1.0^NN &#xff08;0和任何数异或都…

STM32G4系列MCU的Direct memory access controller (DMA)功能介绍之二

目录 概述 1 DMA通道 1.1 可编程数据大小 1.2 指针增量 2 通道配置 2.1 配置步骤 2.2 通道状态和禁用通道 3 模式应用 3.1 循环模式&#xff08;内存到外设/外设到内存的传输&#xff09; 3.2 内存到内存模式 3.3 Peripheral-to-peripheral模式 3.4 编程转移方向&a…

【一文读懂】大语言模型

学习参考 项目教程&#xff1a;中文教程 代码仓库&#xff1a;代码地址 仓库代码目录说明&#xff1a; requirements.txt&#xff1a;官方环境下的安装依赖 notebook&#xff1a;Notebook 源代码文件 docs&#xff1a;Markdown 文档文件 figures&#xff1a;图片 data_base&…

注册表修改键盘位置

1.winr 输入 regedit 2.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout 3.右键Keyboard Layout->新建->二进制值->取名Scancode Map 4.右键Scancode Map&#xff0c;修改如下 //第一列 自动生成序号&#xff0c;不用管 第一行 输入8个00 第二…

服务器密码错误被锁定怎么解决?

当服务器密码错误多次导致账号被锁定时&#xff0c;解决方法需要根据服务器的操作系统&#xff08;如 Linux 或 Windows &#xff09;和具体服务器环境来处理。以下是常见的解决办法&#xff1a; 一、Linux 服务器被锁定的解决方法 1. 使用其他用户账号登录 如果有其他未被…

shell脚本编写练习2

1.准备阶段 在根目录下创建一个目录来存储shell脚本 mkdir /s3 2.题目 1. 使用case实现成绩优良差的判断 #!/bin/bash# 假设成绩存储在变量GRADE中 read -p "请输入成绩&#xff08;0-100&#xff09;&#xff1a;" GRADE# 使用case语句进行判断 case $GRADE in[…

清远榉之乡托养机构探讨:自闭症的本质辨析

当人们谈及自闭症时&#xff0c;常常会产生一个疑问&#xff1a;自闭症是精神类疾病吗&#xff1f;今天&#xff0c;清远榉之乡托养机构就来为大家解开这个疑惑。 榉之乡大龄自闭症托养机构在江苏、广东、江西等地都有分校&#xff0c;一直致力于为大龄自闭症患者提供专业的支持…

基于PoE交换机的智慧停车场监控组网应用

伴随城市发展快速&#xff0c;汽车保有量也不断增长&#xff0c;导致停车管理问题也愈发凸显。针对包括路侧停车位、地面停车场、地下停车场等场景的停车管理需求&#xff0c;通常会部署监控设备进行车位监测、现场安全监测等&#xff0c;助力构建智能化停车管理。因此如何为分…