> 技术文档 > 微服务的编程测评系统19-我的消息功能-竞赛排名功能

微服务的编程测评系统19-我的消息功能-竞赛排名功能


提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 1. 我的消息功能
    • 1.1 业务分析
    • 1.2 消息发送
    • 1.3 消息列表展示
    • 1.4 前端开发
  • 2. 竞赛排名功能
  • 总结8

前言

1. 我的消息功能

1.1 业务分析

微服务的编程测评系统19-我的消息功能-竞赛排名功能
这个是站内通信

我的消息功能

站内信:网站内部的一种通信方式。
1.用户和用户之间的通信。(点对点)
2.管理员/系统 和 某个用户之间的通信。(点对点) ===》竞赛结果的通信消息
3. 管理员/系统 和 某个用户群(指的是满足某一条件的用户的群体)之间的通信。(点对面)

而且每个用户的消息都不一样
这个是给用户群发消息,福利信息每个用户的消息都一样—》点对面
因为每个用户消息不一样—》点对点

消息的话我们还要设计数据库

因为如果是消息群的话,那么就会把相同的消息发给多个人,所以我们可以设计两个表,一个消息内容表,一个是消息和用户的对应表,这样就不会相同消息发给多个人了

消息内容表create table tb_message_text(text_id bigint unsigned NOT NULL COMMENT \'消息内容id(主键)\',message_title varchar(10) NOT NULL COMMENT \'消息标题\',message_content varchar(200) NOT NULL COMMENT \'消息内容\',create_by bigint unsigned not null comment \'创建人\',create_time datetime not null comment \'创建时间\',update_by bigint unsigned comment \'更新人\',update_time datetime comment \'更新时间\',primary key (text_id))
# 消息表create table tb_message(message_id bigint unsigned NOT NULL COMMENT \'消息id(主键)\',text_id bigint unsigned NOT NULL COMMENT \'消息内容id(主键)\',send_id bigint unsigned NOT NULL COMMENT \'消息发送人id\',rec_id bigint unsigned NOT NULL COMMENT \'消息接收人id\',create_by bigint unsigned not null comment \'创建人\',create_time datetime not null comment \'创建时间\',update_by bigint unsigned comment \'更新人\',update_time datetime comment \'更新时间\',primary key (message_id));

消息如何产生—》竞赛结果通知消息–》凌晨统计排名,对当天结束的竞赛进行排名的统计—》产生消息—》竞赛结束时间不能超过晚上十点—>把消息存在数据库中,然后查询就可以了
然后消息也要存在redis中,不然还是太慢了
微服务的编程测评系统19-我的消息功能-竞赛排名功能
一个是user:message:list:userId,存储list,每个元素是消息id
还有一个是message:detail:textId,存储的是JSON,消息详情

1.2 消息发送

通过定时任务生成消息–.>存储到数据库和缓存中,获取消息列表的时候就可以从缓存中获取了,注意生成消息的时候只存在缓存中
缓存没有修改和删除

@Datapublic class UserScore { private Long examId; private Long userId; private Integer score;}

这个是新增加的类

<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"><mapper namespace=\"com.ck.job.mapper.user.UserSubmitMapper\"> <select id=\"selectUserScoreList\" resultType=\"com.ck.job.domain.user.UserScore\"> SELECT user_id, exam_id, sum(score) as score FROM tb_user_submit <where> <foreach collection=\"examIdSet\" open=\"exam_id in (\" close=\")\" item=\"examId\" separator=\",\" >  #{examId} </foreach> </where> GROUP BY user_id , exam_id ORDER BY score DESC </select></mapper>

这个是使用的xml

@Servicepublic class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMessageService{ @Override public boolean batchInsert(List<Message> messageList){ return saveBatch(messageList); }}
@Servicepublic class MessageTextServiceImpl extends ServiceImpl<MessageTextMapper, MessageText> implements IMessageTextService { @Override public boolean batchInsert(List<MessageText> messageTextList){ return saveBatch(messageTextList); }}

这个是批量插入的service方法

 public static final Long SYSTEM_USER_ID = 1L;

因为createBy无法获取用户Id,所以我们提前要设置好

 public static final String USER_MESSAGE_LIST_USERID = \"user:message:list:\"; public static final String MESSAGE_DETAIL_MESSAGEID = \"message:detail:\";

这个是存入缓存的结构

@Datapublic class MessageCacheVO { private String messageTitle; private String messageContent;}

这个是存入信息详细数据的类

最后展示定时器的代码

 @XxlJob(\"examResultHandler\") public void examResultHandler(){ log.info(\"*****examResultHandler:凌晨统计排名*****\"); //先从数据库中获取所有已经结束的竞赛列表 LocalDateTime now = LocalDateTime.now(); LocalDateTime minusDays = now.minusDays(1);//获取小于一天的时间 List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>() .select(Exam::getExamId,Exam::getTitle) .ge(Exam::getEndTime, minusDays) .le(Exam::getEndTime, now)//小于等于当前时间 .eq(Exam::getStatus, Constants.TRUE));//已经发布) if(CollectionUtil.isEmpty(examList)){ return; } Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet()); //然后根据examIdSet获取所有用户的分数 List<UserScore> userScoreList = userSubmitMapper.selectUserScoreList(examIdSet); Map<Long, List<UserScore>> examIdUserScoreMap = userScoreList.stream().collect(Collectors.groupingBy(UserScore::getExamId)); //按照examId分组,那么分数排名就已经OK了 saveMessage(examList,examIdUserScoreMap); } private void saveMessage(List<Exam> examList, Map<Long, List<UserScore>> examIdUserScoreMap ) { List<Message> messageList = new ArrayList<>();//插入msg与用户对应信息数据库 List<MessageText> messageTextList = new ArrayList<>();//插入数据库,msg详细信息 for(Exam exam: examList){ Long examId = exam.getExamId(); List<UserScore> userScoreList = examIdUserScoreMap.get(examId); int userTotal = userScoreList.size(); int rank = 1; for (UserScore userScore : userScoreList){ String msgTitle = exam.getTitle()+\"——排名情况\"; String msgContent = \"你参加的竞赛:\"+ exam.getTitle()+\",你的分数为:\" +userScore.getScore()+\",总人数:+\"+userTotal +\",你的排名为:\"+rank; rank++; MessageText messageText = new MessageText(); messageText.setMessageTitle(msgTitle); messageText.setMessageContent(msgContent); messageText.setCreateBy(Constants.SYSTEM_USER_ID); messageTextList.add(messageText); Message message = new Message(); message.setSendId(Constants.SYSTEM_USER_ID); message.setRecId(userScore.getUserId()); message.setCreateBy(Constants.SYSTEM_USER_ID); messageList.add(message); } } messageTextService.batchInsert(messageTextList); //给messageList添加messageId Map<String, MessageCacheVO> messageCacheVOMap = new HashMap<>();//存入redis,信息详细数据 for(int i=0;i<messageTextList.size();i++){ MessageText messageText = messageTextList.get(i); Message message = messageList.get(i); message.setTextId(messageText.getTextId()); MessageCacheVO messageCacheVO = new MessageCacheVO(); messageCacheVO.setMessageContent(messageText.getMessageContent()); messageCacheVO.setMessageTitle(messageText.getMessageTitle()); String messageDetailKey = getMessageDetailKey(messageText.getTextId()); messageCacheVOMap.put(messageDetailKey,messageCacheVO); } redisService.multiSet(messageCacheVOMap); messageService.batchInsert(messageList); //存入缓存,用户的信息列表---》那么就要把信息按照userId进行分组了 Map<Long, List<Message>> userMsgMap = messageList.stream().collect(Collectors.groupingBy(Message::getRecId)); Iterator<Map.Entry<Long, List<Message>>> iterator = userMsgMap.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry<Long, List<Message>> entry = iterator.next(); Long userId = entry.getKey(); String userMessageListKey = getUserMessageListKey(userId); List<Message> userMessageList = entry.getValue(); List<Long> userMsgIdList = userMessageList.stream().map(Message::getTextId).toList(); redisService.rightPushAll(userMessageListKey,userMsgIdList); }// for (Map.Entry<Long, List> entry : userMsgMap.entrySet()) {// Long userId = entry.getKey();// String userMessageListKey = getUserMessageListKey(userId);// List userMessageList = entry.getValue();// List userMsgIdList = userMessageList.stream().map(Message::getTextId).toList();// redisService.rightPushAll(userMessageListKey, userMsgIdList);// } } private String getUserMessageListKey(Long userId) { return CacheConstants.USER_MESSAGE_LIST_USERID + userId; } private String getMessageDetailKey(Long messageTextId) { return CacheConstants.MESSAGE_DETAIL_MESSAGEID + messageTextId; }

我们使用的都是批量插入
在 Java 中,Iterator(迭代器)初始化后,其初始状态是指向集合中第一个元素的「前面」

1.3 消息列表展示

创建一个新的controller,UserMessageController

@RestController@RequestMapping(\"/user/message\")@Tag(name = \"C端用户信息接口\")@Slf4jpublic class UserMessageController { @Autowired private IUserMessageService userMessageService; @GetMapping(\"/list\") @Operation(description = \"获取用户接收到的信息\") public TableDataInfo list(PageQueryDTO dto){ log.info(\"获取用户接收到的信息,PageQueryDTO:{}\", dto); return userMessageService.list(dto); }}

直接拷贝以前获取竞赛列表的代码,然后改吧改吧

@Datapublic class MessageCacheVO { private Long textId; private String messageTitle; private String messageContent;}

这个类要完善一下,因为从数据库中可以查询出这个类,然后刷新缓存就要用到messageTextId,记得定时器存入缓存的时候,这个字段也要完善

<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"><mapper namespace=\"com.ck.friend.mapper.message.MessageTextMapper\"> <select id=\"selectUserMsgList\" resultType=\"com.ck.friend.domain.message.vo.MessageCacheVO\"> SELECT text_id, message_title, message_content, FROM tb_message m JOIN tb_message_text tm ON m.text_id = tm.text_id <where> m.rec_id = #{userId} </where> ORDER BY t.create_time DESC </select></mapper>

这个是根据userId查询它的所有的信息的xml

 @Override public TableDataInfo list(PageQueryDTO dto) { Long userId= ThreadLocalUtil.get(Constants.USER_ID,Long.class); Long listSize = userMessageCacheManager.getListSize(userId); List<MessageCacheVO> list ; if(listSize==null||listSize==0){ //说明缓存中没有数据,所以要先从数据库中获取数据,然后存入redis PageHelper.startPage(dto.getPageNum(), dto.getPageSize()); list = messageTextMapper.selectUserMsgList(userId); userMessageCacheManager.refreshCache(userId); long total = new PageInfo<>(list).getTotal(); return TableDataInfo.success(list, total); }else{ //直接从redis中获取数据 list = userMessageCacheManager.getUserMsgList(dto,userId); listSize = userMessageCacheManager.getListSize(userId); return TableDataInfo.success(list, listSize); } }

这是service代码
然后是userMessageCacheManager的代码

@Componentpublic class UserMessageCacheManager { @Autowired private RedisService redisService; @Autowired private MessageTextMapper messageTextMapper; public Long getListSize(Long userId) { String userMessageListKey = getUserMessageListKey(userId); return redisService.getListSize(userMessageListKey); } public void refreshCache(Long userId) { List<MessageCacheVO> messageCacheVOList = new ArrayList<>(); messageCacheVOList = messageTextMapper.selectUserMsgList(userId);//没有分页 List<Long> userMsgIdList = messageCacheVOList.stream().map(MessageCacheVO::getTextId).toList(); if (CollectionUtil.isEmpty(messageCacheVOList)) { return; } redisService.rightPushAll(getUserMessageListKey(userId), userMsgIdList); //刷新列表缓存 //刷新信息详情缓存 Map<String, MessageCacheVO> messageCacheVOMap = new HashMap<>(); for (MessageCacheVO messageCacheVO : messageCacheVOList) { messageCacheVOMap.put(getMessageDetailKey(messageCacheVO.getTextId()),messageCacheVO); } redisService.multiSet(messageCacheVOMap); //刷新详情缓存 } public List<MessageCacheVO> getUserMsgList(PageQueryDTO dto, Long userId) { int start = (dto.getPageNum() - 1) * dto.getPageSize(); int end = start + dto.getPageSize() - 1; //下标需要 -1 String userMessageListKey = getUserMessageListKey(userId); List<Long> messageIdList = redisService.getCacheListByRange(userMessageListKey, start, end, Long.class); List<MessageCacheVO> messageCacheVOList = assembleExamVOList(messageIdList);//从缓存中加载详情 if (CollectionUtil.isEmpty(messageCacheVOList)) { //说明redis中数据可能有问题 从数据库中查数据并且重新刷新缓存 messageCacheVOList = getMessageVOListByDB(dto,userId); //从数据库中获取数据 refreshCache(userId); } return messageCacheVOList; } private List<MessageCacheVO> getMessageVOListByDB(PageQueryDTO dto, Long userId) { PageHelper.startPage(dto.getPageNum(), dto.getPageSize()); return messageTextMapper.selectUserMsgList(userId); } private List<MessageCacheVO> assembleExamVOList(List<Long> messageIdList) { if (CollectionUtil.isEmpty(messageIdList)) { //说明redis当中没数据 从数据库中查数据并且重新刷新缓存 return null; } //拼接redis当中key的方法 并且将拼接好的key存储到一个list中 List<String> detailKeyList = new ArrayList<>(); for (Long messageTextId : messageIdList) { detailKeyList.add(getMessageDetailKey(messageTextId)); } List<MessageCacheVO> messageCacheVOList = redisService.multiGet(detailKeyList, MessageCacheVO.class); CollUtil.removeNull(messageCacheVOList); if (CollectionUtil.isEmpty(messageCacheVOList) || messageCacheVOList.size() != messageIdList.size()) { //说明redis中数据有问题 从数据库中查数据并且重新刷新缓存 return null; } return messageCacheVOList; } private String getUserMessageListKey(Long userId) { return CacheConstants.USER_MESSAGE_LIST_USERID + userId; } private String getMessageDetailKey(Long messageTextId) { return CacheConstants.MESSAGE_DETAIL_MESSAGEID + messageTextId; }}

1.4 前端开发

创建文件UserMessage.vue

<template> <div class=\"message-list\"> <div class=\"message-list-block\"> <div class=\"message-list-header\"> <span class=\"ms-title\">我的消息</span> <span class=\"message-list-back\" @click=\"goBack()\">返回</span> </div> <div class=\"mesage-list-content\" v-for=\"(item, index) in messageList\" :key=\"index\"> <img src=\"@/assets/message/notice.png\" width=\"50px\" class=\"image\" /> <div class=\"message-content\">  <div class=\"title-box\"> <div class=\"title\"> {{ item.messageTitle }} </div>  </div>  <div class=\"content\">{{ item.messageContent }}</div> </div> <el-button class=\"mesage-button\" type=\"text\" @click.stop=\"handlerDelete(item)\">删除</el-button> </div> <div class=\"message-pagination\"> <!-- 增加分页展示器 --> <el-pagination background layout=\"total, sizes, prev, pager, next, jumper\" :total=\"total\"  v-model:current-page=\"params.pageNum\" v-model:page-size=\"params.pageSize\"  :page-sizes=\"[5, 10, 15, 20]\" @size-change=\"handleSizeChange\"  @current-change=\"handleCurrentChange\" /> </div> </div> </div></template><script setup>import { getMessageListService } from \"@/apis/message\"import router from \"@/router\"import { reactive, ref } from \"vue\"const messageList = ref([]) //消息列表const total = ref(0)const params = reactive({ pageNum: 1, pageSize: 10,})//消息列表async function getMessageList() { const ref = await getMessageListService(params) messageList.value = ref.rows total.value = ref.total}getMessageList()const goBack = () => { router.go(-1)}// 分页function handleSizeChange(newSize) { params.pageNum = 1 getMessageList()}function handleCurrentChange(newPage) { getMessageList()}</script>
import service from \"@/utils/request\";export function getMessageListService(params) { return service({ url: \"/user/message/list\", method: \"get\", params, });}

然后就可以测试了
微服务的编程测评系统19-我的消息功能-竞赛排名功能
我们创建三个用户来测试一下

微服务的编程测评系统19-我的消息功能-竞赛排名功能

 <select id=\"selectUserMsgList\" resultType=\"com.ck.friend.domain.message.vo.MessageCacheVO\"> SELECT tm.text_id, tm.message_title, tm.message_content FROM tb_message m JOIN tb_message_text tm ON m.text_id = tm.text_id WHERE m.rec_id = #{userId} ORDER BY m.create_time DESC </select>

然后发现xml文件有问题

修改一下

微服务的编程测评系统19-我的消息功能-竞赛排名功能
成功了

2. 竞赛排名功能

微服务的编程测评系统19-我的消息功能-竞赛排名功能
就是历史竞赛那里的排名功能
未完赛没有查看排名功能
微服务的编程测评系统19-我的消息功能-竞赛排名功能

排名和得分和用户id都有了

但是得分和排名还没有存储—》tb_user_exam有排名的得分字段
----》不用重新统计了–》直接获取—》存入数据库,在定时器的时候

然后还要存入缓存–》key为exam:rank:list:examId
value为userId?不是,第一我们是为了防止一个数据存储多份,所以才存id,但是这里的排名是不会存储多份的,因为不同竞赛的排名和分数是不一样的,而且排名和分数是不能修改的
所以value就是需要什么存什么–》json–>examRank,nickName,score,其中examRank和score在不同竞赛中一般是不同的
但是nickName是会重复的,而且用户修改nickname还要改redis—》所以可以存userId,然后由userId获取redis中的nickname

我们现在定时器那里,修改tb_user_exam表,完善score和exam_rank字段
然后往redis中存入排名数据

@Datapublic class UserScore { private Long examId; private Long userId; private Integer score; private Integer examRank;}

完善一下这个类,这个是可以直接存入数据库中,什么都有了

<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\"><mapper namespace=\"com.ck.job.mapper.user.UserExamMapper\"> <update id=\"updateScoreAndExamRank\"> <foreach collection=\"userScoreList\" item=\"item\" separator=\";\"> UPDATE tb_user_exam SET score = #{item.score}, exam_rank = #{item.examRank} WHERE exam_id = #{item.examId} AND user_id = #{item.userId} </foreach> </update></mapper>

这个是修改数据库tb_user_exam的xml语句

 public static final String EXAM_RANK_LIST_EXAMID = \"exam:rank:list:\";
 private String getExamRankListKey(Long examId) { return CacheConstants.EXAM_RANK_LIST_EXAMID + examId; }

这个是redis的key
在savemessage方法中

 for(Exam exam: examList){ Long examId = exam.getExamId(); List<UserScore> userScoreList = examIdUserScoreMap.get(examId); int userTotal = userScoreList.size(); int rank = 1; for (UserScore userScore : userScoreList){ String msgTitle = exam.getTitle()+\"——排名情况\"; String msgContent = \"你参加的竞赛:\"+ exam.getTitle()+\",你的分数为:\" +userScore.getScore()+\",总人数:\"+userTotal +\",你的排名为:\"+rank; userScore.setExamRank(rank); rank++; MessageText messageText = new MessageText(); messageText.setMessageTitle(msgTitle); messageText.setMessageContent(msgContent); messageText.setCreateBy(Constants.SYSTEM_USER_ID); messageTextList.add(messageText); Message message = new Message(); message.setSendId(Constants.SYSTEM_USER_ID); message.setRecId(userScore.getUserId()); message.setCreateBy(Constants.SYSTEM_USER_ID); messageList.add(message); } userExamMapper.updateScoreAndExamRank(userScoreList); redisService.rightPushAll(getExamRankListKey(examId),userScoreList); }

然后是创建查询的controller

 @GetMapping(\"/rank/list\") public TableDataInfo rankList(RankQueryDTO rankQueryDTO){ log.info(\"获取竞赛排名列表信息,rankQueryDTO:{}\", rankQueryDTO); return examService.rankList(rankQueryDTO); }
@Datapublic class RankQueryDTO extends PageQueryDTO { private Long examId;}

然后service

@Datapublic class ExamRankCacheVO { private String nickName; private Long userId; private Integer score; private Integer examRank;}

这个类是从缓存中要获取的数据,其中只用获取后面三个字段,第一个字段是再次获取的,再次从redis中获取

 <select id=\"selectExamRankCacheVOList\" resultType=\"com.ck.friend.domain.exam.vo.ExamRankCacheVO\"> SELECT user_id, score, exam_rank FROM tb_user_exam WHERE exam_id = #{examId} ORDER BY exam_rank </select>

这个是从数据库中获取排名信息的xml语句,根据examId

 @Override public TableDataInfo rankList(RankQueryDTO rankQueryDTO) { Long listSize = examCacheManager.getExamRankListSize(rankQueryDTO.getExamId()); List<ExamRankCacheVO> list; if(listSize==null||listSize==0){ //说明缓存中没有数据,所以要先从数据库中获取数据,然后存入redis PageHelper.startPage(rankQueryDTO.getPageNum(), rankQueryDTO.getPageSize()); list = examMapper.selectExamRankCacheVOList(rankQueryDTO.getExamId()); examCacheManager.refreshExamRankListCache(rankQueryDTO.getExamId()); listSize = new PageInfo<>(list).getTotal(); }else{ //直接从redis中获取数据 list = examCacheManager.getExamRankList(rankQueryDTO); } assembleExamRankList(list); return TableDataInfo.success(list, listSize); } private void assembleExamRankList(List<ExamRankCacheVO> list) { if(CollectionUtil.isEmpty(list)){ return; } for (ExamRankCacheVO examRankCacheVO : list) { UserVO user = userCacheManager.getUserById(examRankCacheVO.getUserId()); examRankCacheVO.setNickName(user.getNickName()); } }

然后是examCacheManager中的方法

 //竞赛排名 public Long getExamRankListSize(Long examId) { return redisService.getListSize(getExamRankListKey(examId)); } private String getExamRankListKey(Long examId) { return CacheConstants.EXAM_RANK_LIST_EXAMID + examId; } public void refreshExamRankListCache(Long examId) { //没有分页查询 List<ExamRankCacheVO> examRankCacheVOList = examMapper.selectExamRankCacheVOList(examId); redisService.rightPushAll(getExamRankListKey(examId),examRankCacheVOList); } public List<ExamRankCacheVO> getExamRankList(RankQueryDTO rankQueryDTO) { int start = (rankQueryDTO.getPageNum() - 1) * rankQueryDTO.getPageSize(); int end = start + rankQueryDTO.getPageSize() - 1; //下标需要 -1 return redisService.getCacheListByRange(getExamRankListKey(rankQueryDTO.getExamId()),start,end,ExamRankCacheVO.class); }

这样就OK了

然后拷贝前端代码到exam.vue

 <el-dialog v-model=\"dialogVisible\" width=\"600px\" top=\"30vh\" :show-close=\"true\" :close-on-click-modal=\"false\" :close-on-press-escape=\"false\" class=\"oj-login-dialog-centor\" center> <el-table :data=\"examRankList\"> <el-table-column label=\"排名\" prop=\"examRank\" /> <el-table-column label=\"用户昵称\" prop=\"nickName\" /> <el-table-column label=\"用户得分\" prop=\"score\" /> </el-table> <el-pagination class=\"range_page\" background layout=\"total, sizes, prev, pager, next, jumper\" :total=\"rankTotal\" v-model:current-page=\"rankParams.pageNum\" v-model:page-size=\"rankParams.pageSize\" :page-sizes=\"[5, 10, 15, 20]\" @size-change=\"handleRankSizeChange\" @current-change=\"handleRankCurrentChange\" /> </el-dialog>
//竞赛排名const rankParams = reactive({ examId:\'\', pageNum: 1, pageSize: 9,})const examRankList = ref([])const rankTotal = ref(0)// 分页function handleRankSizeChange(newSize) { rankParams.pageNum = 1 getExamRankList()}function handleRankCurrentChange(newPage) { getExamRankList()}const dialogVisible = ref(false)async function getExamRankList() { const result = await getExamRankListService(rankParams) examRankList.value = result.rows rankTotal.value = result.total}function togglePopover(examId) { dialogVisible.value = true rankParams.examId = examId getExamRankList()}
export function getExamRankListService(params) { return service({ url: \"/exam/rank/list\", method: \"get\", params, });}

然后就可以进行测试了
但是有一个要注意的点就是
我们的sql是不支持批量update的
要加上allowMultiQueries=true才可以
微服务的编程测评系统19-我的消息功能-竞赛排名功能

微服务的编程测评系统19-我的消息功能-竞赛排名功能

这样就成功了

总结8