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

news2025/5/20 18:36:27

文章目录

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

概要

需求分析以及接口设计

由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;

    @JsonIgnore
    public 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;

    @Override
    public SignResultVO addSignRecords() {
        // 1.签到
        // 1.1.获取登录用户
        Long userId = UserContext.getUser();
        // 1.2.获取日期
        LocalDate now = LocalDate.now();
        // 1.3.拼接key
        String key = RedisConstants.SIGN_RECORD_KEY_PREFIX
                + userId
                + now.format(DateUtils.SIGN_DATE_SUFFIX_FORMATTER);
        // 1.4.计算offset
        int 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.计数器+1
            count++;
            // 5.把数字右移一位,最后一位被舍弃,倒数第二位成了最后一位
            num >>>= 1;
        }
        return count;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2337209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LWIP_MQTT连接ONENET

前言&#xff1a; 使用正点原子STM32F407, LWIP,MQTT demo,验证LwIP的MQTT连接ONENET物联网平台,测试整个链路是否畅通&#xff0c;后面再详细分析LWIP移植和MQTT协议的使用。 26 基于 MQTT 协议连接 OneNET 服务器 本章主要介绍 lwIP 如何通过 MQTT 协议将设备连接到 OneNET…

代码随想录刷题|Day20(组合总数,组合总数2、分割回文串)

回溯算法 Part02 组合总数 力扣题目链接 代码随想录链接 视频讲解 题目描述&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你…

ArcGIS Desktop使用入门(四)——9版本与10版本区别

系列文章目录 ArcGIS Desktop使用入门&#xff08;一&#xff09;软件初认识 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——标准工具 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——编辑器 ArcGIS Desktop使用入门&#xff08;二&#x…

R语言之环境清理

有时候 R 环境中残留的变量可能会导致警告&#xff0c;可以尝试清理工作空间并重新加载数据。 警告信息: In mget(objectNames, envir ns, inherits TRUE) : 重新评估被中断的许诺 # 观察前6行 head(iris)# 观察数据结构 str(iris)# 探知数据的极值和分位数&#xff0c;以及…

javaSE————网络编程套接字

网络编程套接字~~~~~ 好久没更新啦&#xff0c;蓝桥杯爆掉了&#xff0c;从今天开始爆更嗷&#xff1b; 1&#xff0c;网络编程基础 为啥要有网络编程呢&#xff0c;我们进行网络通信就是为了获取丰富的网络资源&#xff0c;说实话真的很神奇&#xff0c;想想我们躺在床上&a…

FreeRTOS二值信号量详解与实战教程

FreeRTOS二值信号量详解与实战教程 &#x1f4da; 作者推荐&#xff1a;想系统学习FreeRTOS嵌入式开发&#xff1f;请访问我的FreeRTOS开源学习库&#xff0c;内含从入门到精通的完整教程和实例代码&#xff01; 1. 二值信号量核心概念解析 二值信号量(Binary Semaphore)是Fre…

赛灵思 XCVU440-2FLGA2892E XilinxFPGA Virtex UltraScale

XCVU440-2FLGA2892E 属于 Xilinx Virtex UltraScale 系列&#xff0c;是面向高端应用的旗舰 FPGA 器件。该系列产品以出色的高并行处理能力、丰富的逻辑资源和高速互联能力闻名&#xff0c;广泛用于 高性能计算、数字信号处理等对计算能力和带宽要求极高的场景。采用先进的 20n…

Spring Cloud Alibaba微服务-微服务介绍和搭建

1. 课程介绍 单体服务中有订单&#xff0c;用户&#xff0c;库存&#xff0c; 两个缺陷&#xff1a; a. 是以应用的维度进行负载均衡&#xff0c;资源占用大 b. 当其中一个模块宕机&#xff0c;整个应用就不能用了&#xff1b; nacos&#xff1b;ribbon&#xff0c;loadBa…

KALI安装JAVA8和切换JDK版本

一、安装JDK1.8 1、直接使用下面的地址下载java 1.8&#xff1a; https://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz 2、建立目录&#xff0c;将下载的jdk的安装包复制过去并进行解压 sudo mkdir -p /usr/local/java cp jdk-8u202-linux-x64.t…

今日行情明日机会——20250417

指数目前在区间内缩量震荡 2025年4月17日涨停主要行业方向分析 一、核心主线方向 化工&#xff08;产能优化涨价预期&#xff09; • 涨停家数&#xff1a;11家&#xff08;最强方向&#xff09;。 • 代表标的&#xff1a; ◦ 红宝丽&#xff08;2连板&#xff09;&#xff…

一篇讲完自动化测试基础-Python【万字详细讲解】12

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

极限编程(XP)简介及其价值观与最佳实践

目录 一、什么是极限编程&#xff08;XP&#xff09;二、极限编程的核心价值观1. 沟通2. 简单3. 反馈4. 勇气 三、极限编程的12个最佳实践1. 结对编程2. 40小时工作制3. 简单设计4. 代码规范5. 测试驱动开发&#xff08;TDD&#xff09;6. 系统隐喻7. 持续集成8. 重构9. 客户在…

四层板的蛇形走线技巧:原理、策略与应用

在四层板的设计过程中&#xff0c;蛇形走线是一种常见且重要的布线方式。它能够满足特定的设计需求&#xff0c;如调整信号线长度、实现等长布线等&#xff0c;但如果使用不当&#xff0c;也可能会带来一些负面影响&#xff0c;如增加信号衰减、引入电磁干扰等。以下将详细探讨…

面向对象—有理数类的设计

目录 1.代码呈现 1.1编写toString、equals方法 1.2测试代码 1.3有理数类的代码 2.论述题 3.有理类设计 1.代码呈现 1.1编写toString、equals方法 (1)toString方法 Overridepublic String toString(){if(this.v20){return "Undefined";}return this.v1 "/…

408数据结构绪论刷题001

答案&#xff1a;D 解析&#xff1a; • A选项&#xff1a;数据元素是组成数据对象的基本单位 &#xff0c;它只是数据的基本个体&#xff0c;不能完整定义数据结构&#xff0c;所以A选项错误。 • B选项&#xff1a;数据对象是性质相同的数据元素的集合&#xff0c;仅仅描述…

Leetcode 3359. 查找最大元素不超过 K 的有序子矩阵【Plus题】

1.题目基本信息 1.1.题目描述 给定一个大小为 m x n 的二维矩阵 grid。同时给定一个 非负整数 k。 返回满足下列条件的 grid 的子矩阵数量&#xff1a; 子矩阵中最大的元素 小于等于 k。 子矩阵的每一行都以 非递增 顺序排序。 矩阵的子矩阵 (x1, y1, x2, y2) 是通过选择…

文件系统 软硬连接

&#x1f33b;个人主页&#xff1a;路飞雪吖~ &#x1f320;专栏&#xff1a;Linux 目录 一、理解文件系统 &#x1f320;磁盘结构 二、软硬连接 &#x1f31f;软硬链接 &#x1f320;软链接&#xff1a; &#x1f320;硬链接&#xff1a; &#x1f31f;理解软硬链接的应…

计算机视觉——JPEG AI 标准发布了图像压缩新突破与数字图像取证的挑战及应对策略

概述 今年2月&#xff0c;经过多年旨在利用机器学习技术开发一种更小、更易于传输和存储且不损失感知质量的图像编解码器的研究后&#xff0c;JPEG AI国际标准正式发布。 来自JPEG AI官方发布流&#xff0c;峰值信噪比&#xff08;PSNR&#xff09;与JPEG AI的机器学习增强方法…

Oracle 19c部署之数据库软件安装(二)

在完成了Oracle Linux 9的初始化配置之后&#xff0c;我们准备安装Oracle 19c数据库软件。 Oracle数据库支持两种主要的安装方式&#xff1a;图形化安装和静默安装。这两种方法各有优缺点&#xff0c;选择哪种取决于你的具体需求、环境配置以及个人偏好。 图形化安装 图形化安…

在Vmware15(虚拟机免费) 中安装纯净win10详细过程

一、软件备选 1. VMware15.5.1 网盘下载地址 链接: https://pan.baidu.com/s/1y6GLJ2MG-1tomWblt3otsg?pwdim8e 提取码: im8e 2. windows镜像下载 去官网下载ios包 链接&#xff1a;https://www.microsoft.com/zh-cn/software-download/windows10 二、在VMware15.5.1下安装w…