laravel+redis 附近的车辆 + 发布订单 + 司机抢单

路由

Route::get('post-moment-import', [\App\Http\Controllers\IndexController::class, 'postMomentImport']);
Route::get('post-moment', [\App\Http\Controllers\IndexController::class, 'postMoment']);
Route::get('edit-moment/{moment}', [\App\Http\Controllers\IndexController::class, 'editMoment']);
Route::get('get-moments', [\App\Http\Controllers\IndexController::class, 'getMoments']);
// 发布抢单
Route::get('issue-order', [\App\Http\Controllers\IndexController::class, 'IssueOrder']);
// 抢单
Route::get('grab-single', [\App\Http\Controllers\IndexController::class, 'GrabSingle']);

Collection

<?php

namespace App\Http\Controllers;

use App\Helps\api\redisLbs;
use App\Models\Moment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\Facades\Image;

class IndexController extends Controller
{
    public function postMoment (Request $request, Moment $moment)
    {
        if (!$request->longitude){
            return response()->json(['status' => 0, 'msg' => '缺少经度']);
        }
        if (!$request->latitude){
            return response()->json(['status' => 0, 'msg' => '缺少纬度']);
        }

        //依赖注入,随时用
        $moment->name = $request->name;
        $moment->longitude = $request->input('longitude');
        $moment->latitude = $request->input('latitude');

        if ($moment->save()){
            //连接redis加点
            $lbs = new redisLbs();
            $result = $lbs->geoAdd($moment->id, $request->input('longitude'), $request->input('latitude'));
            if ($result){
                return response()->json(['status' => 1, 'msg' => '添加动态成功']);
            }
            return response()->json(['status' => 0, 'msg' => '动态添加成功,redis同步失败']);
        }
        return response()->json(['status' => 0, 'msg' => '动态添加失败']);
    }

    public function postMomentImport ()
    {
        $json = '[{"name":"xxx","poi":"118.96,42.2737"}]';
        $json_arr = json_decode($json, JSON_UNESCAPED_UNICODE);

        foreach (collect($json_arr)->chunk(300) ?? [] as $chunk)
        {
            foreach ($chunk ?? [] as $arr)
            {
                list($longitude, $latitude) = explode(',', $arr['poi']);
                $moment = Moment::create([
                    'name' => $arr['name'],
                    'longitude' => $longitude,
                    'latitude' => $latitude,
                ]);

//            $lbs = new redisLbs();
//            $result = $lbs->geoAdd($moment->id, $longitude, $latitude);
            }
        }

        return response()->json(['status' => 1, 'msg' => '更新动态成功']);
    }

    public function editMoment (Request $request, Moment $moment)
    {
        if (!$request->longitude){
            return response()->json(['status' => 0, 'msg' => '缺少经度']);
        }
        if (!$request->latitude){
            return response()->json(['status' => 0, 'msg' => '缺少纬度']);
        }

        //依赖注入,随时用
        $moment->name = $request->name;
        $moment->longitude = $request->input('longitude');
        $moment->latitude = $request->input('latitude');

        if ($moment->save()){
            //连接redis加点
            $lbs = new redisLbs();
            $result = $lbs->geoAdd($moment->id, $request->input('longitude'), $request->input('latitude'));
            if ($result){
                return response()->json(['status' => 1, 'msg' => '更新动态成功']);
            }
            return response()->json(['status' => 0, 'msg' => '动态更新成功,redis同步失败']);
        }
        return response()->json(['status' => 0, 'msg' => '动态更新失败']);
    }

    public function getMoments (Request $request)
    {
        $lbs = new redisLbs();
        $result = $lbs->geoNearFind($request->longitude,$request->latitude,1000); //获取附近距离3千米的
        /* 返回的两个坐标点,mid为76和12,距离,还有经纬度
        [
            "76",
            "1112.2630",
            [
                "100.19999831914902",
                "39.999999910849162"
            ]
        ],
        [
            "12",
            "2213.4033",
            [
                "100.19999831914902",
                "10.100000747410967"
            ]
        ],
          */
        $mid = $dist=[];
        for($i=0;$i<count($result);$i++){
            $dist[$i]['mid'] = $mid[$i] = $result[$i][0];  //点的id,也就是moment的主键
            $dist[$i]['distance'] = round($result[$i][1], 2);
        }
//        $moments = Moment::where([
//            ['created_at','>',date('Y-m-d H:m:i',time()-1800)],
//        ])->whereIn('id', $mid)->orderBy('created_at', 'desc')->get()->toArray();
        $moments = Moment::whereIn('id', $mid)->orderBy('created_at', 'desc')->select('id', 'name')->get()->toArray();

        // 合并数组
        foreach ($dist ?? [] as $item)
        {
            foreach ($moments ?? [] as $k => $moment)
            {
                if ($item['mid'] == $moment['id'])
                {
                     $moments[$k]['distance'] = $item['distance'];
                }
            }
        }

        // 根据distance进行排序
        $datas = collect($moments)->sortBy('distance')->values()->all();

        return response()->json(['status' => 1, 'msg' => '成功获取附近动态', 'data' => $datas]);
    }

    public function IssueOrder ()
    {
        $orderNum = 2000; // 发布了20个签单订单
        for ($i=1; $i <= $orderNum; $i++) {
            $grab_orders = "grab_orders".$i;
            Redis::lpush($grab_orders, 1);
        }
        return response()->json(['status' => 200, 'msg' => '发布成功!']);
    }

    public function GrabSingle (Request $request)
    {
        // 用户id
        $userId = rand(1, 9999);
        // 抢单订单的id
        $orderId = rand(1, 2000);
        //对应商品库存队列
        $goods = "grab_orders".$orderId;
        //对应商品抢购成功用户集合 {1,3,4}
        $robSuccessUser = "success_user".$orderId;
        //进行判断当前用户是否在抢成功的队列里面
        $result = Redis::sismember($robSuccessUser,$userId);

        //如果你在这里面,就抢完了
        if ($result) {
            //如果抢购成功 返回状态码,进行下单
            Log::info("用户:{$userId},已经抢过了,订单:{$goods}");
            return response()->json(['status' => 20000, 'data' => '', 'msg' => '您已经抢购过了']);
        }
        //减库存,把队列里面的数据从左边 头
        $count = Redis::lpop($goods);

        if (!$count) {
            //如果抢购成功 返回状态码,进行下单
            Log::info("用户:{$userId},已经抢光了哦,订单:{$goods},手慢了");
            return response()->json(['status' => 20001, 'data' => '', 'msg' => '已经抢光了哦']);
        }
        //把当前这个秒杀的uid存储到中奖的队列里set
        $success = Redis::sadd($robSuccessUser, $userId);
        if(!$success){
            //已经在成功队列里了,加回库存,防止的是同个用户并发请求
            Redis::lpush($goods, 1);
            //如果抢购成功 返回状态码,进行下单
            Log::info("用户:{$userId},已经抢购过了,订单:{$goods},无需在枪");
            return response()->json(['status' => 20002, 'data' => '', 'msg' => '已经抢购过了']);
        }

        //如果抢购成功 返回状态码,进行下单
        Log::info("用户:{$userId},抢单成功,订单:{$goods}");
        return response()->json(['status' => 200, 'data' => '', 'msg' => '抢单成功']);
    }
}

RedisLbs

<?php


namespace App\Helps\api;


class redisLbs
{
    /** @var Redis */
    private $redis;
    public function __construct($config = array())
    {
        $host = isset($config['host']) ? $config['host'] : '127.0.0.1';
        $port = isset($config['port']) ? $config['port'] : '6379';
        $redis = new \Redis();
        $redis->connect($host, $port);
        if (env('APP_ENV') != 'local'){
            $redis->auth('myRedis');
            $redis ->set( "root" , "myRedis");
        }
        $this->setRedis($redis);
    }
    public function getRedis()
    {
        return $this->redis;
    }
    public function setRedis($redis)
    {
        $this->redis = $redis;
    }

    //添加点
    public function geoAdd($uin, $lon, $lat)
    {
        $redis = $this->getRedis();
        $redis->geoAdd('moments', $lon, $lat, $uin);
        return true;
    }

    //获取点
    public function geoNearFind($longitude , $latitude , $maxDistance = 0, $unit = 'm')
    {
        $redis = $this->getRedis();
        $options = ['WITHDIST','ASC','WITHCOORD']; //显示距离
        $list = $redis->geoRadius('moments', $longitude, $latitude , $maxDistance, $unit, $options);
        return $list;
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 6

建议所有的错误提示用异常处理,只保留正常的 return 返回

1年前 评论
会尿尿的大鲨鱼 (楼主) 1年前

redis对象从容器内获取会更好点吧

1年前 评论
会尿尿的大鲨鱼 (楼主) 1年前
pndx

这代码看的好难受

1年前 评论

很棒 学习了

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!