• 签到领金币模块


      最近做了一个签到模块的需求,主要就是签到,根据连签天数提供不同和奖励并在首页展示不同的文案。奖励分为金币和话费,话费也是通过金币的形式发放,但是有效期只有1天。

    签到需求

    1. 每日签到给奖励,七日一循环
    2. 若未签到,从第一天开始至后七天。若签到,从第一天签到返回至七日后。七天一循环
    3. 返回一个月内签到记录
    4. 若签到用户为新签到用户,则其连续签到第3天和第7天分别多领取有效期为一天的话费等额金币
    5. 新增首页签到入口文案展示,文案提示根据签到天数和是否是新人变化
    6. 给一个连续签到总天数,不是七日一循环。

    解决方案

    数据库设计:

    签到表

    字段设计包括自增id,用户userId,签到当天零点日期checkDate,奖励record,签到天数(一周)day,连签总天数alwaysDays

     

    获取最近七天签到记录

    通过sql

    select * from 签到表 where userId = #{userId} order by date desc limit 7

    优化:userId建立索引, 通过order by  … limit 7可以避免全表扫描 。

    查询出结果后存入缓存,缓存时间只要大于24小时即可,但考虑大多数人连签不会坚持两天,所以可以将缓存失效时间设置72到96小时。时间太短则用户下次签到时需多次读取数据库增加数据库负载(我的签到逻辑是签到时先通过缓存查出最近一天签到记录,签到后清除缓存,展示时再访问数据库并存入缓存)。时间太长又会浪费redis空间。

     

    签到逻辑

    1. 获取最近七天签到记录和签到总天数

    2. 如果最近一天签到时间等于当天,则直接返回;如果签到时间等于昨天,则将签到天数day和连签总天数alwaysDays增加1,若day大于7则重新置为1.存入数据库同时移除缓存并异步进行奖励金币入库。

     

    如何判断是否是新签到用户(七天内)

    将limit 7 查询的结果与7比较,

    若小于7则证明签到总天数小于7,将值与昨日签到记录中的day比较,若相同则确定其为新签到用户(若不同,肯定不是连续签到,则为老用户。day永远小于等于7),在进行奖励金币入库时额外增加新签到用户奖励。

    若等于7,则判断alwaysDay的值,老用户重新签到时,会将最近签到记录条数维护到alwaysDay中。alwaysDay的值与day不相同,则其为新用户第七天签到。(防止老用户隔断时间后连续签到七天领取第七天签到奖励)。

     

    获取一个月内签到记录

    根据传入的日期参数date(转化为时间戳10位Integer类型)通过Calendar

    类求出当月的所有日期(日期为当天零点)。

    通过日期开始和结束时间范围求出当月所有签到记录并通过stream流转为以签到当天零点日期为key的map。循环当月日期并与map进行比较,若不为空则表示当天有签到,返回true;否则返回false。因该接口入口签到后才展示且一般用户很少点开,所以暂未加缓存。

     

    展示一周签到记录

    通过缓存查询出最近七天签到记录,判断最近一天签到是否是昨天或今天当天,若不是则发生断签,一周全部返回false。若未断签则根据1-7循环与day比较,day之前为true,day之后为false。

     

    新签到用户额外领取金币过期

    因新签到用户额外领取的金币只有一天的使用时间,所以需要有一个过期判定。

    该需求可以通过mp消息进行过期扣减。在新用户额外奖励入库时发送一条延时24小时的消息,消息主体为userId+奖励金额。

    消息消费时可根据userId和出账Type及时间范围查询出用户金币使用期内的出账总额。若出账小于奖励金额则进行扣减操作。

    同时为防止消息丢失,可以每晚执行一个定时任务,扫描出当天获取额外奖励的新签到用户及其出账记录,通过stream流进行比对,将异常用户id返回(或直接在定时任务内进行处理)(因where条件均有索引且可以将定时任务设置在晚上3、4点等用户不活跃的时间,所以对数据库负载较小)。

    因为产品要求签到日期取整点,可以通过 Calendar类获取当前整点时间进行运算后发送消息

    public static Long getNowHour() {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DATE, 0);
            calendar.set(Calendar.HOUR_OF_DAY, calendar.get(HOUR_OF_DAT));
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            return calendar.getTimeInMillis()/1000;
        }

    首页根据签到天数展示不同文案

    通过是否是新签到用户和是否签到展示不同文案。

    若是新签到用户且未签到,可根据昨日 签到天数day对应1-6展示不同的提示文案(若昨日也未签到则不可能是新签到用户)

    如果有错误或者更优化的解决方案,欢迎大家在评论区留言探讨。

    也可以给我的个人公众号私信留言。

  • 相关阅读:
    docker学习笔记及hadoop集群搭建
    Zookeeper+Kafka+Storm+HDFS实践
    zookeeper集群搭建
    scala学习笔记——特质
    scala学习笔记-集合
    scala学习笔记-隐式转换和隐式参数
    RDD 重新分区,排序 repartitionAndSortWithinPartitions
    scala学习笔记——操作符
    JAVA基础系列(一) 概述与相关概念
    网络收藏夹
  • 原文地址:https://www.cnblogs.com/shangyang/p/13285536.html
Copyright © 2020-2023  润新知