Laravel 中操作 Redis

字数 485阅读 280

需求:

今天的开发需求是记录web和pc端的访问量。初步思路是在controller入口进行记录。使用redis中的Hash数据类型。key为日期,value为次数,正好Hash提供了累加(hincrby)操作,可以满足要求。目前的时间粒度是按照天数,后期扩展的时候可以将时间粒度进行细分。

""

编码:

在laravel中的那个地方进行次数的统计呢?有两个地方,一个是BaseController,还有一个中间件,所有的请求均经过这里。在统计的时候需要注意的是进行过滤一些请求,比如接口post请求,来自后台管理系统的请求等等。

//基类controller构造函数
 public function __construct(Request $request) 
    {
        $requestParam = request()->route()->getAction(); //获取访问的url
        $domain = [env('WECHAT_SUB_ROUTE'), env('FRONTEND_SUB_ROUTE')];//参与次数统计的rul
        if (in_array($requestParam['domain'], $domain) && $request->isMethod('get')) {
            $hashKey = 'webVisits';
            Redis::hincrby($hashKey, date('Y-m-d'), 1);//存入redis的hash
        }
    }

//getAction方法可以取到的值
array:8 [▼
  "domain" => "www.laravelylw.com"
  "middleware" => array:5 [▶]
  "as" => "xiong.test"
  "uses" => "App\Http\Controllers\Home\Main\XiongTestController@index"
  "controller" => "App\Http\Controllers\Home\Main\XiongTestController@index"
  "namespace" => "App\Http\Controllers\Home\Main"
  "prefix" => null
  "where" => []
]
redis中储存的值

根据需求可以看到会按照月和周进行比较。所以初步思路是获取某个时间段的startTime和endTime,然后通过Redis::hgetall($key)获取到哈希表中所有的key-value,以数组的方式返回。


redis通过hgetall获取的

然后遍历数组,将每个值和startTime-endTime比较,是否在该范围,若在就进行累加,即可得到这个时间段的访问量总和。

    //本周访问量
    $memberVisiyNum_week =$this->getVisit(Time::week());
    //date是一个数组包含startTIme和endTIme,获取本周,上周,本月,上个月等时间工具在后面附上。
    //还使用到Carbon工具类,用法见https://9iphp.com/web/laravel/php-datetime-package-carbon.html
    private function getVisit($date){
        $key = 'webVisits';//hash的key
        $lists = Redis::hgetall($key);//返回整个hash表元素
        $visit = 0;
        $Carbon = new Carbon();
        $startTime = $Carbon->create(date('Y',$date[0]),date('m',$date[0]),date('d',$date[0]),0,0,0);//用于后面使用Carbon种的日期比较方法
        $endTime = $Carbon->create(date('Y',$date[1]),date('m',$date[1]),date('d',$date[1]),0,0,0);
        foreach ($lists as $k => $v){
            $vTime = $Carbon->create(date('Y',strtotime($k)),date('m',strtotime($k)),date('d',strtotime($k)),0,0,0);//可以兼容细化时间粒度后。
            if($vTime->gte($startTime) && $vTime->lte($endTime)){
                $visit = $visit + Redis::hget($key,$k);
            }
        }
        return $visit;
    }

至此编码结束。

优化

可以优化的地方有以下几个。
1、时间粒度的优化,目前的业务是统计到天,没准哪天运营说我要看看每天那个时间段访问量最多。如果将时间粒度细化了,是否还能兼容现在的getVisit方法呢,是可以的。
2、通过Redis::hgetall($key)取值的时候,我们其实每次不需要都取出来,根据业务需求,最多60天的数据就ok了,如果每次都取出来,foreach的时候很浪费时间。

Time()工具类

class Time
{
    /**
     * 返回今日开始和结束的时间戳
     *
     * @return array
     */
    public static function today()
    {
        return [
            mktime(0, 0, 0, date('m'), date('d'), date('Y')),
            mktime(23, 59, 59, date('m'), date('d'), date('Y'))
        ];
    }

    /**
     * 返回昨日开始和结束的时间戳
     *
     * @return array
     */
    public static function yesterday()
    {
        $yesterday = date('d') - 1;
        return [
            mktime(0, 0, 0, date('m'), $yesterday, date('Y')),
            mktime(23, 59, 59, date('m'), $yesterday, date('Y'))
        ];
    }

    /**
     * 返回本周开始和结束的时间戳
     *
     * @return array
     */
    public static function week()
    {
        $timestamp = time();
        return [
            strtotime(date('Y-m-d', strtotime("this week Monday", $timestamp))),
            strtotime(date('Y-m-d', strtotime("this week Sunday", $timestamp))) + 24 * 3600 - 1
        ];
    }

    /**
     * 返回上周开始和结束的时间戳
     *
     * @return array
     */
    public static function lastWeek()
    {
        $timestamp = time();
        return [
            strtotime(date('Y-m-d', strtotime("last week Monday", $timestamp))),
            strtotime(date('Y-m-d', strtotime("last week Sunday", $timestamp))) + 24 * 3600 - 1
        ];
    }

    /**
     * 返回本月开始和结束的时间戳
     *
     * @return array
     */
    public static function month($everyDay = false)
    {
        return [
            mktime(0, 0, 0, date('m'), 1, date('Y')),
            mktime(23, 59, 59, date('m'), date('t'), date('Y'))
        ];
    }

    /**
     * 返回上个月开始和结束的时间戳
     *
     * @return array
     */
    public static function lastMonth()
    {
        $begin = mktime(0, 0, 0, date('m') - 1, 1, date('Y'));
        $end = mktime(23, 59, 59, date('m') - 1, date('t', $begin), date('Y'));

        return [$begin, $end];
    }

    /**
     * 返回今年开始和结束的时间戳
     *
     * @return array
     */
    public static function year()
    {
        return [
            mktime(0, 0, 0, 1, 1, date('Y')),
            mktime(23, 59, 59, 12, 31, date('Y'))
        ];
    }

    /**
     * 返回去年开始和结束的时间戳
     *
     * @return array
     */
    public static function lastYear()
    {
        $year = date('Y') - 1;
        return [
            mktime(0, 0, 0, 1, 1, $year),
            mktime(23, 59, 59, 12, 31, $year)
        ];
    }

    public static function dayOf()
    {

    }

    /**
     * 获取几天前零点到现在/昨日结束的时间戳
     *
     * @param int $day 天数
     * @param bool $now 返回现在或者昨天结束时间戳
     * @return array
     */
    public static function dayToNow($day = 1, $now = true)
    {
        $end = time();
        if (!$now) {
            list($foo, $end) = self::yesterday();
        }

        return [
            mktime(0, 0, 0, date('m'), date('d') - $day, date('Y')),
            $end
        ];
    }

    /**
     * 返回几天前的时间戳
     *
     * @param int $day
     * @return int
     */
    public static function daysAgo($day = 1)
    {
        $nowTime = time();
        return $nowTime - self::daysToSecond($day);
    }

    /**
     * 返回几天后的时间戳
     *
     * @param int $day
     * @return int
     */
    public static function daysAfter($day = 1)
    {
        $nowTime = time();
        return $nowTime + self::daysToSecond($day);
    }

    /**
     * 天数转换成秒数
     *
     * @param int $day
     * @return int
     */
    public static function daysToSecond($day = 1)
    {
        return $day * 86400;
    }

    /**
     * 周数转换成秒数
     *
     * @param int $week
     * @return int
     */
    public static function weekToSecond($week = 1)
    {
        return self::daysToSecond() * 7 * $week;
    }

    private static function startTimeToEndTime()
    {

    }
}

推荐阅读更多精彩内容