当前位置: 首页 > news >正文

签到功能---实现签到接口

文章目录

    • 概要
    • 整体架构流程
    • 技术细节
    • 小结

概要

需求分析以及接口设计

由KEY的结构可知,要签到,就必须知道是哪一天签到,也就是两个信息:

  • 当前用户

  • 当前时间

这两个信息我们都可以自己获取,因此签到时,前端无需传递任何参数。

那么签到以后是否需要返回数据呢?

需求中说连续签到会有积分奖励,那么为了提升用户体验,在用户签到成功以后是不是应该返回连续签到天数和获取的积分奖励呢。

综上,最终签到的接口信息如下:

另外,为了便于统计,我们计划每个月为每个用户生成一个独立的KEY,因此KEY中必须包含用户信息、月份信息,长这样:

 

sign:uid:xxx:202401

 

技术细节

package com.tianji.learning.domain.vo;import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "签到结果")
public class SignResultVO {@ApiModelProperty("连续签到天数")private Integer signDays;@ApiModelProperty("签到得分")private Integer signPoints = 1;@ApiModelProperty("连续签到奖励积分,连续签到超过7天以上才有奖励")private Integer rewardPoints;@JsonIgnorepublic int totalPoints(){return signPoints + rewardPoints;}
}

1.Controller层

package com.tianji.learning.controller;import com.tianji.learning.domain.vo.SignResultVO;
import com.tianji.learning.service.ISignRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@Api(tags = "签到相关接口")
@RestController
@RequestMapping("sign-records")
@RequiredArgsConstructor
public class SignRecordController {private final ISignRecordService recordService;@PostMapping@ApiOperation("签到功能接口")public SignResultVO addSignRecords(){return recordService.addSignRecords();}
}

2.Service层:

package com.tianji.learning.service.impl;import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BooleanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.vo.SignResultVO;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.ISignRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;import java.time.LocalDate;
import java.util.List;@Service
@RequiredArgsConstructor
public class SignRecordServiceImpl implements ISignRecordService {private final StringRedisTemplate redisTemplate;@Overridepublic SignResultVO addSignRecords() {// 1.签到// 1.1.获取登录用户Long userId = UserContext.getUser();// 1.2.获取日期LocalDate now = LocalDate.now();// 1.3.拼接keyString key = RedisConstants.SIGN_RECORD_KEY_PREFIX+ userId+ now.format(DateUtils.SIGN_DATE_SUFFIX_FORMATTER);// 1.4.计算offsetint offset = now.getDayOfMonth() - 1;// 1.5.保存签到信息Boolean exists = redisTemplate.opsForValue().setBit(key, offset, true);if (BooleanUtils.isTrue(exists)) {throw new BizIllegalException("不允许重复签到!");}// 2.计算连续签到天数int signDays = countSignDays(key, now.getDayOfMonth());// 3.计算签到得分int rewardPoints = 0;switch (signDays) {case 7:rewardPoints = 10;break;case 14:rewardPoints = 20;break;case 28:rewardPoints = 40;break;}// TODO 4.保存积分明细记录 // 5.封装返回SignResultVO vo = new SignResultVO();vo.setSignDays(signDays);vo.setRewardPoints(rewardPoints);return vo;}private int countSignDays(String key, int len) {// 1.获取本月从第一天开始,到今天为止的所有签到记录List<Long> result = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(len)).valueAt(0));if (CollUtils.isEmpty(result)) {return 0;}int num = result.get(0).intValue();// 2.定义一个计数器int count = 0;// 3.循环,与1做与运算,得到最后一个bit,判断是否为0,为0则终止,为1则继续while ((num & 1) == 1) {// 4.计数器+1count++;// 5.把数字右移一位,最后一位被舍弃,倒数第二位成了最后一位num >>>= 1;}return count;}
}

相关文章:

  • Unity基于屏幕空间的鼠标拖动,拖动物体旋转
  • 强化学习算法系列(五):最主流的算法框架——Actor-Critic算法框架
  • 论文阅读VACE: All-in-One Video Creation and Editing
  • 用Python Pandas高效操作数据库:从查询到写入的完整指南
  • 音视频相关协议和技术内容
  • 智能体开发的范式革命:Cangjie Magic全景解读与实践思考
  • 游戏盾和高防ip有什么区别
  • CSS进度条带斑马纹动画(有效果图)
  • 云转型(cloud transformation)——不仅仅是简单的基础设施迁移
  • Java字符串处理
  • IntelliJ IDEA 2025.1 发布 ,默认 K2 模式 | Android Studio 也将跟进
  • XC7K410T‑2FFG900I 赛灵思XilinxFPGA Kintex‑7
  • BUUCTF-Web(21-40)
  • 计算机视觉——JPEG AI 标准发布了图像压缩新突破与数字图像取证的挑战及应对策略
  • HTTP 3.0 协议的特点
  • Oracle 19c部署之初始化实例(三)
  • AI编写的“黑科技风格、自动刷新”的看板页面
  • Echarts柱状图斜线环纹(图形的贴花图案)
  • 30Metrics Server的使用
  • 在VirtualBox上安装Ubuntu
  • 三大猪企4月生猪销量同比均增长,销售均价同比小幅下降
  • 中铁房地产24.7亿元竞得上海松江新城宅地,溢价率20.42%
  • 视频丨习近平同普京在主观礼台出席红场阅兵式
  • 红场阅兵即将开始!中国人民解放军仪仗队亮相
  • 援藏博士张兴堂已任西藏农牧学院党委书记、副校长
  • 美众议院通过法案将“墨西哥湾”更名为“美国湾”