Laravel 开发简易的附近动态功能

Laravel 140℃ 0评论

码农宅

使用laravel开发简易的附近动态功能

简介

公司app准备做个附近的功能,方便用户交(y)流(p),然后呢,大概目标就是点击附近,出来一列的用户动态列表,按时间地点距离排列。

思路

在网上找了一些资料,发现有三种实现方法,mysql,redis,MongoDB;mysql因为用公式来跑select,用户一多就难受了,所以采用redis来存用户的地理位置,再用redis的新命令实现计算筛选用户。

开始

redis命令解释中文命令:

GEOADD---(将指定的地理空间位置(纬度、经度、名称)添加到指定的key中),我们用这个命令将用户发表动态时的位置信息记录进redis:key longitude latitude member [longitude latitude member ...]
  • key:区域名或者空间名,我们统一用‘moment’
  • longitude:经度
  • latitude:纬度
  • member:即为redis的key值,我们用moments表的id来代表
GEORADIUS---(以给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素),key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
  • key::区域名或者空间名,我们统一用‘moment’
  • longitude:经度
  • latitude:纬度
  • radius:距离,比如附近1km内
  • km:默认用千米
  • option:多个返回参数用到的有:(WITHDIST->返回这个点和当前用户的位置的距离,ASC->从近到远排列)
  • 更多信息参考

设计

一个是mysql的表,一个是redis存放地点;利用moments表的主键id来做redis的唯一key
准备两个api:

post-moment:接收app端传来的用户当前定位的经纬度参数并生成一条动态  
get-moments:根据当前用户的经纬度位置获取附近动态列表

开发

  • 添加两条路由
    //往web.php 添加两个路由
    Route::get('/post-moment', 'NearByController@postMoment');
    Route::get('/get-moments', 'NearByController@getMoments');
  • 创建model文件
php artisan make:model Moment
  • 添加redisLbs文件
    随便放到help还是什么目录就好,namespace可以找到就行
<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/3/29
 * Time: 14:26
 */

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 = 'km')
    {
        $redis = $this->getRedis();
        $options = ['WITHDIST','ASC','WITHCOORD']; //显示距离
        $list = $redis->geoRadius('moments', $longitude, $latitude , $maxDistance, $unit, $options);
        return $list;
    }

}
  • 创建控制器
php artisan make:controller NearByController
  • 逻辑代码
<?php

namespace App\Http\Controllers;

use App\Help\redisLbs;
use App\Moment;
use Illuminate\Http\Request;

class NearByController extends Controller
{

    /*
     * 添加新动态:1.mysql插入 2.redis插入
     */
    public function postMoment(Request $request,Moment $moment)
    {
        $user = $this->authenticate($request);//根据根据实际登录用户
        if (!$request->input('longitude')){
            return $this->failure(0,'缺少经度');
        }
        if (!$request->input('latitude')){
            return $this->failure(0,'缺少纬度');
        }

        //依赖注入,随时用
        $moment->user_id = $user->id; //根据实际登录用户
        $moment->longitude = $request->input('longitude');
        $moment->latitude = $request->input('latitude');
        $moment->created_at = time();
        $moment->updated_at = time();

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

    /*
     * 获取附近动态
     */
    public function getMomentsList(Request $request)
    {
        $lbs = new redisLbs();
        $result = $lbs->geoNearFind($request->input('longitude'),$request->input('latitude'),30000); //获取附近距离3w米的
        /* 返回的两个坐标点,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'] = $result[$i][1];
        }
        $moments = Moment::where([
            ['created_at','>',date('Y-m-d H:m:i',time()-1800)],
        ])->whereIn('id', $mid)->orderBy('created_at', 'desc')->get()->toArray();

        //根据距离排序动态列表
        $date = array_column($moments, 'distance');
        array_multisort($date,SORT_ASC,$moments);

        return $this->success(1,'成功获取附近动态',$moments);
    }
}

具体的代码还需具体实现,比如用户,认证等等,这里只有相关演示代码。大体思路就是酱紫,有更好的思路

转载请注明:码农宅 » Laravel 开发简易的附近动态功能

喜欢 (0)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. redis 做距离计算 很好
    luo2018-04-15 22:21 回复
  2. 不错
    随遇而安2018-04-15 22:20 回复