news 2026/2/9 9:45:05

天机学堂-积分功能-day07(五)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
天机学堂-积分功能-day07(五)

接口

1.签到功能接口

参数说明
请求方式POST
请求路径/sign-records
请求参数
返回值{ "signDays": 10, // 连续签到天数 "points" : 14 // 今日签到获取的积分 }
SignRecordController.java
/** * 新增签到记录 * @return SignResultVO */@PostMapping@ApiOperation("新增签到记录")publicSignResultVOaddSignRecords(){returnsignRecordService.addSignRecords();}
ISignRecordService.java
SignResultVOaddSignRecords();
RedisConstants.java
publicinterfaceRedisConstants{/** * 签到记录的key前缀 完整格式为 sign:uid:用户id:年月 */StringSIGN_RECORD_KEY_PREFIX="sign:uid:";}
SignRecordServiceImpl.java
@OverridepublicSignResultVOaddSignRecords(){// 1.签到Longuser=UserContext.getUser();StringsignRecordKeyPrefix=RedisConstants.SIGN_RECORD_KEY_PREFIX;Stringnow=LocalDate.now().format(DateUtils.SIGN_DATE_SUFFIX_FORMATTER);//key offsetStringkey=signRecordKeyPrefix+user+now;intoffset=LocalDate.now().getDayOfMonth()-1;Booleanb=stringRedisTemplate.opsForValue().setBit(key,offset,true);// 2计算签到得分//已经签到过了if(Boolean.TRUE.equals(b)){thrownewBizIllegalException("请勿重复签到");}// 3.统计连续签到天数(传递键与当天的日期)intcontinueSignDays=countSignDays(key,offset+1);// 本月签到天数intcountedMonthDays=countMonthDays(key,offset+1);intrewardPoints=0;switch(countedMonthDays){case7:rewardPoints=5;break;case14:rewardPoints=10;break;case21:rewardPoints=15;break;}log.info("用户{}签到成功,连续签到{}天,签到天数{},签到得分{}",user,continueSignDays,countedMonthDays,rewardPoints);SignResultVOsignResultVO=newSignResultVO();//连续签到天数signResultVO.setSignDays(continueSignDays);//签到得分signResultVO.setRewardPoints(rewardPoints);returnsignResultVO;}/** * 计算签到的天数 * * @param key 缓存中的key * @param dayOfMonth 今天几号 * @return */privateintcountMonthDays(Stringkey,intdayOfMonth){// 求本月第一天到今天签到的天数 bitFiled 得到的是十进制// bitField key get u天数 0List<Long>bitField=stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));if(CollUtils.isEmpty(bitField)){return0;}// 本月第一天到今天的签到天数 拿到的十进制Longnum=bitField.get(0);// num转二进制 从后往前推共有多少个一intcounter=0;while((num&1)==1){counter++;num=num>>>1;}returncounter;}/** * 统计连续签到天数 * * @param key 缓存中的key * @param dayOfMonth 今天记号 * @return */privateintcountSignDays(Stringkey,intdayOfMonth){// 1.获取对应的十进制数List<Long>longs=stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));if(CollUtils.isEmpty(longs)){return0;}// 2.循环与运算intsignNum=longs.get(0).intValue();intcontinuousDays=0;// 遇到未签到,终止循环,判断最后一位是否为1(是否签到)while((signNum&1)!=0){// 连续签到,计数器+1continuousDays++;// 右移一位,判断前一天signNum=signNum>>1;}// 5.返回结果returncontinuousDays;}

2.查询本月签到记录

参数说明
请求方式GET
请求路径/sign-records
请求参数
返回值[ 0, // 第1天签到情况 1, // 第2天签到情况 1, // 第3天签到情况 // ... ]
SignRecordController.java
/** * 查询签到记录 * @return List<> */@GetMapping@ApiOperation("查询签到记录")publicList<Integer>querySignRecord(){returnISignRecordService.querySignRecord();}
ISignRecordService.java
List<Integer>querySignRecord();
SignRecordServiceImpl.java
@OverridepublicList<Integer>querySignRecord(){// 1.用户id与日期Longuser=UserContext.getUser();LocalDatetoday=LocalDate.now();// 2.key与偏移量Stringnow=today.format(DateUtils.SIGN_DATE_SUFFIX_FORMATTER);Stringkey=RedisConstants.SIGN_RECORD_KEY_PREFIX+user+now;intoffset=today.getDayOfMonth()-1;// 3.创建集合ArrayList<Integer>arr=newArrayList<>(40);for(inti=0;i<=offset;i++){BooleanisSign=stringRedisTemplate.opsForValue().getBit(key,i);if(Boolean.TRUE.equals(isSign)){arr.add(1);}else{arr.add(0);}}returnarr;}

3.新增积分记录

SignInMessage.java
/** * 签到消息 * * @author ax */@Data@AllArgsConstructor@NoArgsConstructorpublicclassSignInMessage{privateLonguserId;privateIntegerpoints;}
LearningPointsListener.java
packagecom.tianji.learning.mq;importcom.tianji.common.constants.MqConstants;importcom.tianji.learning.enums.PointsRecordType;importcom.tianji.learning.mq.message.SignInMessage;importcom.tianji.learning.service.IPointsRecordService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.amqp.core.ExchangeTypes;importorg.springframework.amqp.rabbit.annotation.Exchange;importorg.springframework.amqp.rabbit.annotation.Queue;importorg.springframework.amqp.rabbit.annotation.QueueBinding;importorg.springframework.amqp.rabbit.annotation.RabbitListener;importorg.springframework.stereotype.Component;/** * 积分监听器 * * @author ax */@Slf4j@Component@RequiredArgsConstructorpublicclassLearningPointsListener{privatefinalIPointsRecordServicepointsRecordService;/** * 监听-写回答积分 * * @param userId */@RabbitListener(bindings=@QueueBinding(value=@Queue(name="qa.points.queue",durable="true"),exchange=@Exchange(name=MqConstants.Exchange.LEARNING_EXCHANGE,type=ExchangeTypes.TOPIC),key=MqConstants.Key.WRITE_REPLY))publicvoidlistenWriteReplyMessage(LonguserId){//用户id,累加的积分,积分类型pointsRecordService.addPointsRecord(userId,5,PointsRecordType.QA);}/** * 监听-签到积分 * * @param message */@RabbitListener(bindings=@QueueBinding(value=@Queue(name="sign.points.queue",durable="true"),exchange=@Exchange(name=MqConstants.Exchange.LEARNING_EXCHANGE,type=ExchangeTypes.TOPIC),key=MqConstants.Key.SIGN_IN))publicvoidlistenWriteSignMessage(SignInMessagemessage){//用户id,累加的积分,积分类型pointsRecordService.addPointsRecord(message.getUserId(),message.getPoints(),PointsRecordType.SIGN);}/** * 监听-被采纳笔记积分 * * @param userId */@RabbitListener(bindings=@QueueBinding(value=@Queue(name="notegathered.points.queue",durable="true"),exchange=@Exchange(name=MqConstants.Exchange.LEARNING_EXCHANGE,type=ExchangeTypes.TOPIC),key=MqConstants.Key.NOTE_GATHERED))publicvoidlistenWriteNoteMessage01(LonguserId){//用户id,累加的积分,积分类型pointsRecordService.addPointsRecord(userId,2,PointsRecordType.NOTE);}/** * 监听-写笔记积分 * * @param userId */@RabbitListener(bindings=@QueueBinding(value=@Queue(name="note.points.queue",durable="true"),exchange=@Exchange(name=MqConstants.Exchange.LEARNING_EXCHANGE,type=ExchangeTypes.TOPIC),key=MqConstants.Key.WRITE_NOTE))publicvoidlistenWriteNoteMessage02(LonguserId){//用户id,累加的积分,积分类型pointsRecordService.addPointsRecord(userId,3,PointsRecordType.NOTE);}/** * 监听-学习视频积分 * * @param userId */@RabbitListener(bindings=@QueueBinding(value=@Queue(name="video.points.queue",durable="true"),exchange=@Exchange(name=MqConstants.Exchange.LEARNING_EXCHANGE,type=ExchangeTypes.TOPIC),key=MqConstants.Key.LEARN_SECTION))publicvoidlistenWriteVideoMessage(LonguserId){//用户id,累加的积分,积分类型pointsRecordService.addPointsRecord(userId,10,PointsRecordType.LEARNING);}/** * 监听-评论积分 * * @param userId */@RabbitListener(bindings=@QueueBinding(value=@Queue(name="comment.points.queue",durable="true"),exchange=@Exchange(name=MqConstants.Exchange.LEARNING_EXCHANGE,type=ExchangeTypes.TOPIC),key=MqConstants.Key.COMMENT))publicvoidlistenWriteCommentMessage(LonguserId){//用户id,累加的积分,积分类型pointsRecordService.addPointsRecord(userId,10,PointsRecordType.COMMENT);}// /* 写回答 */// String WRITE_REPLY = "reply.new";// /* 签到 */// String SIGN_IN = "sign.in";// /* 学习视频 */// String LEARN_SECTION = "section.learned";// /* 写笔记 */// String WRITE_NOTE = "note.new";// /* 笔记被采集 */// String NOTE_GATHERED = "note.gathered";// /* 评论 */// String COMMENT = "comment.new";// LEARNING(1, "课程学习", 50),// SIGN(2, "每日签到", 0),// QA(3, "课程问答", 20),// NOTE(4, "课程笔记", 20),// COMMENT(5, "课程评价", 0),}
IPointsRecordService.java
voidaddPointsRecord(LonguserId,intpoint,PointsRecordTypepointsRecordType);
PointsRecordServiceImpl.java
@OverridepublicvoidaddPointsRecord(LonguserId,intpoint,PointsRecordTypetype){//判断该积分类型是否有上限 type.maxPoints是否大于0if(point<=0){return;}intmaxPoints=type.getMaxPoints();if(maxPoints>0){LocalDateTimenow=LocalDateTime.now();LocalDateTimedayStartTime=DateUtils.getDayStartTime(now);LocalDateTimedayEndTime=DateUtils.getDayEndTime(now);//如果有上限 查询该用户 该积分类型 今日已得积分 points_record 条件userId typeQueryWrapper<PointsRecord>wrapper=newQueryWrapper<>();wrapper.select("sum(points) as totalPoints");wrapper.eq("user_id",userId);wrapper.eq("type",type);wrapper.between("create_time",dayStartTime,dayEndTime);Map<String,Object>map=this.getMap(wrapper);//当前用户该积分类型 已得积分intcurrentPoints=0;if(map!=null&&map.containsKey("totalPoints")){BigDecimaltotalPoints=(BigDecimal)map.get("totalPoints");currentPoints=totalPoints.intValue();}//判断已得积分是否超过上限if(currentPoints>=maxPoints){//说明已得积分 达到上限return;}// 此时的point标识能得得积分if(currentPoints+point>maxPoints){point=maxPoints-currentPoints;}}//保存积分PointsRecordrecord=newPointsRecord();record.setUserId(userId);record.setType(type);record.setPoints(point);this.save(record);}

4.查询今日积分情况

参数说明
请求方式GET
请求路径/points/today
请求参数
返回值[ { "type": "每日签到", // 积分类型描述 "points" : 1, // 今日签到获取的积分 "maxPoints" : 5, // 每日积分上限 }, { "type": "回答问题", // 积分类型描述 "points" : 1, // 今日签到获取的积分 "maxPoints" : 5, // 每日积分上限 } ]
PointsRecordController.java
@ApiOperation("查询今日积分")@GetMapping("today")publicList<PointsStatisticsVO>getPointsRecord(){returnpointsRecordService.queryMyPointsToday();}
IPointsRecordService.java
List<PointsStatisticsVO>queryMyPointsToday();
PointsRecordServiceImpl.java
@OverridepublicList<PointsStatisticsVO>queryMyPointsToday(){// 1.获取用户idLonguserId=UserContext.getUser();// 2.获取当天得时间范围LocalDateTimenow=LocalDateTime.now();LocalDateTimedayStartTime=DateUtils.getDayStartTime(now);LocalDateTimedayEndTime=DateUtils.getDayEndTime(now);// 3.借助类型去分组判断每个类型今日获取得积分(在语句当中将积分和映射为userId从而便于映射实体)QueryWrapper<PointsRecord>wrapper=newQueryWrapper<>();wrapper.select("type","sum(points) as userId");wrapper.eq("user_id",userId);wrapper.between("create_time",dayStartTime,dayEndTime);wrapper.groupBy("type");List<PointsRecord>list=this.list(wrapper);if(CollUtils.isEmpty(list)){returnCollUtils.emptyList();}//封装vo返回List<PointsStatisticsVO>voList=newArrayList<>();for(PointsRecordrecord:list){PointsStatisticsVOvo=newPointsStatisticsVO();//积分类型vo.setType(record.getType().getDesc());//积分类型得分数上限vo.setMaxPoints(record.getType().getMaxPoints());// if(record.getType().getMaxPoints()==0){// vo.setMaxPoints(41);// }//今日已获得积分vo.setPoints(record.getUserId().intValue());voList.add(vo);}returnvoList;}

查询赛季列表功能

参数说明
请求方式GET
请求路径/boards/seasons/list
请求参数
返回值[ { "id": "110", // 赛季id "name": "第一赛季", // 赛季名称 "beginTime": "2023-05-01", // 赛季开始时间 "endTime": "2023-05-31", // 赛季结束时间 } ]
PointsBoardSeasonController.java
@ApiOperation("查询赛季列表")@GetMapping("list")publicList<PointsBoardSeason>queryPointBoardSeasonList(){returnpointsBoardSeasonService.list();//要返回的结果字段与po字段一样 所以可以直接调用mp中的list方法}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/8 0:56:01

Windows Server 2016 中文版、英文版下载 (2025 年 12 月更新)

Windows Server 2016 中文版、英文版下载 (2025 年 12 月更新) Windows Server 2016 x64 Version 1607 (updated Dec 2025) 请访问原文链接&#xff1a;https://sysin.org/blog/windows-server-2016/ 查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a…

作者头像 李华
网站建设 2026/2/7 5:52:00

pycharm下新建一个项目并加入svn

因为要计划要经常新建工程&#xff0c;不再是都放在一个工程里面搞应用实现&#xff0c;另外还要加入svn版本库管理&#xff0c;所以稍微整理了一下新建的过程&#xff0c;供参考。 1、python版本 C:\Users\yegang>python -V Python 3.11.02、安装django并升级pip C:\Users\…

作者头像 李华
网站建设 2026/2/8 1:38:42

用于电力系统瞬态稳定性评估的机器学习。 从数据挖掘和机器学习的角度来解决电力系统的稳定性

用于电力系统瞬态稳定性评估的机器学习。 从数据挖掘和机器学习的角度来解决电力系统的稳定性&#xff0c;该模型由去噪堆叠自编码器和投票集成分类器构建。 集成由来自支持向量机和随机森林的池化预测组成。 报告并讨论了分类器在电力系统测试用例中的应用结果。 TSA问题的ML应…

作者头像 李华
网站建设 2026/2/8 6:59:34

三小时前刚调通的新鲜案例还在冒热气。ZYNQ这玩意儿玩TCP传输,核心就三件事:怎么把PL数据塞进DDR、怎么让LWIP别偷懒、怎么让DMA别堵车。直接上干货

ZYNQ平台基于LwIP实现TCP数据通信&#xff0c;PL端产生数据传递到PS端的DDR3&#xff0c;再利用LwIP通过TCP传输到PC端。 实测数据吞吐量能到达到500Mbps左右&#xff0c;最高能到700M 长达一小时的视频&#xff0c;从硬件设计的注意事项&#xff0c;到软件设计的思路都包含了。…

作者头像 李华
网站建设 2026/2/5 18:47:20

Mcdowell-CV:专业级LaTeX简历模板终极指南

Mcdowell-CV&#xff1a;专业级LaTeX简历模板终极指南 【免费下载链接】mcdowell-cv A Nice-looking CV template made into LaTeX 项目地址: https://gitcode.com/gh_mirrors/mc/mcdowell-cv 在当今竞争激烈的求职市场中&#xff0c;一份专业、整洁的简历是脱颖而出的关…

作者头像 李华
网站建设 2026/2/6 18:23:19

Flutter app_settings 库在鸿蒙(OHOS)平台的适配实践与解析

Flutter app_settings 库在鸿蒙&#xff08;OHOS&#xff09;平台的适配实践与解析 引言 OpenHarmony&#xff08;OHOS&#xff09;生态正在快速成长&#xff0c;影响力逐步扩大&#xff0c;将成熟的跨平台框架与它对接&#xff0c;成了拓展应用覆盖面的重要手段。Flutter 以其…

作者头像 李华