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

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

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

二、订单库存系统方案(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();
        }

    }
}

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

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

相关文章

三角网格体的光滑性问题

三角网格体的光滑性问题 在计算机图形学和计算机辅助设计中&#xff0c;C0连续性&#xff08;也称为位置连续性&#xff09;是指两个曲线或曲面在它们的公共边界上具有相同的位置。这意味着它们在边界处没有缝隙或重叠&#xff0c;但它们的切线方向可以不同。C0连续性是最低级…

独家|京东调整职级序列体系

原有的M、P、T、S主序列将正式合并为新的专业主序列P。 作者|文昌龙 编辑|杨舟 据「市象」独家获悉&#xff0c;京东已在近日在内部宣布对职级序列体系进行调整&#xff0c;将原有的M、P、T、S主序列正式合并为新的专业主序列P&#xff0c;合并后的职级体系将沿用原有专业序…

Echarts 绘制地图

一、Apache Echarts 官网地址&#xff1a;https://echarts.apache.org/ npm install echarts --save 二、获取地图的GeoJSON 地址&#xff1a;DataV.GeoAtlas地理小工具系列 左侧是地图&#xff0c;右侧是JSON数据路径&#xff0c;点击你想要生成的地图省市、地级&#xff0…

想入手养宠宠物空气净化器,养宠宠物空气净化器哪个好?

家里有了宠物后&#xff0c;确实多了很多欢乐&#xff0c;但掉落的毛发也多了不少&#xff0c;特别是换毛期&#xff0c;掉毛问题真的很让人头疼&#xff01;作为养了多年宠物的铲屎官&#xff0c;我真心推荐大家买一台宠物空气净化器&#xff0c;它能大大提升家里的空气质量&a…

ASUS/华硕ROG掌机 2023款 RC71 NR2301原厂win11系统 工厂文件 带ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;一键恢复&#xff0c;以及机器所有驱动软件。 系统版本&#xff1a;windows11 原厂系统下载网址&#xff1a;http://www.bioxt.cn 需准备一个20G以上u盘进行恢复 请注意&#xff1a;仅支持以上型号专用…

nginx 升级http 到 http2

同步发布于我的网站 &#x1f680; 背景介绍准备工作配置过程遇到的问题及解决方法验证升级总结参考资料 背景介绍 HTTP/2 是 HTTP 协议的最新版本&#xff0c;相比 HTTP/1.1&#xff0c;它带来了多项重要的改进&#xff0c;包括多路复用、头部压缩和服务端推送。这些特性可…

Spark 内存管理机制

Spark 内存管理 堆内内存和堆外内存 作为一个 JVM 进程&#xff0c;Executor 的内存管理建立在 JVM(最小为六十四分之一&#xff0c;最大为四分之一)的内存管理之上&#xff0c;此外spark还引入了堆外内存&#xff08;不在JVM中的内存&#xff09;&#xff0c;在spark中是指不…

透视投影(Perspective projection)与等距圆柱投影(Equirectangular projection)

一、透视投影 1.方法概述 Perspective projection&#xff08;透视投影&#xff09;是一种模拟人眼观察三维空间物体时的视觉效果的投影方法。它通过模拟观察者从一个特定视点观察三维场景的方式来创建二维图像。在透视投影中&#xff0c;远处的物体看起来比近处的物体小&…

uniapp开发微信小程序笔记8-uniapp使用vant框架

前言&#xff1a;其实用uni-app开发微信小程序的首选不应该是vant&#xff0c;因为vant没有专门给uni-app设置专栏&#xff0c;可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 但是vant的优…

Spring Web MVC其他扩展(详解下)

文章目录 Spring MVC其他扩展&#xff08;下&#xff09;异常处理异常处理机制声明式异常好处基于注解异常声明异常处理 拦截器拦截器概念拦截器使用拦截器作用位置图解拦截器案例拦截器工作原理源码 参数校验校验概述操作演示SpringMVC自定义参数验证ValueObject(VO) 文件上传…

【线上问题记录 | 排查网络连接问题】

问题描述 现在有我们程序是部署在服务器A的&#xff0c;A链接的是B。程序从B的redis进行存储和取数据的。 我们的业务是: 信息展示&#xff0c;也就是如果发现机器有异常了&#xff0c;实时进行监控。突然发现有一天&#xff0c;信息显示延迟了。 然后我们就开始排查究竟什么原…

如何保护LabVIEW程序免遭反编译

在正常情况下&#xff0c;LabVIEW程序&#xff08;即编译后的可执行文件或运行时文件&#xff0c;如 .exe 或 .llb&#xff09;无法直接被反编译出源码。然而&#xff0c;有一些需要特别注意的点&#xff1a; 1. LabVIEW的编译机制 LabVIEW编译器会将源码&#xff08;.vi文件&a…

求助:selenium.common.exceptions.SessionNotCreatedException: x x x

1.背景 想要使用python代码接管已打开的浏览器&#xff0c;减少重复登录或者selenium用例执行前的又臭又长的流程 2.报错截图 3.场景 目前是已开启浏览器调试模式且终端未关闭&#xff0c;执行上图中的代码后没有自动输入url且报错 4. 分析 我尝试了add_experimental_optio…

40分钟学 Go 语言高并发:【实战课程】工作池(Worker Pool)实现

工作池&#xff08;Worker Pool&#xff09;实战实现 一、知识要点概述 模块核心功能实现难点重要程度池化设计管理协程生命周期并发安全、资源控制⭐⭐⭐⭐⭐动态扩缩容根据负载调整池大小平滑扩缩、性能优化⭐⭐⭐⭐任务分发合理分配任务到worker负载均衡、任务优先级⭐⭐⭐…

Could not locate device support files.

报错信息&#xff1a;Failure Reason: The device may be running a version of iOS (13.6.1 17G80) that is not supported by this version of Xcode.[missing string: 869a8e318f07f3e2f42e11d435502286094f76de] 问题&#xff1a;xcode15升级到xcode16之后&#xff0c;13.…

Ubantu系统docker运行成功拉取失败【成功解决】

解决docker运行成功拉取失败 失败报错 skysky-Legion-Y7000-IRX9:~$ docker run hello-world docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head “http://%2Fvar%2Frun%2Fdocker.sock/_ping”: dial uni…

git rebase-优雅合并与修改提交

文章目录 简介rebase用于合并使用rebase修改提交cherry-pick 简介 在Git核心概念图例与最常用内容操作(reset、diff、restore、stash、reflog、cherry-pick)中我们已经介绍了git的最常用实用的命令。 在上面说的那篇文章中&#xff0c;我们只是简单提了一下rebase。 是因为r…

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

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

【大数据学习 | Spark调优篇】Spark之内存调优

1. 内存的花费 1&#xff09;每个Java对象&#xff0c;都有一个对象头&#xff0c;会占用16个字节&#xff0c;主要是包括了一些对象的元信息&#xff0c;比如指向它的类的指针。如果一个对象本身很小&#xff0c;比如就包括了一个int类型的field&#xff0c;那么它的对象头实…

pageoffice最新版本浏览器点击没反应解决办法

一、问题现象 最新版本的谷歌、火狐浏览器&#xff0c;调用pageoffice时&#xff0c;点击后没反应&#xff08;旧的谷歌浏览器不受影响&#xff09;。 二、产生原因 服务器返回pageOffice的客户端唤起链接格式为&#xff1a; PageOffice://|http://192.168.1.120:8080/xxx …