前言
最近在做社交業務,用戶進入APP后有簽到功能,簽到成功后獲取相應的獎勵:
項目狀況:前期嘗試業務階段;
特點:
- 快速實現(不需要做太重,滿足初期推廣運營即可)
- 快速投入市場去運營
用戶簽到:
- 用戶在每次啟動時查詢簽到記錄(規則:連續7日簽到從0開始,簽到過程中有斷簽從0開始)
- 如果今日未簽到則提示用戶可以進行簽到
- 用戶簽到獲取相應的獎勵
提到簽到,腦海中首先浮現特點:
- 需要記錄每位用戶每天的簽到情況
- 查詢時根據規則進行簽到記錄情況
需求&流程設計&技術實現方案
需求原型圖
查詢簽到記錄
進行簽到
技術實現方案
- SpringBoot
- MySQL
數據庫表結構
簽到記錄最新表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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= '用戶簽到表' ; |
簽到記錄歷史表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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= '用戶簽到歷史表' ; |
代碼實現
完整代碼(GitHub,歡迎大家Star,Fork,Watch)
https://github.com/dangnianchuntian/springboot
主要代碼展示
Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
/* * Copyright (c) 2020. [email protected] All Rights Reserved. * 項目名稱:Spring Boot實戰:簽到獎勵實現方案 * 類名稱:SignInController.java * 創建人:張晗 * 聯系方式:[email protected] * 開源地址: 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; @RestController public class SignInController { @Autowired private 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
/* * Copyright (c) 2020. [email protected] All Rights Reserved. * 項目名稱:Spring Boot實戰:簽到獎勵實現方案 * 類名稱:SignInServiceImpl.java * 創建人:張晗 * 聯系方式:[email protected] * 開源地址: 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.*; @Service public class SignInServiceImpl implements SignInService { @Autowired private XZhSignInMapper xZhSignInMapper; @Autowired private XZhSignInHistMapper xZhSignInHistMapper; //校驗連續天數是否為7 @Value("#{T(java.lang.Integer).parseInt('${zh.sign.in.continuite.day.threshold:7}')}") public Integer continuiteDayThreshold; //簽到獎勵金幣集合配置 @Autowired public SignInRewardMoneyListConfig signInRewardMoneyListConfig; /** * 查詢用戶簽到記錄 */ @Override public 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)); } /** * 進行簽到 */ @Override public 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); } } |
測試
模擬用戶進行簽到
進行請求
查看數據庫結果
模擬用戶查詢簽到記錄
進行請求
總結
- 亮點:實現業務連續簽到,斷簽以及獎勵的業務
- 注意點:基于數據庫查詢做的,在進行簽到接口需要用redis鎖防止并發操作
- 后續會持續分享更多業務中的亮點
到此這篇關于SpringBoot 簽到獎勵實現方案的示例代碼的文章就介紹到這了,更多相關SpringBoot 簽到獎勵內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/u012829124/article/details/108306434