springboot 7天签到功能设计 数据库表设计 加代码

实现一个类似于这样的签到功能 (参考的百度网盘签到页面)

数据表是一个用户只有一条签到记录的设计, 没有使用签到一次表中加一条数据, 那样的话数据太多了

签到有中断,下一次签到重新从第一天开始计算连续签到天数

表结构:

CREATE TABLE `sign_in` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` bigint(20) NOT NULL COMMENT '签到用户id',
  `continue_days` int(3) NOT NULL DEFAULT '1' COMMENT '连续签到天数',
  `update_time` datetime DEFAULT NULL COMMENT '更新日期, 最后签到日期',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `user_id_unique` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户签到表';

实体对象:

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

/**
 * 用户签到表
 *
 * @author lixx
 * @version 1.0
 * @date 2020-06-10 10:36
 */
@Data
@NoArgsConstructor
public class SignIn {


	/**
	 * 主键
	 */
	@TableId(type = IdType.AUTO)
	private Long id;

	/**
	 * 签到用户id
	 */
	private Long userId;

	/**
	 * 连续签到天数
	 */
	private Integer continueDays;

	/**
	 * 更新日期, 最后签到日期
	 */
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
	@TableField(fill = FieldFill.UPDATE)
	private LocalDateTime updateTime;

	public SignIn(Long userId, LocalDateTime updateTime) {
		this.userId = userId;
		this.updateTime = updateTime;
	}
}

签到接口:

	/**
	 * 用户签到
	 *
	 * @param userId 用户id
	 * @return
	 */
	public JsonResult signIn(Long userId) {
		// 查询用户是否签过到
		QueryWrapper<SignIn> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(SignIn::getUserId, userId);
		SignIn signIn = signInMapper.selectOne(queryWrapper);
		/*没有签过到, 直接新增*/
		if (null == signIn) {
			signInMapper.insert(new SignIn(userId, LocalDateTime.now()));
		} else {/*签过到*/
			// 判断最后签到日期与当前日期是否超过一天
			LocalDate signInTime = signIn.getUpdateTime().toLocalDate();
			LocalDate currTime = LocalDate.now();
			long daysDiff = ChronoUnit.DAYS.between(signInTime, currTime);
			if (daysDiff <= 0) {
				return JsonResult.buildSuccess("重复签到");
			}
			if (daysDiff > 1) {
				// 1, 超过一天, 把连续签到的天数重置为 1
				signIn.setContinueDays(1);
			} else {
				// 2, 没有超过一天, 把连续签到的天数+1
				signIn.setContinueDays(signIn.getContinueDays() + 1);
			}
			signIn.setUpdateTime(LocalDateTime.now());
			signInMapper.updateById(signIn);
		}
		return JsonResult.buildSuccess();
	}

这样签到功能就做好了, 数据库数据如下:

签到列表接口:

需要增加一个接口返回的dto类型(大家用map也行)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @author lixx
 * @version 1.0
 * @date 2020-06-10 15:09
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SignInDto implements Serializable {

	/**
	 * 表示签到的天数
	 */
	private Integer day;

	/**
	 * 1表示已经签到, 0表示未签到
	 */
	private Integer flag;

	// 如果还有其他业务字段就加在后面, 如积分, 如金币

}

签到列表接口逻辑代码:

	/**
	 * 用户签到列表
	 *
	 * @param userId 用户id
	 * @return
	 */
	public JsonResult signInList(Long userId) {
		QueryWrapper<SignIn> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(SignIn::getUserId, userId);
		SignIn signIn = signInMapper.selectOne(queryWrapper);
		List<SignInDto> list = new ArrayList<>(7);
		if (null == signIn) {
			// 没有签过到
			for (int i = 1; i < 8; i++) {
				list.add(new SignInDto(i, 0));
			}
		} else {
			// 签过到
			Integer continueDays = signIn.getContinueDays();
			// 1, 前六天的 flag是要固定的
			if (continueDays <= 6) {
				for (int i = 1; i < 8; i++) {
					if (i <= continueDays) {
						list.add(new SignInDto(i, 1));
					} else {
						list.add(new SignInDto(i, 0));
					}
				}
			} else {
				// 2, 6天后的签到天数要跟随日期增加
				for (int i = 5; i > -2; i--) {
					if (i > -1) {
						list.add(new SignInDto(continueDays - i, 1));
					} else {
						list.add(new SignInDto(continueDays + 1, 0));
					}
				}
			}
		}
		return JsonResult.buildSuccess(list);
	}

效果如下:

1:签到第五天的时候

2:签到第7天的时候

3:签到第N天的时候

ps: 每天凌晨要把未连续签到用户的连续签到天数(sign_in表的continue_days字段)设置为0, 我这里使用的是数据库定时任务, 大家也可以使用代码的定时任务,看个人选择

/*定时任务*/
-- 每天凌晨重置超过时间未签到的连续签到天数为0
CREATE EVENT IF NOT EXISTS reset_expired_signins
    ON SCHEDULE EVERY 1 DAY STARTS DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 1 DAY), INTERVAL 5 MINUTE)
    ON COMPLETION PRESERVE ENABLE
    -- 更新语句
    DO UPDATE sign_in SET continue_days = 0 WHERE id IN ( SELECT a.id FROM ( SELECT id FROM sign_in WHERE DATEDIFF(CURDATE(), update_time) > 1 ) AS a )

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7 号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值