您的位置:首页 > 汽车 > 新车 > 利用redis Zset实现 排行榜功能 配合xxl-job持久化每一个赛季的排行榜

利用redis Zset实现 排行榜功能 配合xxl-job持久化每一个赛季的排行榜

2024/10/18 15:48:50 来源:https://blog.csdn.net/qq_62383709/article/details/140247051  浏览:    关键词:利用redis Zset实现 排行榜功能 配合xxl-job持久化每一个赛季的排行榜
zset 可以排序 使用xxl-job实现定时任务 对历史排行榜持久化到数据库
排行榜有当前赛季排行版和历史排行榜

当前赛季排行榜利用redis 中的SortSet 数据结构 获取
每个月的 月初 利用xxl-job的定时任务持久化化上一个月的排行榜信息 并删除redis中的数据
当排行榜数据量巨大时可以 通过对每一个赛季的历史排行榜水平分表 减小单表的数据量和压力
查询历史排行榜 通过持久化的表查询

代码
cotroller
package com.orchids.ranklist.web.controller;import com.orchids.ranklist.web.domain.query.BoardQuery;
import com.orchids.ranklist.web.domain.vo.PointsBoardVO;
import com.orchids.ranklist.web.service.IPointsBoardService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @ Author qwh* @ Date 2024/7/6 14:56*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/rank")
@Api(tags = "积分积分排行榜")
public class PointBoardController {private final IPointsBoardService pointsBoardService;/*** 查询指定赛季的排行榜* @param query* @return*/@GetMapping("boards")@ApiOperation("分页查询指定赛季的排行榜")public PointsBoardVO queryPointsBoardBySeasonId(BoardQuery query){return pointsBoardService.queryPointsBoardBySeasonId(query);}
}
service

Iservice

package com.orchids.ranklist.web.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.orchids.ranklist.web.domain.po.PointsBoard;
import com.orchids.ranklist.web.domain.query.BoardQuery;
import com.orchids.ranklist.web.domain.vo.PointsBoardVO;import java.util.List;/*** @ Author qwh* @ Date 2024/7/6 18:55*/public interface IPointsBoardService extends IService<PointsBoard> {PointsBoardVO queryPointsBoardBySeasonId(BoardQuery query);/*** 持久化上个月的排行榜信息之前需要创建的表* @param season*/void createPointsBoardTableBySeason(Integer season);
}

servieImpl

package com.orchids.ranklist.web.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.orchids.ranklist.web.domain.po.PointsBoard;
import com.orchids.ranklist.web.domain.query.BoardQuery;
import com.orchids.ranklist.web.domain.vo.PointsBoardVO;
import com.orchids.ranklist.web.mapper.PointsBoardMapper;
import com.orchids.ranklist.web.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orchids.ranklist.web.utils.TableNameContext;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;/*** @author nullpointer* @since 2024-07-06*/
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {private final PointsBoardMapper pointsBoardMapper;private final StringRedisTemplate redisTemplate;//          排行榜//  位次      id          score//  3        myID             myScore//  1        otherID          otherScore//  2        otherID          otherScore//  3        myID             myScore@Overridepublic PointsBoardVO queryPointsBoardBySeasonId(BoardQuery query) {Long seasonId = query.getSeasonId();//判断是否是当前赛季 seasonId 为 null || 0 就是当前赛季boolean isCurrent = seasonId == null || seasonId == 0;//是当前赛季从redis 获取每一个人的积分 积分由zset封装     userId1   score1//拼接整个榜单的 key  point:rank:board:2024:07      userId2   score2 ...LocalDate localDate = LocalDate.now();String format = localDate.format(DateTimeFormatter.ofPattern("yyyy:MM"));String key = "point:rank:board:" + format;//查询我的积分和排名PointsBoard pointsBoard = isCurrent ?//当前赛季查询redisqueryMyCurrentBoard(key)://历史赛季查数据库 因为每个月初会定时把上个月的排行信息从redis中持久化到数据库中每个月的排行表中queryMyCountHistoryBoard(seasonId);//查询整个积分排行榜信息List<PointsBoard> pointsBoards = isCurrent ?queryCurrentBoardList(key,query.getPageNo(),query.getPageSize()) :queryCountHistoryBoardList(query);//封装排行榜信息PointsBoardVO result = new PointsBoardVO();if (pointsBoard!=null){result.setRank(pointsBoard.getRank());result.setPoints(pointsBoard.getPoints());}if (CollectionUtils.isEmpty(pointsBoards)){return result;}//获取其他人的ID 榜单可以添加用户名信息 通过ID查询 例如// todo List<Long> UserIds = pointsBoards.stream().map(PointsBoard::getUserId).collect(Collectors.toList());//封装排行列表result.setBoardList(pointsBoards);return result;}/*** 查询当前赛季积分排行榜* @param key* @return*/private PointsBoard queryMyCurrentBoard(String key) {//当月排行信息从redis查//获取redis操作对象BoundZSetOperations<String, String> ops = redisTemplate.boundZSetOps(key);//获取当前用户的 积分排行信息//获取当前用户的UserId 可以从请求头或者token中获取 假设为Long userId = 13666666L;Double score = ops.score(userId.toString());//获取我的排行信息Long rank = ops.reverseRank(userId.toString());//封装我的排行版信息PointsBoard board = new PointsBoard();board.setRank(rank.intValue()+1);board.setUserId(userId);board.setPoints(score.intValue());//返回PointBoardreturn board;}/*** 查询我的历史赛季积分排行信息* @param seasonId* @return*/private PointsBoard queryMyCountHistoryBoard(Long seasonId) {//todo 从数据库中查询历史排行表中的排行信息//获取Id//获取当前用户的UserId 可以从请求头或者token中获取 假设为Long userId = 13666666L;//拼接表名TableNameContext.setInfo("points_board_"+seasonId);//因为mybatis动态表名插件在执行查询和修改操作会 从TableNameContext中获取表名PointsBoard board = lambdaQuery().eq(PointsBoard::getUserId, userId).one();board.setRank(board.getId().intValue());TableNameContext.remove();return board;}/*** 查询当前赛季积分排行榜* @param key* @return*/private List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {//计算分页信息int from = (pageNo - 1) * pageSize;int end = from + pageSize + 1;//从redis中查询Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, from, end);//判断是否为空if (CollectionUtils.isEmpty(tuples)) {return new ArrayList<>();}//封装排行榜信息int rank = from + 1;List<PointsBoard> result = new LinkedList<>();for (ZSetOperations.TypedTuple<String> tuple : tuples) {String userId = tuple.getValue(); //用户IdDouble score = tuple.getScore();  //用户积分if (userId==null||score==null){continue;}PointsBoard board = new PointsBoard();board.setRank(rank++);board.setUserId(Long.valueOf(userId));board.setPoints(score.intValue());result.add(board);}return result;}/*** 查询历史赛季积分排行榜* @param query* @return*/private List<PointsBoard> queryCountHistoryBoardList(BoardQuery query) {//todo 后序查询数据库//获取赛季IdLong seasonId = query.getSeasonId();//拼接查询的表TableNameContext.setInfo("points_board_"+seasonId);Page<PointsBoard> ipage = new Page<>(query.getPageNo(), query.getPageSize());Page<PointsBoard> page = pointsBoardMapper.selectPage(ipage, null);List<PointsBoard> boardList = page.getRecords();//这里可以 获取用户ID 查询用户信息 修改显示内容TableNameContext.remove();return boardList;}@Overridepublic void createPointsBoardTableBySeason(Integer season) {// 第七赛季的排行榜 表实例 points_board_7pointsBoardMapper.createPointsBoardTable("points_board_" + season);}
}
定时任务类
package com.orchids.ranklist.web.handler;/*** @ Author qwh* @ Date 2024/7/6 20:41*/
import com.orchids.ranklist.web.domain.po.PointsBoard;
import com.orchids.ranklist.web.service.IPointsBoardSeasonService;
import com.orchids.ranklist.web.service.IPointsBoardService;
import com.orchids.ranklist.web.utils.TableNameContext;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;//定时任务 每月初定时创建榜单表 将redis中的数据持久化到数据库
@Slf4j
@Component
@RequiredArgsConstructor
public class PointsBoardPersistentHandler {//查询赛季信息private final IPointsBoardSeasonService seasonService;//创建赛季表private final IPointsBoardService pointsBoardService;//删除redis中的上个月榜单private final StringRedisTemplate redisTemplate;@XxlJob("xxl_job_time_test")public void createLocalTime(){log.debug("xl_job_demo执行器正在执行现在时间是{}",LocalDateTime.now());System.out.println("xl_job_demo执行器正在执行现在时间是"+LocalDateTime.now());}// 每月1号,凌晨3点执行//todo 添加定时或者 XXL_JOB@XxlJob("xxl_job_points_board_create_table")public void createPointBoardTableOfSeason(){//上个月的凌晨三点LocalDateTime time = LocalDateTime.now().minusMonths(1);//查询赛季表获取赛季IdInteger season = seasonService.querySeasonByTime(time);if (season == null){return;}//将表名保存到ThreadLocalTableNameContext.setInfo("points_board_" + season);//创建对应的表pointsBoardService.createPointsBoardTableBySeason(season);}/*** 持久化排行榜到数据库*///todo 添加定时或者 XXL_JOB@XxlJob("xxl_job_points_board_save_mysql")private void savePointsBoardToDb() {//拼接redis keyLocalDateTime time = LocalDateTime.now().minusMonths(1);//计算动态表名Integer season = seasonService.querySeasonByTime(time);TableNameContext.setInfo("points_board_"+season);//拼接keyLocalDateTime now = LocalDateTime.now();String format = now.format(DateTimeFormatter.ofPattern("yyyy:MM"));// point:rank:board:2024:06String key = "point:rank:board:" + format;//获取redis中的数据// todo 可以利用分片xxl_jobint pageNo =1;int pageSize = 1000;System.out.println(key);while (true){List<PointsBoard> pointsBoards = queryCurrentBoardList(key, pageNo, pageSize);if (CollectionUtils.isEmpty(pointsBoards)){//当没有数据了跳过循环break;}//持久化到数据库pointsBoardService.saveBatch(pointsBoards);System.out.println("持久化成功");pageNo++;}//任务结束 移除表名TableNameContext.remove();}//删除redis中的数据//todo 添加定时或者 XXL_JOB@XxlJob("xxl_job_points_board_remove_redis")public void clearPointsBoardFromRedis(){//获取上个月的时间LocalDateTime time = LocalDateTime.now().minusMonths(1);//拼接keyString key = "point:rank:board:" + time.format(DateTimeFormatter.ofPattern("yyyy:MM"));//删除上个月的redis缓存数据redisTemplate.unlink(key);}public List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {//计算分页信息int from = (pageNo - 1) * pageSize;int end = from + pageSize + 1;//从redis中查询Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, from, end);//判断是否为空if (CollectionUtils.isEmpty(tuples)) {return new ArrayList<>();}//封装排行榜信息int rank = from + 1;List<PointsBoard> result = new LinkedList<>();for (ZSetOperations.TypedTuple<String> tuple : tuples) {String userId = tuple.getValue(); //用户IdDouble score = tuple.getScore();  //用户积分if (userId==null||score==null){continue;}PointsBoard board = new PointsBoard();board.setId(Long.valueOf(rank++));board.setUserId(Long.valueOf(userId));board.setPoints(score.intValue());result.add(board);}return result;}}
配置类
package com.orchids.ranklist.web.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.orchids.ranklist.web.utils.TableNameContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** @ Author qwh* @ Date 2024/7/6 14:49*/
@Configuration
public class MybatisPlusConfiguration {/*** 添加动态表明插件*/@Beanpublic DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {// 准备一个Map,用于存储TableNameHandlerMap<String, TableNameHandler> map = new HashMap<>(1);// 存入一个TableNameHandler,用来替换points_board表名称// 替换方式,就是从TableInfoContext中读取保存好的动态表名map.put("points_board", (sql, tableName) -> TableNameContext.getInfo() == null ? tableName : TableNameContext.getInfo());return new DynamicTableNameInnerInterceptor(map);}/*** 添加分页插件*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(@Autowired(required = false) DynamicTableNameInnerInterceptor nameInnerInterceptor) {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//表名替换插件  //todo !!!!!!!!!!!!!!!!!!!!!注意注意(っ °Д °;)っinterceptor.addInnerInterceptor(nameInnerInterceptor);//f分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加// 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbTypereturn interceptor;}
}
xxl配置类
package com.orchids.ranklist.web.config;import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @ Author qwh* @ Date 2024/7/7 9:28*/
@Slf4j
@Configuration
@EnableConfigurationProperties(XxlJobProperties.class)
public class XxlJobConfig {/*** 配置XxlJobSpringExecutor Bean,用于初始化XxlJob的执行器。* @param prop XxlJobProperties实例,包含XxlJob的配置信息。* @return 初始化后的XxlJobSpringExecutor实例。*/@Beanpublic XxlJobSpringExecutor xxlJobExecutor(XxlJobProperties prop) {// 初始化日志,表示XxlJob配置开始初始化log.info(">>>>>>>>>>> xxl-job config init.");// 创建XxlJobSpringExecutor实例XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();// 配置管理员地址XxlJobProperties.Admin admin = prop.getAdmin();if (admin != null && admin.getAddress()!=null) {xxlJobSpringExecutor.setAdminAddresses(admin.getAddress());}// 配置执行器信息XxlJobProperties.Executor executor = prop.getExecutor();if (executor != null) {// 配置执行器名称if (executor.getAppName() != null)xxlJobSpringExecutor.setAppname(executor.getAppName());// 配置执行器IPif (executor.getIp() != null)xxlJobSpringExecutor.setIp(executor.getIp());// 配置执行器端口if (executor.getPort() != null)xxlJobSpringExecutor.setPort(executor.getPort());// 配置日志路径if (executor.getLogPath() != null)xxlJobSpringExecutor.setLogPath(executor.getLogPath());// 配置日志保留天数if (executor.getLogRetentionDays() != null)xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays());}// 配置访问令牌if (prop.getAccessToken() != null)xxlJobSpringExecutor.setAccessToken(prop.getAccessToken());// 初始化日志,表示XxlJob配置结束log.info(">>>>>>>>>>> xxl-job config end.");// 返回初始化后的执行器实例return xxlJobSpringExecutor;}
}
package com.orchids.ranklist.web.config;import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** @ Author qwh* @ Date 2024/7/7 9:28*/
@Data
//排除没有加入xxl_job的服务避免无法生成bean导致启动失败
@ConditionalOnClass(XxlJobSpringExecutor.class)
@ConfigurationProperties(prefix = "xxl-job")
public class XxlJobProperties {private String accessToken;private Admin admin;private Executor executor;@Datapublic static class Admin {private String address;}@Datapublic static class Executor {private String appName;private String address;private String ip;private Integer port;private String logPath;private Integer logRetentionDays;}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--接口的地址com开始到接口名UserMapper-->
<mapper namespace="com.orchids.ranklist.web.mapper.PointsBoardMapper"><!--sql语句--><insert id="createPointsBoardTable">CREATE TABLE `${tableName}`(`id`      BIGINT NOT NULL AUTO_INCREMENT COMMENT '榜单id',`user_id` BIGINT NOT NULL COMMENT '学生id',`points`  INT    NOT NULL COMMENT '积分值',PRIMARY KEY (`id`) USING BTREE,INDEX `idx_user_id` (`user_id`) USING BTREE)COMMENT ='学霸天梯榜'COLLATE = 'utf8mb4_0900_ai_ci'ENGINE = InnoDBROW_FORMAT = DYNAMIC</insert>
</mapper>
# 应用服务 WEB 访问端口
server:port: 8081
spring:application:name: rank-list# knife4j 额外配置mvc:pathmatch:matching-strategy: ant_path_matcher# Redis 配置redis:port: 6379host: localhostpassword: 6379# 数据库 配置datasource:type: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://localhost:3306/tianji_redis?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8username: rootpassword: 123123hikari:connection-test-query: SELECT 1 # 自动检测连接connection-timeout: 60000 #数据库连接超时时间,默认30秒idle-timeout: 500000 #空闲连接存活最大时间,默认600000(10分钟)max-lifetime: 540000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟maximum-pool-size: 12 #连接池最大连接数,默认是10minimum-idle: 10 #最小空闲连接数量pool-name: SPHHikariPool # 连接池名称
# Mybatis-plus 配置
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
xxl-job:# 访问令牌 不能乱改 要和jar包中的一致access-token: default_tokenadmin:address: http://localhost:8080/xxl-job-adminexecutor:appname: rank-list# 日志保存时间log-retention-days: 10# 日志地址logPath: rank-list#自动获取
#      port: 9999#ip会自动获取
#      ip: localhost
其他的类

PointsBoard

package com.orchids.ranklist.web.domain.po;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;/*** <p>* 学霸天梯榜* </p>** @author nullpointer* @since 2024-07-06*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
//@TableName("points_board")  //每月初 持久化一个赛季的排行信息 到数据库 表为 points_board_seasonId
public class PointsBoard implements Serializable {private static final long serialVersionUID = 1L;/*** 榜单id*/@TableId(value = "id")private Long id;/*** 学生id*/@TableField("user_id")private Long userId;/*** 积分值*/@TableField("points")private Integer points;/*** 名次,只记录赛季前100*/@TableField(exist = false)private Integer rank;/*** 赛季,例如 1,就是第一赛季,2-就是第二赛季*/@TableField(exist = false)private Integer season;}

PointsBoardSeason

package com.orchids.ranklist.web.domain.po;import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import java.time.LocalDate;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;/*** <p>* * </p>** @author nullpointer* @since 2024-07-06*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("points_board_season")
public class PointsBoardSeason implements Serializable {private static final long serialVersionUID = 1L;/*** 自增长id,season标示*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 赛季名称,例如:第1赛季*/private String name;/*** 赛季开始时间*/private LocalDate beginTime;/*** 赛季结束时间*/private LocalDate endTime;}
package com.orchids.ranklist.web.domain.query;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;import javax.validation.constraints.Min;/*** @ Author qwh* @ Date 2024/7/6 19:53*/
@Data
@ApiModel(description = "分页请求参数")
@Accessors(chain = true)
public class BoardQuery {public static final Integer DEFAULT_PAGE_SIZE = 20;public static final Integer DEFAULT_PAGE_NUM =1;@ApiModelProperty(value = "页码", example = "1")@Min(value = 1, message = "页码不能小于1")private Integer pageNo = DEFAULT_PAGE_NUM;@ApiModelProperty(value = "每页大小", example = "5")@Min(value = 1, message = "每页查询数量不能小于1")private Integer pageSize = DEFAULT_PAGE_SIZE;@ApiModelProperty(value = "赛季id,为null或者0则代表查询当前赛季")private Long seasonId;
}
package com.orchids.ranklist.web.domain.vo;import com.orchids.ranklist.web.domain.po.PointsBoard;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;/*** @ Author qwh* @ Date 2024/7/6 19:01*/
@Data
@ApiModel(description = "积分榜单汇总信息")
public class PointsBoardVO {@ApiModelProperty("我的榜单排名")private Integer rank;@ApiModelProperty("我的积分值")private Integer points;@ApiModelProperty("前100名上榜人信息")private List<PointsBoard> boardList;
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.orchids</groupId><artifactId>rank-list</artifactId><version>0.0.1-SNAPSHOT</version><name>rank-list</name><description>rank-list</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core --><dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>2.4.1</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.orchids.ranklist.RankListApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
测试

当前赛季
image.png
image.png
历史赛季
image.png
image.png

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com