前言
最近在做社交業(yè)務(wù),用戶進(jìn)入APP后有簽到功能,簽到成功后獲取相應(yīng)的獎勵:
項(xiàng)目狀況:前期嘗試業(yè)務(wù)階段;
特點(diǎn):
- 快速實(shí)現(xiàn)(不需要做太重,滿足初期推廣運(yùn)營即可)
- 快速投入市場去運(yùn)營
用戶簽到:
- 用戶在每次啟動時(shí)查詢簽到記錄(規(guī)則:連續(xù)7日簽到從0開始,簽到過程中有斷簽從0開始)
- 如果今日未簽到則提示用戶可以進(jìn)行簽到
- 用戶簽到獲取相應(yīng)的獎勵
提到簽到,腦海中首先浮現(xiàn)特點(diǎn):
- 需要記錄每位用戶每天的簽到情況
- 查詢時(shí)根據(jù)規(guī)則進(jìn)行簽到記錄情況
需求&流程設(shè)計(jì)&技術(shù)實(shí)現(xiàn)方案
需求原型圖
查詢簽到記錄
進(jìn)行簽到
技術(shù)實(shí)現(xiàn)方案
- SpringBoot
- MySQL
數(shù)據(jù)庫表結(jié)構(gòu)
簽到記錄最新表
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 '業(yè)務(wù)編碼' , `customer_id` varchar (32) DEFAULT NULL COMMENT '簽到用戶編碼' , `sign_in_date` datetime DEFAULT NULL COMMENT '簽到日期(單位精確到日)' , `reward_money` int (11) DEFAULT NULL COMMENT '本次簽到獎勵金幣個(gè)數(shù)' , `continuite_day` int (2) DEFAULT '1' COMMENT '連續(xù)簽到天數(shù)(A:7天內(nèi)如果有斷簽從0開始 B:7天簽滿從0開始)' , `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間' , `update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新時(shí)間' , `param1` int (2) DEFAULT NULL COMMENT '預(yù)留字段1' , `param2` int (4) DEFAULT NULL COMMENT '預(yù)留字段2' , `param3` int (11) DEFAULT NULL COMMENT '預(yù)留字段3' , `param4` varchar (20) DEFAULT NULL COMMENT '預(yù)留字段4' , `param5` varchar (32) DEFAULT NULL COMMENT '預(yù)留字段5' , `param6` varchar (64) DEFAULT NULL COMMENT '預(yù)留字段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 '業(yè)務(wù)編碼' , `customer_id` varchar (32) DEFAULT NULL COMMENT '簽到用戶編碼' , `sign_in_date` datetime NULL DEFAULT NULL COMMENT '簽到日期(單位精確到日)' , `reward_money` int (11) DEFAULT NULL COMMENT '本次簽到獎勵金幣個(gè)數(shù)' , `continuite_day` int (2) DEFAULT '1' COMMENT '連續(xù)簽到天數(shù)(A:7天內(nèi)如果有斷簽從0開始 B:7天簽滿從0開始)' , `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間' , `update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新時(shí)間' , `param1` int (2) DEFAULT NULL COMMENT '預(yù)留字段1' , `param2` int (4) DEFAULT NULL COMMENT '預(yù)留字段2' , `param3` int (11) DEFAULT NULL COMMENT '預(yù)留字段3' , `param4` varchar (20) DEFAULT NULL COMMENT '預(yù)留字段4' , `param5` varchar (32) DEFAULT NULL COMMENT '預(yù)留字段5' , `param6` varchar (64) DEFAULT NULL COMMENT '預(yù)留字段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= '用戶簽到歷史表' ; |
代碼實(shí)現(xiàn)
完整代碼(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. zhanghan_java@163.com All Rights Reserved. * 項(xiàng)目名稱:Spring Boot實(shí)戰(zhàn):簽到獎勵實(shí)現(xiàn)方案 * 類名稱:SignInController.java * 創(chuàng)建人:張晗 * 聯(lián)系方式: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; @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); } /** * 用戶進(jìn)行簽到 */ @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. zhanghan_java@163.com All Rights Reserved. * 項(xiàng)目名稱:Spring Boot實(shí)戰(zhàn):簽到獎勵實(shí)現(xiàn)方案 * 類名稱:SignInServiceImpl.java * 創(chuàng)建人:張晗 * 聯(lián)系方式: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.*; @Service public class SignInServiceImpl implements SignInService { @Autowired private XZhSignInMapper xZhSignInMapper; @Autowired private XZhSignInHistMapper xZhSignInHistMapper; //校驗(yàn)連續(xù)天數(shù)是否為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()) { //最近一次簽到是昨日且之前已連續(xù)簽到7日 if (continuiteDay >= continuiteDayThreshold) { return WrapMapper.ok(new ListSignInDetailResponse(TODAY_NOT_SIGN_IN, SignInConstant.CONTINUITE_DAY_ZERO, signInDetailList)); } //最近一次簽到是昨日且之前連續(xù)未超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)); } /** * 進(jìn)行簽到 */ @Override public Object postSignIn(PostSignInRequest postSignInRequest) { //若配置文件中未配置簽到獎勵則不展示簽到記錄 List<Integer> signInRewardMoneyListConfigList = signInRewardMoneyListConfig.getList(); if (CollectionUtils.isEmpty(signInRewardMoneyListConfigList)) { return WrapMapper.ok(); } //獲取session用戶對象 String customerId = postSignInRequest.getCustomerId(); //根據(jù)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( "今天已經(jīng)簽到" ); } //獲取連續(xù)簽到天數(shù) 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); } } |
測試
模擬用戶進(jìn)行簽到
進(jìn)行請求
查看數(shù)據(jù)庫結(jié)果
模擬用戶查詢簽到記錄
進(jìn)行請求
總結(jié)
- 亮點(diǎn):實(shí)現(xiàn)業(yè)務(wù)連續(xù)簽到,斷簽以及獎勵的業(yè)務(wù)
- 注意點(diǎn):基于數(shù)據(jù)庫查詢做的,在進(jìn)行簽到接口需要用redis鎖防止并發(fā)操作
- 后續(xù)會持續(xù)分享更多業(yè)務(wù)中的亮點(diǎn)
到此這篇關(guān)于SpringBoot 簽到獎勵實(shí)現(xiàn)方案的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot 簽到獎勵內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/u012829124/article/details/108306434