java签到_实战:如果让你用SpringBoot实现签到奖励的功能,你会怎么做?

d1ffe197b10b8c8779cbe56bb1e803f7.png

阅读本文大概需要 6 分钟。

来自:网络

前言

最近在做社交业务,用户进入APP后有签到功能,签到成功后获取相应的奖励:项目状况:前期尝试业务阶段;

特点:

  • 快速实现(不需要做太重,满足初期推广运营即可)
  • 快速投入市场去运营

用户签到:

  • 用户在每次启动时查询签到记录(规则:连续7日签到从0开始,签到过程中有断签从0开始)
  • 如果今日未签到则提示用户可以进行签到
  • 用户签到获取相应的奖励

提到签到,脑海中首先浮现特点:

  • 需要记录每位用户每天的签到情况
  • 查询时根据规则进行签到记录情况

需求&流程设计&技术实现方案

1.需求原型图

ac1a1ca9dd9cd790a1883e42d78aeb28.png

2.查询签到记录

c25b53a6bd45bff33c57042a2d6b7649.png

3.进行签到

1fefb4a3c92e7d2ce28fdfaf966a42de.png

4.技术实现方案

  • SpringBoot
  • MySQL

数据库表结构

1.签到记录最新表

   CREATE TABLE `zh_sign_in` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`bu_no` varchar(32) DEFAULT NULL COMMENT '业务编码',`customer_id` varchar(32) DEFAULT NULL COMMENT '签到用户编码',`sign_in_date` datetime DEFAULT NULL COMMENT '签到日期(单位精确到日)',`reward_money` int(11) DEFAULT NULL COMMENT '本次签到奖励金币个数',`continuite_day` int(2) DEFAULT '1' COMMENT '连续签到天数(A:7天内如果有断签从0开始 B:7天签满从0开始)',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`param1` int(2) DEFAULT NULL COMMENT '预留字段1',`param2` int(4) DEFAULT NULL COMMENT '预留字段2',`param3` int(11) DEFAULT NULL COMMENT '预留字段3',`param4` varchar(20) DEFAULT NULL COMMENT '预留字段4',`param5` varchar(32) DEFAULT NULL COMMENT '预留字段5',`param6` varchar(64) DEFAULT NULL COMMENT '预留字段6',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `uk_zh_sign_in_buno` (`bu_no`),UNIQUE KEY `uk_zh_sign_in_cid_signindate` (`customer_id`,`sign_in_date`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户签到表';

2.签到记录历史表

   CREATE TABLE `zh_sign_in_hist` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`bu_no` varchar(32) DEFAULT NULL COMMENT '业务编码',`customer_id` varchar(32) DEFAULT NULL COMMENT '签到用户编码',`sign_in_date` datetime NULL DEFAULT NULL COMMENT '签到日期(单位精确到日)',`reward_money` int(11) DEFAULT NULL COMMENT '本次签到奖励金币个数',`continuite_day` int(2) DEFAULT '1' COMMENT '连续签到天数(A:7天内如果有断签从0开始 B:7天签满从0开始)',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`param1` int(2) DEFAULT NULL COMMENT '预留字段1',`param2` int(4) DEFAULT NULL COMMENT '预留字段2',`param3` int(11) DEFAULT NULL COMMENT '预留字段3',`param4` varchar(20) DEFAULT NULL COMMENT '预留字段4',`param5` varchar(32) DEFAULT NULL COMMENT '预留字段5',`param6` varchar(64) DEFAULT NULL COMMENT '预留字段6',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `uk_zh_sign_in_hist_cid_signindate` (`customer_id`,`sign_in_date`) USING BTREE,KEY `key_zh_sign_in_hist_buno` (`bu_no`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户签到历史表';

代码实现

1.完整代码(GitHub,欢迎大家Star,Fork,Watch)

https://github.com/dangnianchuntian/springboot

2.主要代码展示

         Controller/* * Copyright (c) 2020. zhanghan_java@163.com All Rights Reserved.* 项目名称:Spring Boot实战:签到奖励实现方案* 类名称:SignInController.java* 创建人:张晗* 联系方式:zhanghan_java@163.com* 开源地址: https://github.com/dangnianchuntian/springboot* 博客地址: https://zhanghan.blog.csdn.net*/package com.zhanghan.zhsignin.controller;import com.zhanghan.zhsignin.controller.request.PostSignInRequest;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import com.zhanghan.zhsignin.controller.request.ListSignInDetailRequest;import com.zhanghan.zhsignin.service.SignInService;@RestControllerpublic class SignInController {@Autowiredprivate SignInService signInService;/*** 查询签到记录*/@RequestMapping(value = "/list/sign/in/detail", method = RequestMethod.POST)public Object listSignInDetail(@RequestBody @Validated ListSignInDetailRequest listSignInDetailRequest) {return signInService.listSignInDetail(listSignInDetailRequest);}/*** 用户进行签到*/@RequestMapping(value = "/post/sign/in", method = RequestMethod.POST)public Object postSignIn(@RequestBody @Validated PostSignInRequest postSignInRequest) {return signInService.postSignIn(postSignInRequest);}}

service

   /** Copyright (c) 2020. zhanghan_java@163.com All Rights Reserved.* 项目名称:Spring Boot实战:签到奖励实现方案* 类名称:SignInServiceImpl.java* 创建人:张晗* 联系方式:zhanghan_java@163.com* 开源地址: https://github.com/dangnianchuntian/springboot* 博客地址: https://zhanghan.blog.csdn.net*/package com.zhanghan.zhsignin.service.impl;import cn.hutool.core.util.IdUtil;import com.zhanghan.zhsignin.config.SignInRewardMoneyListConfig;import com.zhanghan.zhsignin.constant.SignInConstant;import com.zhanghan.zhsignin.controller.request.ListSignInDetailRequest;import com.zhanghan.zhsignin.controller.request.PostSignInRequest;import com.zhanghan.zhsignin.controller.response.ListSignInDetailResponse;import com.zhanghan.zhsignin.mybatis.entity.XZhSignInEntity;import com.zhanghan.zhsignin.mybatis.entity.XZhSignInHistEntity;import com.zhanghan.zhsignin.mybatis.mapper.XZhSignInHistMapper;import com.zhanghan.zhsignin.mybatis.mapper.XZhSignInMapper;import com.zhanghan.zhsignin.service.SignInService;import com.zhanghan.zhsignin.util.DateUtils;import com.zhanghan.zhsignin.util.wrapper.WrapMapper;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import org.springframework.util.CollectionUtils;import java.util.Date;import java.util.List;import java.util.stream.Collectors;import static com.zhanghan.zhsignin.constant.SignInConstant.*;@Servicepublic class SignInServiceImpl implements SignInService {@Autowiredprivate XZhSignInMapper xZhSignInMapper;@Autowiredprivate XZhSignInHistMapper xZhSignInHistMapper;//校验连续天数是否为7@Value("#{T(java.lang.Integer).parseInt('${zh.sign.in.continuite.day.threshold:7}')}")public Integer continuiteDayThreshold;//签到奖励金币集合配置@Autowiredpublic SignInRewardMoneyListConfig signInRewardMoneyListConfig;/*** 查询用户签到记录*/@Overridepublic Object listSignInDetail(ListSignInDetailRequest listSignInDetailRequest) {//若配置文件中未配置签到奖励则不展示签到记录List<Integer> signInRewardMoneyListConfigList = signInRewardMoneyListConfig.getList();if (CollectionUtils.isEmpty(signInRewardMoneyListConfigList)) {return WrapMapper.ok(new ListSignInDetailResponse(false));}String customerId = listSignInDetailRequest.getCustomerId();XZhSignInEntity xZhSignInEntity = xZhSignInMapper.findByCustomerId(customerId);List<ListSignInDetailResponse.SignInDetail> signInDetailList = signInRewardMoneyListConfigList.stream().map(aa -> new ListSignInDetailResponse.SignInDetail(0, aa)).collect(Collectors.toList());//该用户之前未签到过if (null == xZhSignInEntity) {return WrapMapper.ok(new ListSignInDetailResponse(TODAY_NOT_SIGN_IN, SignInConstant.CONTINUITE_DAY_ZERO, signInDetailList));}long signInDateTime = xZhSignInEntity.getSignInDate().getTime();//最近一次签到是否为昨日之前if (signInDateTime < DateUtils.getYesterdayDateTime()) {return WrapMapper.ok(new ListSignInDetailResponse(TODAY_NOT_SIGN_IN, SignInConstant.CONTINUITE_DAY_ZERO, signInDetailList));}//最近一次签到是否为昨日Integer todaySignStatus = TODAY_YES_SIGN_IN;Integer continuiteDay = xZhSignInEntity.getContinuiteDay();if (signInDateTime < DateUtils.getTodayDateTime()) {//最近一次签到是昨日且之前已连续签到7日if (continuiteDay >= continuiteDayThreshold) {return WrapMapper.ok(new ListSignInDetailResponse(TODAY_NOT_SIGN_IN, SignInConstant.CONTINUITE_DAY_ZERO, signInDetailList));}//最近一次签到是昨日且之前连续未超7日todaySignStatus = TODAY_NOT_SIGN_IN;}//查询用户签到历史记录List<XZhSignInHistEntity> xZhSignInHistEntitieList = xZhSignInHistMapper.listByCustomerIdAndLimit(customerId, continuiteDay);for (XZhSignInHistEntity xZhSignInHistEntity : xZhSignInHistEntitieList) {ListSignInDetailResponse.SignInDetail signInDetail = new ListSignInDetailResponse.SignInDetail(TODAY_YES_SIGN_IN, xZhSignInHistEntity.getRewardMoney());signInDetailList.remove(xZhSignInHistEntity.getContinuiteDay() - 1);signInDetailList.add(xZhSignInHistEntity.getContinuiteDay() - 1, signInDetail);}return WrapMapper.ok(new ListSignInDetailResponse(todaySignStatus, continuiteDay, signInDetailList));}/*** 进行签到*/@Overridepublic Object postSignIn(PostSignInRequest postSignInRequest) {//若配置文件中未配置签到奖励则不展示签到记录List<Integer> signInRewardMoneyListConfigList = signInRewardMoneyListConfig.getList();if (CollectionUtils.isEmpty(signInRewardMoneyListConfigList)) {return WrapMapper.ok();}//获取session用户对象String customerId = postSignInRequest.getCustomerId();//根据customerId查询用户签到记录XZhSignInEntity xZhSignInEntityByCustomerId = xZhSignInMapper.findByCustomerId(customerId);//签到记录是否为空if (null == xZhSignInEntityByCustomerId) {XZhSignInEntity xZhSignInEntity = new XZhSignInEntity();xZhSignInEntity.setBuNo(IdUtil.simpleUUID());xZhSignInEntity.setCustomerId(customerId);xZhSignInEntity.setContinuiteDay(CONTINUITE_DAY_ONE);xZhSignInEntity.setRewardMoney(signInRewardMoneyListConfigList.get(0));xZhSignInEntity.setSignInDate(DateUtils.getTodayDate());insertSigninAndHist(xZhSignInEntity);return WrapMapper.ok();}long signInDateTime = xZhSignInEntityByCustomerId.getSignInDate().getTime();if (signInDateTime == DateUtils.getTodayDateTime()) {return WrapMapper.error("今天已经签到");}//获取连续签到天数Integer continuiteDay = continuiteDay(xZhSignInEntityByCustomerId.getContinuiteDay(), signInDateTime);xZhSignInEntityByCustomerId.setSignInDate(DateUtils.getTodayDate());xZhSignInEntityByCustomerId.setContinuiteDay(continuiteDay);xZhSignInEntityByCustomerId.setRewardMoney(signInRewardMoneyListConfigList.get(continuiteDay - 1));xZhSignInEntityByCustomerId.setUpdateTime(new Date());xZhSignInEntityByCustomerId.setBuNo(IdUtil.simpleUUID());updateSignInAndInsertHist(xZhSignInEntityByCustomerId);return WrapMapper.ok();}private Integer continuiteDay(Integer continuiteDay, Long signInDateTime) {if (signInDateTime < DateUtils.getYesterdayDateTime()) {return CONTINUITE_DAY_ONE;}if (continuiteDay >= continuiteDayThreshold) {return CONTINUITE_DAY_ONE;}return continuiteDay + 1;}private void insertSigninAndHist(XZhSignInEntity xZhSignInEntity) {xZhSignInMapper.insertSelective(xZhSignInEntity);XZhSignInHistEntity xZhSignInHistEntity = new XZhSignInHistEntity();BeanUtils.copyProperties(xZhSignInEntity, xZhSignInHistEntity);xZhSignInHistEntity.setId(null);xZhSignInHistMapper.insertSelective(xZhSignInHistEntity);}private void updateSignInAndInsertHist(XZhSignInEntity xZhSignInEntity) {xZhSignInMapper.updateByPrimaryKeySelective(xZhSignInEntity);XZhSignInHistEntity xZhSignInHistEntity = new XZhSignInHistEntity();BeanUtils.copyProperties(xZhSignInEntity, xZhSignInHistEntity);xZhSignInHistEntity.setId(null);xZhSignInHistMapper.insertSelective(xZhSignInHistEntity);}} 

测试

  • 模拟用户进行签到
    • 进行请求

5dddb54059288be6142fb5bd35dea81e.png
    • 查看数据库结果

3c805fcd1d7ac154b223b648d7e854d6.png
  • 模拟用户查询签到记录
    • 进行请求

3a95f6b359ce593201725f0923712c4b.png

总结

  • 亮点:实现业务连续签到,断签以及奖励的业务
  • 注意点:基于数据库查询做的,在进行签到接口需要用redis锁防止并发操作
  • 后续会持续分享更多业务中的亮点

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

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

相关文章

软件开发工具介绍之 1.代码生成器

在程序开发过程当中&#xff0c;程序员会经常做着重复性的工作&#xff0c;最常见的是访问数据库&#xff0c;程序员要经常编写增、删、改、分页之类的操作。为了避免这个问题&#xff0c;节省大量机械录入的时间和重复劳动&#xff0c;提高工作效率&#xff0c;而将精力集中于…

python自带的shell、其性能优于ipython吗_Python自带的shell,其性能优于IPython

信源X的&#xff0c;自带每一机事件的都相等个随概率&#xff0c;即P。 优于 自带优于 自带求(机械的保养要。 优于标有机械的主管理要指。 下尺性期人手节分的病离急法整复后&#xff0c;自带项处做哪理&#xff1a;还应。 并放下肢射至&#xff0c;优于现右肢放扭伤右下臀及后…

虚拟机测试必备虚拟机之VirtualBox 使用

2019独角兽企业重金招聘Python工程师标准>>> 安装&#xff0c;windowns在官网上对应版本下载下一步安装结束即可&#xff0c;配置有seting可以选择中文&#xff0c;方便理解&#xff0c;其实英文也好功能 不多。 安装linux&#xff1a;ubuntu&#xff0c;如果有网su…

基于.NET Framework 4.0的解决方案部署

VS 2010发布之后&#xff0c;随着而来的框架版本也升级到了.NET Framework 4.0。我相信很多朋友已经在用了吧。这一篇文章总结了如何基于.NET Framework 4.0&#xff0c;进行解决方案部署。 之所以要单独写一下&#xff0c;是因为确实这个版本与之前的.NET Framework 2.0&#…

如何在Windows Azure VM上的SQL Server和Windows Azure SQL Database两者中做出选择

作者信息&#xff1a;本篇文章是由SQL Server Cloud Infrastructure Team的 Madhan Arumugam 和 Guy Bowerman共同著作。 简介 把SQL 数据托管在哪里&#xff0c;Windows Azure 为您提供了两个选择&#xff0c;VM上的SQL Server&#xff08;以下简称 SQL/VM&#xff09;和 Wind…

graphviz 画决策树_数据挖掘入门系列教程(四)之基于scikit-lean决策树处理Iris

数据挖掘入门系列教程&#xff08;四&#xff09;之基于scikit-lean决策树处理Iris加载数据集数据特征训练随机森林调参工程师结尾数据挖掘入门系列教程&#xff08;四&#xff09;之基于scikit-lean决策树处理Iris在上一篇博客&#xff0c;我们介绍了决策树的一些知识。如果对…

设计模式UML图

1.简单工厂模式 2.工厂模式 工厂模式与简单工厂模式的不同在于&#xff0c;每个操作类都有自己的工厂&#xff0c;而且把逻辑判断交给了客户端&#xff0c;而简单工厂的逻辑判断在工厂类里边&#xff0c;当增加新的操作类时&#xff0c;简单工厂需要修改工厂类&#xff0c;而工…

Android小項目之--ListView與ListAcitivity完善論壇管理效果2(附源碼)

ListAcitivity 类型布局用来配置应用程序&#xff0c;主要为显示菜单列表、列表明细项目&#xff0c;假如让程序继承 ListActivity ,可以实现以下的方法&#xff1a; getListAdapter()  取得目前列表项目的 AdaptergetListView()  取得目前列表的 ViewgetSelectedItemId() …

docker 覆盖 entrypoint_最佳实践,Dockerfile中ENTRYPOINT与CMD指令的区别与建议

通过本文你会获得什么熟悉Dockerfile中ENTRYPOINT和CMD指令之间的区别&#xff0c;以及在实际项目中的使用建议。1 - 开始前准备首先你要有个docker环境&#xff0c;以下实验基于&#xff1a;docker 18.09&#xff0c;以及alpine:3.8镜像。下载基础镜像docker pull alpine:3.82…

单实例单向rac搭建gg流

1、 m1 m2 m3 source端 2、 在m1 m2 m3 上 /etc/hosts 172.16.10.140 source source上 添加 #public network 172.16.15.101 m1 172.16.15.102 m2 172.16.15.103 m3 #private network 10.11.11.1 m1-pri 10.11.11.2 m2-pri 10.11.11.3 m3-pri 29 #VIP network 172.16.15.1…

python自动登录教程_Python 实现自动登录+点击+滑动验证功能

需要用到的库有selenium&#xff0c;还需要安装Chrome浏览器驱动&#xff0c;具体如何安装我就不详述了 在这里我模拟了csdn的登录过程 ** 1**.首先打开网页&#xff0c;用户名密码登录&#xff0c;然后定位用户名输入框&#xff0c;和密码输入框&#xff0c;输入后 点击登陆 弹…

2月份.xyz域名总量10强:西数称王 注册量破百万

IDC评述网&#xff08;idcps.com&#xff09;02月25日报道&#xff1a;根据ntldstats.com发布的最新数据显示&#xff0c;截止至2016年2月24日17时&#xff0c;国内外.xyz域名总量十强名单顺序&#xff0c;与上期1月28日对比&#xff0c;无任何变化。最值得一提的是&#xff0c…

flash作业_一起作业,你很智障!

电子作业现在貌似很流行&#xff0c;在很多学校都有&#xff0c;具体的利弊就不再赘述&#xff0c;可以点击前面的超链接跳转到某度百科自己看。今天只是忍不住怕盘点下国内知名电子作业平台——一起作业网的一些智障设计。。。本来想写到这里去的&#xff1a;有哪些让人拍案叫…

QtCreator添加图片资源

在qt creator里面&#xff0c;设计师designer是一个很好用的功能&#xff0c;通过它我们可以可视化的设计界面。当然了&#xff0c;设计界面就需要各种各样的效果&#xff0c;图片资源是不可少的。今天&#xff0c;小编就来教大家qt怎么添加图片资源 工具/原料 qt creator方法/…

只安装python_AI帮你写Python,安装只需5步,还能任你调教 | 开源

一行一行地敲代码就像是徒手搬砖&#xff0c;聪明的程序猿们表示&#xff1a;我们要解放生产力&#xff01; 比如像这样&#xff1a;在机器学习的时代&#xff0c;AI智能补全代码早已不是梦想&#xff0c;各种IDE和插件都在努力帮助程序猿减少击键次数&#xff0c;延长键盘寿命…

巧用apply让javascript函数仅执行一次

RT,有时候我们只想要让某些脚步函数执行一次就算完成任务了。如何实现这种功能呢&#xff1f;简单模仿下面这段就可以轻松搞定了&#xff1a; 代码 varobj newObject();obj.triggerOnce function(fn) { //控制让函数只触发一次returnfunction() { try{ fn.ap…

评论时间戳格式化

如图&#xff1a; 注意&#xff0c;评论时间戳的格式&#xff0c;刚才&#xff0c;几小时之前&#xff0c;几天之前..... 实现需要一个时间格式的工具类&#xff0c;如果用java.util.Date当然也可以实现&#xff0c;这里说的是更方便的joda-time。 maven地址&#xff1a;http:/…

android lint工作机制,Android架构

MVCmvc model view controller 模式视图控制器M: 业务逻辑处理V&#xff1a;处理数据显示的部分C&#xff1a;Activity处理用户交互的问题&#xff0c;中间桥梁的作用&#xff0c;解耦的作用。特点&#xff1a;耦合性低扩展性好&#xff0c;利于维护模块职责划分明确Model层&am…

opendds开发指南中文版_最强的开发者技术路线图已经更新到 2020 GitHub 超 118k还有中文...

想必大家都知道&#xff0c;学习路线图是学习一门新技术的入门指南&#xff0c;让我们对技术有一个大概的了解&#xff0c;并且在学习感到困惑时被指导。所谓不求最好&#xff0c;但求最全。今天在在就给大家带来了一个国外大牛开源的项目 — 「developer-roadmap」&#xff0c…

iOS APP网络分析之rvictl(可以捕捉除了Wifi以外的网络类型)

iOS应用&#xff08;包括移动应用&#xff09;的网络分析&#xff0c;一般采用将移动设备上的流量导入到PC机上&#xff0c;利用PC上成熟的数据包分析工具例如wireshark等来进行分析的方法。 总的来说&#xff0c;有以下三种方法&#xff1a;一、在PC上设置网络共享&#xff0c…