Laravel-使用Redis-Bitmap签到

4 篇文章 0 订阅
4 篇文章 0 订阅

注:需求不一样则业务逻辑不一样

不说废话,直接干!!!!

Mysql:

CREATE TABLE `t_user_sign` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `days` int(11) NOT NULL COMMENT '累计签到天数',
  `year` int(11) NOT NULL COMMENT '年',
  `month` tinyint(4) NOT NULL COMMENT '月',
  `sign_record` varchar(255) NOT NULL COMMENT '签到记录',
  `last_sign_time` char(19) NOT NULL COMMENT '上次签到时间',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '0-无效,1-有效',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;


1、控制器代码

    /**
     *  页面初始化,返回结果给前端
     */
    public function index()
    {
        $user_id = Request::input('user_id');
        $year = date('Y');
        $month = date('n');
        $signKey = 'sign_' . $year . '_' . $month . '_' . $user_id;
        $data = UserSignService::signDays($user_id,$signKey);
        $data['year'] = $year;
        $data['month'] = $month;
        return Utils::success($data);
    }


    /**
     *  签到/补签  这里使用了两种Redis数据类型,bitmap、hash
     */
    public function sign()
    {
        $user_id = Request::input('user_id');
        $type = Request::input('type',1); // 1、签到 , 2、补签
        $day = Request::input('day',0);
        if (!Utils::isValue($user_id)){
            return Utils::fail('无效user_id');
        }
        if ($type == 2){
            if (!Utils::isValue($day)){
                return Utils::fail('无效day');
            }
        }else{
            $day = Utils::getNowDay();
        }
        if ($day > Utils::getNowDay()){
            return Utils::fail('补签的日期不能大于等于今天');
        }

        $year = date('Y');
        $month = date('n');
        $signKey = 'sign_' . $year . '_' . $month . '_' . $user_id;

        $sign = Redis::getbit($signKey,$day);
        if ($type == 2){
            if (Utils::isValue($sign)){
                return Utils::success('您已补签,无需补签');
            }
        }else{
            if (Utils::isValue($sign)){
                return Utils::success('您今天已签到');
            }
        }

        Redis::setbit($signKey,0,1);
        Redis::setbit($signKey,$day,1);

        $data = UserSignService::signDays($user_id,$signKey);
        $datas = [
            'user_id' => $user_id,
            'days' => Utils::getValue($data,'days'),
            'year' => $year,
            'month' => $month,
            'sign_record' => Utils::getValue($data,'signDay'),
            'last_sign_time' => date('Y-m-d H:i:s')
        ];

        //  将用户的记录存放hash,到下个月初跑一次记录放进DB。注:需求不一样则业务逻辑不一样
        Redis::hset('sign_record',$user_id,json_encode($datas));
        //  缓存过期时间
        Redis::expire($signKey,3024000);
        Redis::expire('sign_record',3024000);

        if ($type == 2){
            return Utils::success('补签成功');
        }else{
            return Utils::success('签到成功');
        }

    }

2、Service 代码

class UserSignService
{
    /**
     *  获取用户哪一天签到的? 和  签到总天数
     * @param $user_id  '用户ID'
     * @param $signKey  'key'
     * @return array
     */
    public static function signDays($user_id,$signKey): array
    {
        $bitmap_bin_str = self::strToBin(Redis::get($signKey));
        //调试使用,输出本月每天签到情况
        $month = date('t');
        $signDay = 0;
        for($i=1;$i<=$month;$i++) {
            if (empty($bitmap_bin_str[$i])) {
                $bitmap_bin_str[$i] = 0;
            }
            if ($bitmap_bin_str[$i] != 1) {
//                echo "$i 日未签到";
//                echo "<br>";
            } else {
                $signDay += 1;
//                echo "$i 日签到";
//                echo "<br>";
            }
        }

        return [
            'signDay' => substr($bitmap_bin_str,1),
            'days' => $signDay
        ];
    }


    /**
     *  转化数据
     * @param $str
     * @return string
     */
    public static function strToBin($str)
    {
        $arr = preg_split('/(?<!^)(?!$)/u', $str);
        foreach($arr as &$v){
            $temp = unpack('H*', $v);
            $v = base_convert($temp[1], 16, 2);
            unset($temp);
        }
        return join(' ',$arr);
    }
}

3、脚本command

public function handle()
    {
        $datas = Redis::hgetall('sign_record');
        foreach ($datas as $data){
            $data = json_decode($data);
            $user_id = Utils::getValue($data,'user_id');
            $where = [
                'user_id' => $user_id,
                'year' => date('Y'),
                'month' => date('n'),
            ];
            $userSignModel = UserSign::where($where)->first();
            if (Utils::isValue($userSignModel)){
                $userSignModel->toArray();
            }
            $userSignRecord = [
                'days' => Utils::getValue($data,'days'),
                'sign_record' => Utils::getValue($data,'sign_record'),
                'last_sign_time' => Utils::getValue($data,'last_sign_time')
            ];
            if (Utils::isValue($userSignModel)){
                DB::table('user_sign')->where($where)->update($userSignRecord);
            }else{
                $userSignRecord['user_id'] = Utils::getValue($data,'user_id');
                $userSignRecord['year'] = Utils::getValue($data,'year');
                $userSignRecord['month'] = Utils::getValue($data,'month');
                DB::table('user_sign')->insert($userSignRecord);
            }
        }

        echo '执行成功';

    }

如有Command脚本不会的,自己私下百度。

列出执行命令:php artisan list

在这里插入图片描述

发现存在,即可执行,php artisan lesson:sign

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值