项目上传

This commit is contained in:
2025-03-20 22:05:58 +08:00
commit e7bab0d002
278 changed files with 14221 additions and 0 deletions

149
challenge/pom.xml Normal file
View File

@@ -0,0 +1,149 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mine_clearance</artifactId>
<groupId>com.lightyears.mine_clearance</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>challenge</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid数据源驱动 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- 由于SpringBoot 2.x中默认并没有使用Redis连接池所以需要添加commons-pool2的依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--redis依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<!--swagger2整合-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- rocketmq 整合 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
<!-- hutool 一个常用工具集 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.lightyears.mine_clearance</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>challenge</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<!--打包一个JAR-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.lightyears.challenge.ChallengeApp</mainClass>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,19 @@
package com.lightyears.challenge;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.TimeZone;
@EnableScheduling
@SpringBootApplication
@EnableTransactionManagement
public class ChallengeApp {
public static void main(String[] args) {
// 设置时区
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
SpringApplication.run(ChallengeApp.class, args);
}
}

View File

@@ -0,0 +1,9 @@
package com.lightyears.challenge.annotation;
import java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataVerification {
}

View File

@@ -0,0 +1,65 @@
package com.lightyears.challenge.aspect;
import cn.hutool.crypto.digest.MD5;
import com.github.pagehelper.util.StringUtil;
import com.lightyears.common.domain.enums.MessageEnum;
import com.lightyears.challenge.exception.GlobalException;
import com.lightyears.challenge.util.StaticUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.Map;
@Aspect
@Component
public class DataVerificationAspect {
/**
* 过滤类
* 指定自定义注解为切入点
**/
@Pointcut("@annotation(com.lightyears.challenge.annotation.DataVerification)")
public void checkPoint() {
}
/**
* 前置
*/
@Before("checkPoint()")
public void doAround(JoinPoint joinPoint) throws GlobalException {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
assert sra != null;
HttpServletRequest request = sra.getRequest();
String checkKey = request.getHeader("checkKey");
Map<String, String[]> paramMap = request.getParameterMap();
StringBuffer paramsStr = new StringBuffer();
if (StringUtil.isEmpty(checkKey)) {
throw new GlobalException(MessageEnum.CHECK_KEY_ERROR);
}
Object[] params = joinPoint.getArgs();
if(paramMap.size() > 0) {
Collection<String[]> values = paramMap.values();
for (String[] value : values) {
paramsStr.append(value[0]);
}
} else {
if(params.length == 1) {
paramsStr.append(params[0].toString());
}
}
String testKey = MD5.create().digestHex(MD5.create().digestHex(paramsStr.append(StaticUtil.PRIVATE_KEY).toString()));
if (!checkKey.equals(testKey)) {
throw new GlobalException(MessageEnum.CHECK_KEY_ERROR);
}
}
}

View File

@@ -0,0 +1,16 @@
package com.lightyears.challenge.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "appconfig")
public class AppConfig {
private Float version;
}

View File

@@ -0,0 +1,86 @@
package com.lightyears.challenge.configuration;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
// 开启redis缓存功能
@EnableCaching
// 备注这是一个配置类
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 配置redis模板文件
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisSerializer<Object> serializer = redisSerializer();
// 创建RedisTemplate<String, Object>对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 配置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// redis key 序列化方式使用stringSerial
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redis value 序列化方式使用jackson
redisTemplate.setValueSerializer(serializer);
// redis hash key 序列化方式使用stringSerial
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// redis hash value 序列化方式使用jackson
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 配置序列化
* @return
*/
@Bean
public RedisSerializer<Object> redisSerializer() {
// 定义Jackson2JsonRedisSerializer序列化对象
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域field,get和set,以及修饰符范围ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型类必须是非final修饰的final修饰的类比如String,Integer等会报异常
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
return serializer;
}
/**
* 自定义缓存管理器
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
// 设置value 为自动转json的Object
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer()))
// 缓存有效期为一天
.entryTtl(Duration.ofDays(1));
return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
}

View File

@@ -0,0 +1,24 @@
package com.lightyears.challenge.configuration;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.TimeZone;
@Configuration
public class ScheduledConfig {
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(3);
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
return threadPoolTaskScheduler;
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
return jacksonObjectMapperBuilder ->
jacksonObjectMapperBuilder.timeZone(TimeZone.getTimeZone("GMT+8"));
}
}

View File

@@ -0,0 +1,55 @@
package com.lightyears.challenge.controller;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.StaticUtil;
import com.lightyears.common.domain.entity.Player;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BaseController {
@Autowired
private RedisCache redisCache;
/**
* 得到request对象
*
* @return
*/
public HttpServletRequest getRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
return request;
}
/**
* 得到respones对象
* @return
*/
public HttpServletResponse getResponse() {
HttpServletResponse request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getResponse();
return request;
}
/**
* 得到当前登录用户信息
*
* @return
*/
public Player getUserInfo() {
// 获取请求头中的token数据
String token = getRequest().getHeader("Tracecode");
if(token == null) {
token = this.getRequest().getParameter("Tracecode");
}
String key = StaticUtil.ONLINE_USER_PUBLIC_KEY.concat(token);
// 获取登录用户信息
Player user = redisCache.getCacheObject(key);
return user;
}
}

View File

@@ -0,0 +1,109 @@
package com.lightyears.challenge.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.lightyears.challenge.annotation.DataVerification;
import com.lightyears.challenge.schedule.DynamicCornTask;
import com.lightyears.challenge.service.IChallengeService;
import com.lightyears.challenge.util.ResultUtil;
import com.lightyears.common.domain.dto.ResModeBase;
import com.lightyears.common.domain.entity.Player;
import com.lightyears.common.domain.enums.MessageEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@CrossOrigin
@RestController
@RequestMapping("/challenge")
@Api("扫雷 挑战榜调用接口:")
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class ChallengeController extends BaseController{
private final IChallengeService challengeServiceImpl;
private final DynamicCornTask dynamicCornTask;
@DataVerification
@GetMapping("/list")
@ApiOperation(value = "榜单列表", notes = "挑战榜")
public ResModeBase list() {
return challengeServiceImpl.getList();
}
@RequestMapping(value = "/rankList", method = RequestMethod.POST)
@ApiOperation(value = "挑战榜列表", notes = "挑战榜")
@DataVerification
public ResModeBase rankList(
@ApiParam(value = "当前页", example = "1") @RequestParam(value = "pageIndex") Integer pageIndex,
@ApiParam(value = "每页数量", example = "1") @RequestParam(value = "pageSize") Integer pageSize,
@ApiParam(value = "榜单id", example = "1") @RequestParam(value = "id") Integer id) {
return challengeServiceImpl.rankList(pageIndex, pageSize, id);
}
@DataVerification
@RequestMapping(value = "/admissionTicket", method = RequestMethod.POST)
@ApiOperation(value = "挑战门票费-开始挑战", notes = "挑战榜")
public ResModeBase admissionTicket( @ApiParam(value = "榜单id", example = "1") @RequestParam(value = "instanceId") Integer instanceId,
@ApiParam(value = "将要挑战的名次", example = "1") @RequestParam(value = "rank")Integer rank,
@ApiParam(value = "货币数量", example = "1") @RequestParam(value = "gold") Integer gold,
@ApiParam(value = "货币类型", example = "1") @RequestParam(value = "type") Integer type,
@ApiParam(value = "操作备注", example = "1") @RequestParam(value = "remark") String remark) {
return challengeServiceImpl.admissionTicket(instanceId, rank, gold, type,remark, this.getUserInfo().getUser_id());
}
@DataVerification
@RequestMapping(value = "/challengeDataSubmit", method = RequestMethod.POST)
@ApiOperation(value = "挑战结算", notes = "挑战榜")
public ResModeBase challengeDataSubmit( @ApiParam(value = "榜单id", example = "1") @RequestParam(value = "instanceId") Integer instanceId,
@ApiParam(value = "挑战名次", example = "1") @RequestParam(value = "rank") Integer rank,
@ApiParam(value = "游戏数据", example = "1") @RequestParam(value = "gameData") String gameData,
@ApiParam(value = "挑战用时", example = "1") @RequestParam(value = "challengeTime") Integer challengeTime,
@ApiParam(value = "挑战时原榜主id", example = "1") @RequestParam(value = "ownerId") Integer ownerId) {
Player player = this.getUserInfo();
return challengeServiceImpl.challengeDataSubmit(instanceId,rank,gameData,challengeTime,ownerId, player.getUser_id(), player.getUser_name());
}
@DataVerification
@GetMapping("/playerAssert")
@ApiOperation(value = "获取玩家资产信息", notes = "挑战榜")
public ResModeBase playerAssert(){
return challengeServiceImpl.playerAssert(this.getUserInfo().getUser_id());
}
@DataVerification
@GetMapping("/getMyRankInfo")
@ApiOperation(value = "获取玩家在榜单中的名次信息", notes = "挑战榜")
public ResModeBase getPlayerRankInfo(@ApiParam(value = "榜单id", example = "1") @RequestParam(value = "instanceId") Integer instanceId){
return challengeServiceImpl.getPlayerRankInfo(instanceId, this.getUserInfo().getUser_id());
}
@PostMapping("/resetTaskTime")
public ResModeBase resetChallengeTaskTime(@RequestParam(value = "lockDate") String lockDateStr,
@RequestParam(value = "settlementDate") String settlementDateStr,
@RequestParam(value = "initDate") String initDateStr,
@RequestParam(value = "refreshDateStr") String refreshDateStr){
// 锁榜
DateTime lockDate = DateUtil.parse(lockDateStr);
// 结算
DateTime settlementDate = DateUtil.parse(settlementDateStr);
// 初始化
DateTime initDate = DateUtil.parse(initDateStr);
// 刷新
DateTime refreshDate = DateUtil.parse(refreshDateStr);
// 发起重置时间
dynamicCornTask.initChallengeTask(lockDate, settlementDate, initDate, refreshDate);
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), "请求成功!");
}
@PostMapping("/refreshRankCache")
public ResModeBase refreshRankCache(@RequestParam(value = "key")Integer key, @RequestParam(value = "instanceId") Integer instanceId, @RequestParam(value = "playerId") Integer playerId, @RequestParam(value = "rankNum") Integer rankNum){
if(key == 43626546) {
challengeServiceImpl.clearRankByInstancePlayerId(instanceId, playerId, rankNum);
}
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage());
}
}

View File

@@ -0,0 +1,18 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.entity.AssertLog;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Mapper
public interface AssertLogMapper extends BaseMapper<AssertLog> {
}

View File

@@ -0,0 +1,17 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.entity.ListBase;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Mapper
public interface ListBaseMapper extends BaseMapper<ListBase> {
}

View File

@@ -0,0 +1,41 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.dto.ListInstanceDto;
import com.lightyears.common.domain.entity.ListInstance;
import com.lightyears.common.domain.dto.ListInstanceDto;
import com.lightyears.common.domain.entity.ListInstance;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
;
/**
* <p>
* Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Mapper
public interface ListInstanceMapper extends BaseMapper<ListInstance> {
/**
* 奖池增加
* @param instanceId 榜实例id
* @param awardSize 奖池要增加的数
* @param assetsType 货币类型
* @return
*/
int updateInstanceAwardSize(@Param("instanceId") Integer instanceId,@Param("awardSize") Integer awardSize,@Param("assetsType") Integer assetsType);
/**
* 获取榜单列表
*
* @return
*/
List<ListInstanceDto> getListInstances();
}

View File

@@ -0,0 +1,25 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.entity.ListRank;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Mapper
public interface ListRankMapper extends BaseMapper<ListRank> {
int initRank(@Param("instanceId") Integer instanceId, @Param("playerId") Integer playerId);
List<ListRankDto> getRankList(@Param("instanceId") Integer instanceId, @Param("playerId") Integer playerId, @Param("state") Integer state);
List<ListRankDto> getNewRankList (@Param("instanceId") Integer instanceId, @Param("playerId") Integer playerId);
ListRankDto getRankByInsRank(@Param("instanceId") Integer instanceId,@Param("rank") Integer rank);
}

View File

@@ -0,0 +1,19 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.entity.Log;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 游戏 完成记录 表 游戏难度1 - 普通 2 困难 3 大师 Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-09
*/
@Mapper
public interface LogMapper extends BaseMapper<Log> {
}

View File

@@ -0,0 +1,18 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.entity.Notice;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-18
*/
@Mapper
public interface NoticeMapper extends BaseMapper<Notice> {
}

View File

@@ -0,0 +1,32 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.dto.SimplePlayerAssert;
import com.lightyears.common.domain.entity.PlayerAssets;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Mapper
public interface PlayerAssetsMapper extends BaseMapper<PlayerAssets> {
// 货币存放服务器
int addGold(@Param("id") int id, @Param("gold") int gold, @Param("version") Long version);
// 从服务器取出货币
int reduceGold(@Param("id") int id,@Param("gold") int gold, @Param("version") Long version);
/**
* 获取用户资产
* @param playerId
* @return
*/
List<SimplePlayerAssert> getPlayerAssets(@Param("playerId") int playerId);
}

View File

@@ -0,0 +1,17 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.entity.Player;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 扫雷玩家表 Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-09
*/
@Mapper
public interface PlayerMapper extends BaseMapper<Player> {
}

View File

@@ -0,0 +1,18 @@
package com.lightyears.challenge.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lightyears.common.domain.entity.Record;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 游戏存档 Mapper 接口
* </p>
*
* @author hellor
* @since 2022-03-09
*/
@Mapper
public interface RecordMapper extends BaseMapper<Record> {
}

View File

@@ -0,0 +1,18 @@
package com.lightyears.challenge.exception;
import com.lightyears.common.domain.enums.MessageEnum;
/**
* @author fengshuonan
* @Description 业务异常的封装
*/
public class BussinessException extends GlobalException {
public BussinessException(MessageEnum messageEnum) {
super(messageEnum.getCode(), messageEnum.getMessage());
}
public BussinessException(Integer code, String message) {
super(code, message);
}
}

View File

@@ -0,0 +1,47 @@
package com.lightyears.challenge.exception;
import com.lightyears.common.domain.enums.MessageEnum;
/***
* 全局异常捕捉 统一返回 model
* */
public class GlobalException extends RuntimeException {
//友好提示的code码
protected int friendlyCode;
//友好提示
protected String friendlyMsg;
protected GlobalException(int friendlyCode, String friendlyMsg) {
this.setValues(friendlyCode, friendlyMsg);
}
public GlobalException(MessageEnum messageEnum) {
this.setValues(messageEnum.getCode(), messageEnum.getMessage());
}
private void setValues(int friendlyCode, String friendlyMsg) {
this.friendlyCode = friendlyCode;
this.friendlyMsg = friendlyMsg;
}
public int getCode() {
return friendlyCode;
}
public void setCode(int code) {
this.friendlyCode = code;
}
public String getMessage() {
return friendlyMsg;
}
public void setMessage(String message) {
this.friendlyMsg = message;
}
}

View File

@@ -0,0 +1,26 @@
package com.lightyears.challenge.exception;
import com.lightyears.common.domain.dto.ResModeBase;
import com.lightyears.common.domain.enums.MessageEnum;
import com.lightyears.challenge.util.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@ControllerAdvice
public class MyExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResModeBase handle(Exception e) {
if (e instanceof GlobalException) {
GlobalException myException = (GlobalException) e;
return ResultUtil.result(myException.getCode(), myException.getMessage());
} else {
log.error("系统异常", e);
return ResultUtil.result(MessageEnum.UNKNOWN_ERROR.getCode(), MessageEnum.UNKNOWN_ERROR.getMessage());
}
}
}

View File

@@ -0,0 +1,116 @@
package com.lightyears.challenge.filter;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import com.lightyears.challenge.config.AppConfig;
import com.lightyears.common.domain.entity.Player;
import com.lightyears.common.domain.enums.MessageEnum;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.StaticUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Component
public class TokenFilter implements Filter{
@Resource
private RedisCache redisCache;
@Resource
private AppConfig appConfig;
@Override
public void init(FilterConfig filterConfig) {
ServletContext servletContext = filterConfig.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
redisCache = (RedisCache) ctx.getBean("redisCache");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 刷新缓存不验证
if(request.getRequestURI().indexOf("refreshRankCache")<0){
// 版本号验证
String version = request.getHeader("version");
if (StrUtil.isEmpty(version)) {
this.authcReq(response, MessageEnum.VERSION_ERROR.getCode(), MessageEnum.VERSION_ERROR.getMessage());
return;
}
try{
Float versionCode = Float.valueOf(version);
if(versionCode < appConfig.getVersion()){
this.authcReq(response, MessageEnum.VERSION_ERROR.getCode(), MessageEnum.VERSION_ERROR.getMessage());
return;
}
}catch (Exception e) {
this.authcReq(response, MessageEnum.VERSION_ERROR.getCode(), MessageEnum.VERSION_ERROR.getMessage());
return;
}
}
String tracecode = request.getHeader("Tracecode");
Boolean flag = request.getRequestURI().indexOf("touristLogin")<0 && request.getRequestURI().indexOf("getSystemTime") < 0 && request.getRequestURI().indexOf("swagger-ui")<0 && request.getRequestURI().indexOf("swagger-resources")<0 && request.getRequestURI().indexOf("v2") < 0 && request.getRequestURI().indexOf("refreshRankCache")<0;
// 登录放行
if(flag){
// 判断身份码, 是否已登录
if((StringUtil.isEmpty(tracecode) || !redisCache.hasKey(StaticUtil.ONLINE_USER_PUBLIC_KEY.concat(tracecode)))){
/**
* 不是登录 || 身份码不存在 || 未在登录列表 就拒绝访问
*/
this.authcReq(response, MessageEnum.SYSTEM_ERROR.getCode(), MessageEnum.SYSTEM_ERROR.getMessage());
return;
}
Player player = redisCache.getCacheObject(StaticUtil.ONLINE_USER_PUBLIC_KEY.concat(tracecode));
String token = redisCache.getCacheObject(StaticUtil.ONLINE_USER_TOKEN.concat(player.getUser_id().toString())).toString();
if(!tracecode.equals(token)) {
/**
* 登录失效,已被异地登录
*/
this.authcReq(response, MessageEnum.LOCATION_ERROR.getCode(), MessageEnum.LOCATION_ERROR.getMessage());
return;
}
// 重置身份缓存过期时间
redisCache.expire(StaticUtil.ONLINE_USER_TOKEN.concat(player.getUser_id().toString()), 1, TimeUnit.HOURS);
// 重置身份认证过期时间
redisCache.expire(StaticUtil.ONLINE_USER_PUBLIC_KEY.concat(tracecode), 1, TimeUnit.HOURS);
}
//执行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
/**
* 响应访问
* @param response
* @throws IOException
*/
private void authcReq(HttpServletResponse response, Integer code, String msg) throws IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("code", code);
map.put("msg", msg);
writer.print(JSONObject.toJSON(map));
}
}

View File

@@ -0,0 +1,131 @@
package com.lightyears.challenge.init;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lightyears.challenge.dao.ListBaseMapper;
import com.lightyears.challenge.dao.ListInstanceMapper;
import com.lightyears.challenge.dao.ListRankMapper;
import com.lightyears.common.domain.dto.ListInstanceDto;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.dto.OrdinaryRankDto;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.challenge.schedule.DynamicCornTask;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.StaticUtil;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
/**
* 挑战数据初始化
*/
@Component
public class ChallengeDataInit {
@Resource
private RedisCache redisCache;
@Resource
private ListRankMapper listRankMapper;
@Resource
private ListInstanceMapper listInstanceMapper;
@Resource
private ListBaseMapper listBaseMapper;
@Resource
private DynamicCornTask dynamicCornTask;
@PostConstruct
public void init() {
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE);
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL);
this.initData(true);
}
@PreDestroy
public void destroy() {
// 系统运行结束
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE);
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL);
// 写入持久层
}
// 刷新挑战榜的缓存数据
public void refreshData() {
// 删除上一周期的挑战榜缓存数据
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE);
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL);
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_ONLINE_USER);
// 写入新一周期的挑战榜缓存数据
this.initData(false);
}
private void initData(Boolean isStart){
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL);
// 写入开启中挑战榜实例信息
List<ListInstanceDto> instances = this.initInstance();
if(isStart){
// 启动挑战榜定时任务
initChallengeTask();
}
instances.stream().forEach(instance -> {
List<ListRankDto> ranks = this.initranks(instance.getId());
// 存入
redisCache.lSetAll(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(instance.getId().toString()), ranks);
});
}
/**
* 存入榜实例信息
* @return
*/
public List<ListInstanceDto> initInstance (){
redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE);
List<ListInstanceDto> instances = this.listInstanceMapper.getListInstances();
if (!CollectionUtils.isEmpty(instances)){
redisCache.setCacheObject(StaticUtil.CHALLENGE_INSTANCE, instances);
}
return instances;
}
/**
* 写入开启中挑战榜的排名信息
* @param instanceId 榜实例id
* @return
*/
public List<ListRankDto> initranks (Integer instanceId){
// redisCache.deleteByPrefix(StaticUtil.CHALLENGE_INSTANCE_RANK.concat(instanceId.toString()));
List<ListRankDto> ranks = listRankMapper.getRankList(instanceId, null, null);
// if (!CollectionUtils.isEmpty(ranks)){
// redisCache.setCacheList(StaticUtil.CHALLENGE_INSTANCE_RANK.concat(instanceId.toString()), ranks);
// }
return ranks;
}
/**
* 启动挑战榜定时任务
*/
public void initChallengeTask(){
List<ListBase> list = listBaseMapper.selectList(new QueryWrapper<ListBase>().orderByDesc("init_date"));
if (!CollectionUtils.isEmpty(list)){
ListBase bases = list.get(0);
// 锁榜 周日 晚上1100
DateTime lockDate = DateUtil.offsetDay(DateUtil.parse(bases.getInitDate().concat(StaticUtil.LOCKE_TIME)), bases.getSettlementDay() - 1);
// 结算 周一 晚上1145
DateTime settlementDate = DateUtil.offsetDay(DateUtil.parse(bases.getInitDate().concat(StaticUtil.SETTLEMENT_TIME)), bases.getSettlementDay());
// 初始化 周二 早上100
DateTime initDate = DateUtil.offsetDay(DateUtil.parse(bases.getInitDate().concat(StaticUtil.CHALLENGE_INIT_TIME)), bases.getSettlementDay() + 1);
// 缓存刷新 周二 早上105
DateTime refreshData = DateUtil.offsetDay(DateUtil.parse(bases.getInitDate().concat(StaticUtil.CHALLENGE_REFRESH_TIME)), bases.getSettlementDay() + 1);
// 启动定时任务
dynamicCornTask.initChallengeTask(lockDate, settlementDate, initDate, refreshData);
}
}
}

View File

@@ -0,0 +1,50 @@
package com.lightyears.challenge.listener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lightyears.challenge.dao.ListInstanceMapper;
import com.lightyears.common.domain.dto.ListPoolChangeDto;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.entity.ListInstance;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.StaticUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
@RocketMQMessageListener(topic = "admissionTicket", selectorExpression = "submit",consumerGroup = "challengeRankTicket")
public class AdmissionTicketListener implements RocketMQListener<ListPoolChangeDto> {
private final ListInstanceMapper listInstanceMapper;
private final RedisCache redisCache;
@Override
@Transactional
public void onMessage(ListPoolChangeDto dto) {
log.info("报名消息已成功接收!");
ListInstance instance = listInstanceMapper.selectById(dto.getInstanceId());
String key = StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(dto.getInstanceId().toString());
if(instance != null && instance.getStatus() == 1){
Object obj = redisCache.lGetIndex(key, dto.getRank()-1);
if(obj == null)
return;
String json = JSONObject.toJSONString(obj) ;
ListRankDto rankDto = JSON.parseObject(json, ListRankDto.class);
Integer num = rankDto.getChallenges() == null ? 0 : rankDto.getChallenges();
rankDto.setChallenges(num + 1);
// 挑战人数+1
redisCache.lUpdateIndex(key, dto.getRank()-1, rankDto);
// 更新奖池大小
listInstanceMapper.updateInstanceAwardSize(dto.getInstanceId(), (int) (dto.getGold()*instance.getInPondFee()), dto.getType());
}
log.info("报名消息已消费完成");
}
}

View File

@@ -0,0 +1,56 @@
package com.lightyears.challenge.listener;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.dto.RankDataDto;
import com.lightyears.challenge.service.IListRankService;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.StaticUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
@RocketMQMessageListener(topic = "rankUpdate", selectorExpression = "submit", consumerGroup = "challengeRank")
public class RankDataUpdateListener implements RocketMQListener<RankDataDto> {
private final IListRankService listRankService;
private final RedisCache redisCache;
@Override
@Transactional
public void onMessage(RankDataDto dto) {
log.info("结算消息已成功接收!");
ListRankDto rankDto = dto.getRankDto();
// 查询未结算的原排名信息
List<ListRankDto> ranks = listRankService.getPlayerRankInfo(null, dto.getMyId());
for (ListRankDto rank : ranks){
// 重置该挑战榜单下的其他名次信息
int num = listRankService.initRank(rank.getInstanceId(), dto.getMyId());
// 更新原排名缓存
if(num > 0) {
rank.setChallengeTime(null);
rank.setPlayerId(null);
rank.setPlayerName(null);
rank.setGameData(null);
redisCache.lUpdateIndex(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(rank.getInstanceId().toString()), rank.getRankNum() - 1, rank);
}
}
rankDto.setPlayerId(dto.getMyId());
rankDto.setPlayerName(dto.getMyName());
rankDto.setChallengeTime(dto.getChallengeTime());
// 更新缓存
redisCache.lUpdateIndex(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(dto.getInstanceId().toString()), rankDto.getRankNum() - 1, rankDto);
// 写入数据库
listRankService.updateRankInfo(dto.getInstanceId(), dto.getRankNum(), dto.getGameData(), dto.getChallengeTime(), dto.getMyId(), dto.getMyName());
log.info("结算消息已成功消费!");
}
}

View File

@@ -0,0 +1,42 @@
package com.lightyears.challenge.schedule;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.challenge.init.ChallengeDataInit;
import com.lightyears.challenge.service.IListBaseService;
import com.lightyears.challenge.util.GetBeanUtil;
import com.lightyears.challenge.util.StaticUtil;
import org.springframework.util.CollectionUtils;
import java.util.List;
public class ChallengeCacheRefreshTask implements Runnable{
@Override
public void run() {
ChallengeDataInit challengeDataInit = (ChallengeDataInit) GetBeanUtil.getBean(ChallengeDataInit.class);
IListBaseService listBaseService = (IListBaseService)GetBeanUtil.getBean("listBaseServiceImpl");
DynamicCornTask dynamicCornTask = (DynamicCornTask) GetBeanUtil.getBean(DynamicCornTask.class);
// 刷新挑战榜数据
challengeDataInit.refreshData();
// 开启下一周期的任务
List<ListBase> listBases = listBaseService.list();
if(!CollectionUtils.isEmpty(listBases)){
ListBase listBase = listBases.get(0);
// 锁榜 结束日 晚上1100
DateTime lockDate = DateUtil.offsetDay(DateUtil.parse(listBase.getInitDate().concat(StaticUtil.LOCKE_TIME)), listBase.getSettlementDay() - 1);
// 结算 结束日 晚上1145
DateTime settlementDate = DateUtil.offsetDay(DateUtil.parse(listBase.getInitDate().concat(StaticUtil.SETTLEMENT_TIME)), listBase.getSettlementDay());
// 初始化 结束日第二天 早上100
DateTime initDate = DateUtil.offsetDay(DateUtil.parse(listBase.getInitDate().concat(StaticUtil.CHALLENGE_INIT_TIME)), listBase.getSettlementDay() + 1);
// 缓存刷新 结束日第二天 早上100
DateTime refreshDate = DateUtil.offsetDay(DateUtil.parse(listBase.getInitDate().concat(StaticUtil.CHALLENGE_REFRESH_TIME)), listBase.getSettlementDay() + 1);
for (ListBase base : listBases) {
// 修改初始化日期
base.setInitDate(initDate.toDateStr());
}
// 重置定时任务
dynamicCornTask.resetChallengeTask(lockDate, settlementDate, initDate, refreshDate);
}
}
}

View File

@@ -0,0 +1,29 @@
package com.lightyears.challenge.schedule;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lightyears.common.domain.entity.ListInstance;
import com.lightyears.challenge.service.IListInstanceService;
import com.lightyears.challenge.util.GetBeanUtil;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
public class ChallengeLockTask implements Runnable{
@Override
@Transactional
public void run() {
IListInstanceService listInstanceService = (IListInstanceService) GetBeanUtil.getBean("listInstanceServiceImpl");
// 查询开启中的挑战榜实例
List<ListInstance> listInstances = listInstanceService.list(new QueryWrapper<ListInstance>().eq("status", 1));
// 结算每个实例榜单
listInstances.stream().forEach(listInstance ->{
// 结算日期
listInstance.setSettlementDate(new Date());
// 已截止,待结算
listInstance.setStatus(3);
// 修改实例榜信息
listInstanceService.updateById(listInstance);
});
}
}

View File

@@ -0,0 +1,94 @@
package com.lightyears.challenge.schedule;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lightyears.challenge.service.*;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.common.domain.entity.ListInstance;
import com.lightyears.common.domain.entity.Notice;
import com.lightyears.common.domain.enums.AssetsTypeEnum;
import com.lightyears.challenge.util.GetBeanUtil;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.StaticUtil;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class ChallengeSettlementTask implements Runnable{
@Override
@Transactional
public void run() {
IListBaseService listBaseService = (IListBaseService)GetBeanUtil.getBean("listBaseServiceImpl");
IListInstanceService listInstanceService = (IListInstanceService) GetBeanUtil.getBean("listInstanceServiceImpl");
IListRankService listRankService = (IListRankService) GetBeanUtil.getBean("listRankServiceImpl");
IGameSystemService gameSystemService = (IGameSystemService)GetBeanUtil.getBean("gameSystemServiceImpl");
INoticeService noticeService = (INoticeService) GetBeanUtil.getBean("noticeServiceImpl");
RedisCache redisCache = (RedisCache)GetBeanUtil.getBean("redisCache");
// 查询待结算的挑战榜实例
List<ListInstance> listInstances = listInstanceService.list(new QueryWrapper<ListInstance>().eq("status", 3));
// 结算每个实例榜单
listInstances.stream().forEach(listInstance -> {
BigDecimal awardSize = new BigDecimal(listInstance.getAwardSize());
String[] distribution = ObjectUtils.isEmpty(listInstance.getDistribution()) || listInstance.getDistribution().length() < listInstance.getMaxPlayerNum() ? defaultDistribution(listInstance.getMaxPlayerNum()) : listInstance.getDistribution().split(",");
List<ListRankDto> ranks = listRankService.getRankList(listInstance.getId());
BigDecimal hundred = new BigDecimal(100);
for (int i = 0; i < ranks.size(); i++) {
ListRankDto rank = ranks.get(i);
if (!ObjectUtils.isEmpty(rank.getPlayerId())){
BigDecimal distributionNum = new BigDecimal(distribution[i]).divide(hundred);
Integer bonus = awardSize.multiply(distributionNum).setScale(0, BigDecimal.ROUND_HALF_DOWN).intValue();
if (bonus > 0){
// 排名玩家奖励发放
gameSystemService.pushGold(rank.getPlayerId(), bonus, listInstance.getAssetsType(), String.format(StaticUtil.CHALLENGE_REMARK, listInstance.getName(), rank.getRankNum(), bonus, AssetsTypeEnum.getNameById(listInstance.getAssetsType())));
// 奖励通知写入
Notice notice = new Notice().builder()
.playerId(rank.getPlayerId())
.status(0)
.type(1)
.createDate(new Date())
.title(StaticUtil.CHALLENGE_NOTICE_TITLE)
.content(String.format(StaticUtil.CHALLENGE_REMARK, listInstance.getName(), rank.getRankNum(), bonus, AssetsTypeEnum.getNameById(listInstance.getAssetsType()))).build();
noticeService.save(notice);
}
}
}
// 结算日期
listInstance.setSettlementDate(new Date());
// 已截止
listInstance.setStatus(2);
// 修改实例榜信息
listInstanceService.updateById(listInstance);
// 删除这次挑战榜所有缓存
redisCache.deleteByPrefix(StaticUtil.CHALLENGE);
// 修改初始化时间
listBaseService.update(new LambdaUpdateWrapper<ListBase>().set(ListBase::getInitDate, DateUtil.today()).eq(ListBase::getId, listInstance.getListId()));
});
}
private String[] defaultDistribution(Integer maxNum) {
List<String> arr = new ArrayList<>();
for (int i = 0; i < maxNum; i++) {
arr.add(calc(i, 0, 100, maxNum).intValue() + "");
}
return arr.toArray(new String[]{});
}
/**
* @param curtime
* @param begin
* @param end
* @param duration
* @return
*/
private Float controlWeightRote(Integer curtime, Integer begin, Integer end, Integer duration) {
return (curtime == 0) ? begin * 1.0F : end * (curtime / duration - 1) + begin;
}
private Float calc(Integer curtime, Integer begin, Integer end, Integer duration) {
return controlWeightRote(curtime, begin, end, duration) - controlWeightRote(curtime - 1, begin, end, duration);
}
}

View File

@@ -0,0 +1,145 @@
package com.lightyears.challenge.schedule;
import cn.hutool.core.date.DateTime;
import com.lightyears.challenge.util.CronUtils;
import com.lightyears.challenge.util.ScheduledFutureHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.concurrent.ScheduledFuture;
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class DynamicCornTask {
private final ThreadPoolTaskScheduler threadPoolTaskScheduler;
//存储任务执行的包装类
private HashMap<String, ScheduledFutureHolder> scheduleMap = new HashMap<>();
/**
*启动任务
* 如果不想手动触发任务可以使用 @PostConstruct注解来启动
*/
public void startTask(Runnable task, String corn) {
try {
//将任务交给任务调度器执行
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(task, new CronTrigger(corn));
//将任务包装成ScheduledFutureHolder
ScheduledFutureHolder scheduledFutureHolder = new ScheduledFutureHolder();
scheduledFutureHolder.setScheduledFuture(schedule);
scheduledFutureHolder.setRunnableClass(task.getClass());
scheduledFutureHolder.setCorn(corn);
scheduleMap.put(task.getClass().getName(),scheduledFutureHolder);
log.info("定时任务启动成功:".concat(task.getClass().getName()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询所有的任务
*/
public void queryTask(){
scheduleMap.forEach((k,v)->{
System.out.println(k+" "+v);
System.out.println(v.getCorn());
});
}
/**
* 停止任务
* @param className
*/
public void stopTask(String className){
if(scheduleMap.containsKey(className)){//如果包含这个任务
ScheduledFuture<?> scheduledFuture = scheduleMap.get(className).getScheduledFuture();
if(scheduledFuture!=null){
scheduledFuture.cancel(true);
}
}
}
/**
* 重启任务,修改任务的触发时间
* @param className
* @throws InstantiationException
* @throws IllegalAccessException
*/
public void restartTask(String className, String corn){
if(scheduleMap.containsKey(className)){//如果包含这个任务
ScheduledFutureHolder scheduledFutureHolder = scheduleMap.get(className);
ScheduledFuture<?> scheduledFuture = scheduledFutureHolder.getScheduledFuture();
if(scheduledFuture!=null) {
try {
//先停掉任务
scheduledFuture.cancel(true);
//修改触发时间重新启动任务
Runnable runnable = null;
runnable = scheduledFutureHolder.getRunnableClass().newInstance();
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(runnable, new CronTrigger(corn));
scheduledFutureHolder.setScheduledFuture(schedule);
scheduledFutureHolder.setCorn(corn);
scheduleMap.put(scheduledFutureHolder.getRunnableClass().getName(), scheduledFutureHolder);
}catch(Exception e){
log.error("定时任务重置失败:".concat(className));
log.error("详细错误信息:", e);
}
}
}
}
/**
* 挑战榜定时任务重启
* @param lockDate 锁榜日期时间
* @param settlementDate 结算日期时间
* @param initDate 初始化新榜日期时间
* @param refreshDate 缓存刷新时间
*/
public void resetChallengeTask(DateTime lockDate, DateTime settlementDate, DateTime initDate, DateTime refreshDate){
restartTask(ChallengeLockTask.class.getName(), CronUtils.getCron(lockDate));
restartTask(ChallengeSettlementTask.class.getName(), CronUtils.getCron(settlementDate));
restartTask(InitChallengeTask.class.getName(), CronUtils.getCron(initDate));
restartTask(ChallengeCacheRefreshTask.class.getName(), CronUtils.getCron(refreshDate));
log.info("下次锁榜时间:".concat(lockDate.toString()));
log.info("下次结算时间:".concat(settlementDate.toString()));
log.info("下次初始化时间:".concat(initDate.toString()));
log.info("下次刷新时间:".concat(refreshDate.toString()));
log.info("挑战榜定时任务启动成功");
}
/**
* 挑战榜定时任务启动
* @param lockDate 锁榜日期时间
* @param settlementDate 结算日期时间
* @param initDate 初始化新榜日期时间
* @param refreshDate 缓存刷新时间
*/
public void initChallengeTask(DateTime lockDate, DateTime settlementDate, DateTime initDate, DateTime refreshDate){
// 每5分钟刷新挑战实例的奖池
startTask(new RefreshInstanceListTask(), "0 */1 * * * ?");
startTask(new ChallengeLockTask(), CronUtils.getCron(lockDate));
startTask(new ChallengeSettlementTask(), CronUtils.getCron(settlementDate));
startTask(new InitChallengeTask(), CronUtils.getCron(initDate));
startTask(new ChallengeCacheRefreshTask(), CronUtils.getCron(refreshDate));
log.info("下次锁榜时间:".concat(lockDate.toString()));
log.info("下次结算时间:".concat(settlementDate.toString()));
log.info("下次初始化时间:".concat(initDate.toString()));
log.info("下次刷新时间:".concat(refreshDate.toString()));
log.info("挑战榜定时任务启动成功");
}
}

View File

@@ -0,0 +1,35 @@
package com.lightyears.challenge.schedule;
import com.lightyears.challenge.service.IListBaseService;
import com.lightyears.challenge.service.IListInstanceService;
import com.lightyears.challenge.service.IListRankService;
import com.lightyears.challenge.util.GetBeanUtil;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.common.domain.entity.ListInstance;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
public class InitChallengeTask implements Runnable {
@Override
@Transactional
public void run() {
IListInstanceService listInstanceService = (IListInstanceService) GetBeanUtil.getBean("listInstanceServiceImpl");
IListBaseService listBaseService = (IListBaseService)GetBeanUtil.getBean("listBaseServiceImpl");
IListRankService listRankService = (IListRankService) GetBeanUtil.getBean("listRankServiceImpl");
List<ListBase> listBases = listBaseService.list();
List<ListInstance> instances = new ArrayList<>();
if(!CollectionUtils.isEmpty(listBases)){
for (ListBase base : listBases) {
ListInstance instance = listInstanceService.saveInstanceByBase(base);
instances.add(instance);
for (int i = 0; i < instance.getMaxPlayerNum(); i++) {
listRankService.saveRankByInstance(instance.getId(), i+1);
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
package com.lightyears.challenge.schedule;
import com.lightyears.challenge.init.ChallengeDataInit;
import com.lightyears.challenge.util.GetBeanUtil;
public class RefreshInstanceListTask implements Runnable{
@Override
public void run() {
ChallengeDataInit challengeDataInit = (ChallengeDataInit) GetBeanUtil.getBean("challengeDataInit");
challengeDataInit.initInstance();
}
}

View File

@@ -0,0 +1,13 @@
package com.lightyears.challenge.service;
import com.lightyears.common.domain.dto.ResModeBase;
public interface IChallengeService {
ResModeBase getList();
ResModeBase rankList(Integer pageIndex, Integer pageSize, Integer id);
ResModeBase challengeDataSubmit(Integer instanceId, Integer rank, String gameData, Integer challengeTime, Integer ownerId, Integer myId, String myName);
ResModeBase playerAssert(Integer playerId);
ResModeBase admissionTicket(Integer instanceId, Integer rank, Integer gold, Integer type, String remark, Integer playerId);
ResModeBase getPlayerRankInfo(Integer instanceId, Integer playerId);
void clearRankByInstancePlayerId(Integer instanceId, Integer playerId, Integer rankNum);
}

View File

@@ -0,0 +1,9 @@
package com.lightyears.challenge.service;
import com.lightyears.common.domain.dto.ResModeBase;
public interface IGameSystemService {
ResModeBase pushGold(Integer userId, int gold, int type, String remark);
}

View File

@@ -0,0 +1,16 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.entity.ListBase;
/**
* <p>
* 服务类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
public interface IListBaseService extends IService<ListBase> {
}

View File

@@ -0,0 +1,18 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.common.domain.entity.ListInstance;
/**
* <p>
* 服务类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
public interface IListInstanceService extends IService<ListInstance> {
ListInstance saveInstanceByBase(ListBase base);
}

View File

@@ -0,0 +1,24 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.entity.ListRank;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
public interface IListRankService extends IService<ListRank> {
ListRank saveRankByInstance(Integer instanceId, Integer rank);
int initRank(Integer instanceId,Integer playerId);
int updateRankInfo(Integer instanceId, Integer rank, String gameData, Integer challengeTime, Integer playerId, String playerName);
ListRankDto getRankByInsRank(Integer instanceId, Integer rank);
List<ListRankDto> getRankList(Integer instanceId);
List<ListRankDto> getPlayerRankInfo(Integer instanceId, Integer playerId);
}

View File

@@ -0,0 +1,15 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.entity.Log;
/**
* <p>
* 游戏 完成记录 表 游戏难度1 - 普通 2 困难 3 大师 服务类
* </p>
*
* @author hellor
* @since 2022-03-09
*/
public interface ILogService extends IService<Log> {
}

View File

@@ -0,0 +1,16 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.entity.Notice;
/**
* <p>
* 服务类
* </p>
*
* @author hellor
* @since 2022-03-18
*/
public interface INoticeService extends IService<Notice> {
}

View File

@@ -0,0 +1,33 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.dto.SimplePlayerAssert;
import com.lightyears.common.domain.entity.PlayerAssets;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
public interface IPlayerAssetsService extends IService<PlayerAssets> {
/**
* 添加金币
* @param id id
* @param gold 增加后的金币
*/
Integer addGold(int id, int gold);
/**
* 扣除金币
* @param id id
* @param gold 需要扣减的金币
*/
Integer reduceGold(int id, int gold);
List<SimplePlayerAssert> getPlayerAssets(int playerId);
}

View File

@@ -0,0 +1,16 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.entity.Player;
/**
* <p>
* 扫雷玩家表 服务类
* </p>
*
* @author hellor
* @since 2022-03-09
*/
public interface IPlayerService extends IService<Player> {
}

View File

@@ -0,0 +1,16 @@
package com.lightyears.challenge.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lightyears.common.domain.entity.Record;
/**
* <p>
* 游戏存档 服务类
* </p>
*
* @author hellor
* @since 2022-03-09
*/
public interface IRecordService extends IService<Record> {
}

View File

@@ -0,0 +1,231 @@
package com.lightyears.challenge.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.lightyears.challenge.dao.AssertLogMapper;
import com.lightyears.challenge.dao.ListInstanceMapper;
import com.lightyears.common.domain.dto.*;
import com.lightyears.common.domain.entity.AssertLog;
import com.lightyears.common.domain.entity.ListInstance;
import com.lightyears.common.domain.entity.PlayerAssets;
import com.lightyears.common.domain.enums.MessageEnum;
import com.lightyears.challenge.init.ChallengeDataInit;
import com.lightyears.challenge.service.IChallengeService;
import com.lightyears.challenge.service.IListRankService;
import com.lightyears.challenge.service.IPlayerAssetsService;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.ResultUtil;
import com.lightyears.challenge.util.StaticUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@Validated
@Service("challengeServiceImpl")
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class ChallengeServiceImpl implements IChallengeService {
private final RedisCache redisCache;
private final ListInstanceMapper listInstanceMapper;
private final IListRankService listRankServiceImpl;
private final ChallengeDataInit challengeDataInit;
private final RocketMQTemplate rocketMQTemplate;
private final AssertLogMapper assertLogMapper;
private final IPlayerAssetsService playerAssetsService;
@Override
public ResModeBase getList() {
List<ListInstanceDto> dtos = this.redisCache.getCacheObject(StaticUtil.CHALLENGE_INSTANCE);
if(CollectionUtils.isEmpty(dtos)) {
// 如果缓存无,查询数据库
dtos = challengeDataInit.initInstance();
}
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), dtos);
}
@Override
public ResModeBase rankList(Integer pageIndex, Integer pageSize, Integer id) {
Long total = redisCache.lGetListSize(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(id.toString()));
// 计算当前需要显示的数据下标起始值
int startIndex = (pageIndex - 1) * pageSize;
int endIndex = Math.min(startIndex + pageSize,total.intValue()) - 1;
// 缓存中读取对应实例榜的排名数据
List<Object> objectList = redisCache.lGet(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(id.toString()), startIndex, endIndex);
List<ListRankDto> listRankDtos = new ArrayList<>();
objectList.stream().forEach(item -> {
String json = JSONObject.toJSONString(item) ;
listRankDtos.add(JSON.parseObject(json, ListRankDto.class));
});
if (CollectionUtils.isEmpty(listRankDtos)) {
return ResultUtil.result(MessageEnum.ADD_ERROR.getCode(), "暂无该排行排名数据");
}
// 创建Page类
Page page = new Page(pageIndex, pageSize);
// 为Page类中的total属性赋值
page.setTotal(total);
// 从链表中截取需要显示的子链表并加入到Page
page.addAll(listRankDtos);
// 以Page创建PageInfo
PageInfo<ListRankDto> pageInfo = new PageInfo<ListRankDto>(page);
pageInfo.getList().stream().forEach(rankDto -> {
rankDto.setGameData(null);
});
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), pageInfo);
}
@Override
@Transactional
public ResModeBase challengeDataSubmit(Integer instanceId, Integer rank, String gameData, Integer challengeTime, Integer ownerId, Integer myId, String myName){
Integer code = 2;
ListRankDto rankDto;
ListInstance listInstance = listInstanceMapper.selectById(instanceId);
// 挑战榜不存在或者挑战榜不为开启状态
if (ObjectUtils.isEmpty(listInstance) || listInstance.getStatus() != 1){
return ResultUtil.result(MessageEnum.ERROR.getCode(), "提交失败,挑战榜已关闭");
}
/**
* TODO:
* 1.获取指定榜单与名次的listRank
* 2.比较对局时间判断是否挑战成功
* 挑战成功则写入信息到挑战榜返回1.挑战成功;
* 挑战失败则判断挑战榜主id是否是原挑战榜主id是则返回2.挑战失败;
* 否则返回 3.已被其他人抢先挑战成功)
*/
// 获取指定榜单与名次的listRank
Object obj = redisCache.lGetIndex(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(instanceId.toString()), rank-1);
if(obj == null){
rankDto= listRankServiceImpl.getRankByInsRank(instanceId, rank);
if(ObjectUtils.isEmpty(rankDto)){
log.error("未查询到挑战的排名信息");
return ResultUtil.result(MessageEnum.ERROR.getCode(), "未查询到挑战的排名信息");
}
} else {
String json = JSONObject.toJSONString(obj) ;
rankDto = JSON.parseObject(json, ListRankDto.class);
}
if(rankDto.getChallengeTime() == null || challengeTime < rankDto.getChallengeTime()){
RankDataDto rankDataDto = RankDataDto.builder().rankDto(rankDto).instanceId(instanceId).rankNum(rank).gameData(gameData).challengeTime(challengeTime).myId(myId).myName(myName).build();
code = 1;
SendCallback callback = new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("消息已成功发送");
}
@Override
public void onException(Throwable throwable) {
log.info("消息发送异常,发送失败");
}
};
rocketMQTemplate.asyncSend("rankUpdate:submit",rankDataDto,callback);
} else {
// 挑战的榜主与现在的榜主是否是同一用户
if (!rankDto.getPlayerId().equals(ownerId) && ownerId != -1) {
code = 3;
}
}
// 移除正在挑战的信息
redisCache.deleteObject(StaticUtil.CHALLENGE_ONLINE_USER.concat(instanceId.toString()).concat(":".concat(rank.toString()).concat(":".concat(myId.toString()))));
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), code);
}
@Override
public ResModeBase admissionTicket(Integer instanceId, Integer rank, Integer gold, Integer type, String remark, Integer playerId) {
ListInstance instance = listInstanceMapper.selectOne(new QueryWrapper<ListInstance>().eq("id", instanceId).eq("status", 1));
if(ObjectUtils.isEmpty(instance)){
log.error("未查询到挑战榜信息挑战榜实例id".concat(instanceId.toString()));
return ResultUtil.result(MessageEnum.ERROR.getCode(), "挑战榜已关闭!");
}
Object obj = redisCache.lGetIndex(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(instanceId.toString()), rank-1);
if(obj == null){
log.error("未查询到挑战的排名信息");
return ResultUtil.result(MessageEnum.ERROR.getCode(), "未查询到挑战的排名信息");
}
Long time = System.currentTimeMillis() / 1000;
try{
PlayerAssets playerAssets = playerAssetsService.getOne(new LambdaQueryWrapper<PlayerAssets>().eq(PlayerAssets::getPlayerId, playerId).eq(PlayerAssets::getType, type).orderByDesc(PlayerAssets::getId).last("limit 1"));
if(playerAssets == null){
log.error("未查询到玩家资产信息玩家id".concat(playerId.toString()));
return ResultUtil.result(MessageEnum.ERROR.getCode(), "玩家资产信息不存在!");
}
// 扣除玩家指定货币
playerAssetsService.reduceGold(playerAssets.getId(), gold);
//3 写入变化记录
assertLogMapper.insert(AssertLog.builder().playerId(playerId).createDate(new Date()).assertChangeNum(-gold).assertType(type).remark(remark).build());
ListPoolChangeDto dto = ListPoolChangeDto.builder().rank(rank).userId(playerId).instanceId(instanceId).gold(gold).type(type).remark(remark).build();
SendCallback callback = new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("消息已成功发送");
}
@Override
public void onException(Throwable throwable) {
log.error("发送异常", throwable);
log.info("消息发送异常,发送失败");
}
};
rocketMQTemplate.asyncSend("admissionTicket:submit",dto,callback);
// 写入正在挑战的人 设置最长40分钟
redisCache.setCacheObject(StaticUtil.CHALLENGE_ONLINE_USER.concat(instanceId.toString()).concat(":".concat(rank.toString()).concat(":".concat(playerId.toString()))), time.toString(), 40, TimeUnit.MINUTES);
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), "操作成功");
}catch (Exception ex){
log.error("报名失败,挑战扣费失败!", ex);
return ResultUtil.result(MessageEnum.ERROR.getCode(), MessageEnum.SUCCESS.getMessage(), "报名失败,挑战扣费失败!");
}
}
@Override
public ResModeBase playerAssert(Integer playerId) {
List<SimplePlayerAssert> assets = playerAssetsService.getPlayerAssets(playerId);
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), assets);
}
@Override
public ResModeBase getPlayerRankInfo(Integer instanceId, Integer playerId) {
List<ListRankDto> dtos = listRankServiceImpl.getPlayerRankInfo(instanceId, playerId);
ListRankDto dto = null;
if (!CollectionUtils.isEmpty(dtos)){
dto = dtos.get(0);
dto.setGameData(null);
}
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), dto);
}
@Override
public void clearRankByInstancePlayerId(Integer instanceId, Integer playerId, Integer rankNum){
int i = listRankServiceImpl.initRank(instanceId, playerId);
ListRankDto dto = redisCache.getCacheObject(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(instanceId.toString()).concat(":".concat(rankNum.toString())));
if(dto != null && playerId == dto.getPlayerId()){
dto.setChallengeTime(null);
dto.setPlayerId(null);
dto.setPlayerName(null);
dto.setGameData(null);
redisCache.setCacheObject(StaticUtil.CHALLENGE_INSTANCE_RANK_DETAIL.concat(dto.getInstanceId().toString()).concat(":".concat(dto.getRankNum().toString())), dto);
}
if(i > 0){
// 刷新榜单
challengeDataInit.initranks(instanceId);
}
}
}

View File

@@ -0,0 +1,72 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import com.lightyears.challenge.dao.*;
import com.lightyears.common.domain.dto.ResModeBase;
import com.lightyears.common.domain.entity.AssertLog;
import com.lightyears.common.domain.entity.PlayerAssets;
import com.lightyears.common.domain.enums.MessageEnum;
import com.lightyears.challenge.service.IGameSystemService;
import com.lightyears.challenge.service.ILogService;
import com.lightyears.challenge.service.IPlayerAssetsService;
import com.lightyears.challenge.util.RedisCache;
import com.lightyears.challenge.util.ResultUtil;
import com.lightyears.challenge.util.StaticUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
@Slf4j
@Service("gameSystemServiceImpl")
public class GameSystemServiceImpl implements IGameSystemService {
@Resource
private PlayerMapper playerMapper;
@Resource
private RecordMapper recordMapper;
@Resource
private ILogService logService;
@Resource
private RedisCache redisCache;
@Resource
private IPlayerAssetsService playerAssetsService;
@Resource
private AssertLogMapper assertLogMapper;
@Resource
private ListRankMapper listRankMapper;
@Resource
private NoticeMapper noticeMapper;
@Resource
private IGameSystemService gameSystemService;
Interner<String> pool = Interners.newWeakInterner();
private static final int AssetLimit = 999999;
@Override
@Transactional
public ResModeBase pushGold(Integer userId, int gold, int type, String remark) {
//1. 查询金额, 设置资产上限
PlayerAssets playerAssets = playerAssetsService.getOne(new QueryWrapper<PlayerAssets>().eq("player_id", userId).eq("type", type).last("limit 1"));
Integer playerAssetsNumber = playerAssets == null? 0 : playerAssets.getNumber();
int nowGold = Math.min(playerAssetsNumber +gold , AssetLimit);
// 2.写入改变数量
if (ObjectUtils.isEmpty(playerAssets)) {
playerAssetsService.save(PlayerAssets.builder().playerId(userId).type(type).number(nowGold).version(0L).build());
} else {
playerAssetsService.addGold(playerAssets.getId(), nowGold - playerAssetsNumber);
}
//3 写入变化记录
assertLogMapper.insert(AssertLog.builder().playerId(userId).createDate(new Date()).assertChangeNum(nowGold - playerAssetsNumber).assertType(type).remark(remark).build());
return ResultUtil.result(MessageEnum.SUCCESS.getCode(), MessageEnum.SUCCESS.getMessage(), nowGold);
}
}

View File

@@ -0,0 +1,20 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.ListBaseMapper;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.challenge.service.IListBaseService;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Service(value = "listBaseServiceImpl")
public class ListBaseServiceImpl extends ServiceImpl<ListBaseMapper, ListBase> implements IListBaseService {
}

View File

@@ -0,0 +1,51 @@
package com.lightyears.challenge.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.ListInstanceMapper;
import com.lightyears.common.domain.entity.ListBase;
import com.lightyears.common.domain.entity.ListInstance;
import com.lightyears.challenge.service.IListInstanceService;
import org.springframework.stereotype.Service;
import java.util.Date;
/**
* <p>
* 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Service(value = "listInstanceServiceImpl")
public class ListInstanceServiceImpl extends ServiceImpl<ListInstanceMapper, ListInstance> implements IListInstanceService {
@Override
public ListInstance saveInstanceByBase(ListBase base){
String startDate = DateUtil.now();
Date date = DateUtil.parse(startDate);
// 7 周日锁榜 周一晚上结算
DateTime endDate = DateUtil.offsetDay(date, base.getSettlementDay() - 1);
String startDateStr = DateUtil.format(date, "yyyy-MM-dd");
String endDateStr = DateUtil.format(endDate, "yyyy-MM-dd");
ListInstance instance = ListInstance.builder().listId(base.getId())
.listDate(startDateStr.concat("~".concat(endDateStr)))
.ticketsNum(base.getTicketsNum())
.assetsType(base.getAssetsType())
.createDate(new Date())
.mapSize(base.getMapSize())
.status(1)
.entryThreshold(base.getEntryThreshold())
.awardSize(base.getInitAwardSize())
.inPondFee(base.getInPondFee())
.maxPlayerNum(base.getMaxPlayerNum())
.mineNumSection(base.getMineNumSection())
.name(base.getName())
.distribution(base.getDistribution())
.remark("系统自动生成").build();
this.baseMapper.insert(instance);
return instance;
}
}

View File

@@ -0,0 +1,66 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.ListRankMapper;
import com.lightyears.common.domain.dto.ListRankDto;
import com.lightyears.common.domain.entity.ListRank;
import com.lightyears.challenge.service.IListRankService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Service(value = "listRankServiceImpl")
public class ListRankServiceImpl extends ServiceImpl<ListRankMapper, ListRank> implements IListRankService {
@Resource
private ListRankMapper listRankMapper;
@Override
public ListRank saveRankByInstance(Integer instanceId, Integer rank){
ListRank data = ListRank.builder().rankNum(rank).instanceId(instanceId).createDate(new Date()).build();
listRankMapper.insert(data);
return data;
}
@Override
public int initRank(Integer instanceId,Integer playerId){
int num = listRankMapper.initRank(instanceId, playerId);
return num;
}
@Override
@Transactional
public int updateRankInfo(Integer instanceId, Integer rank, String gameData, Integer challengeTime, Integer playerId, String playerName) {
ListRank rankInfo = ListRank.builder().instanceId(instanceId).rankNum(rank).gameData(gameData).challengeTime(challengeTime).playerId(playerId).playerName(playerName).updateDate(new Date()).build();
return listRankMapper.update(rankInfo, new UpdateWrapper<ListRank>().eq("instance_id", instanceId).eq("rank_num", rank));
}
@Override
public ListRankDto getRankByInsRank(Integer instanceId, Integer rank){
return listRankMapper.getRankByInsRank(instanceId, rank);
}
@Override
public List<ListRankDto> getRankList(Integer instanceId) {
return listRankMapper.getRankList(instanceId, null, null);
}
@Override
public List<ListRankDto> getPlayerRankInfo(Integer instanceId, Integer playerId){
// 只查开启中挑战榜的数据
List<ListRankDto> dtos = listRankMapper.getNewRankList(instanceId, playerId);
return dtos;
}
}

View File

@@ -0,0 +1,19 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.LogMapper;
import com.lightyears.common.domain.entity.Log;
import com.lightyears.challenge.service.ILogService;
import org.springframework.stereotype.Service;
/**
* <p>
* 游戏 完成记录 表 游戏难度1 - 普通 2 困难 3 大师 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-09
*/
@Service
public class LogServiceImpl extends ServiceImpl<LogMapper, Log> implements ILogService {
}

View File

@@ -0,0 +1,20 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.NoticeMapper;
import com.lightyears.common.domain.entity.Notice;
import com.lightyears.challenge.service.INoticeService;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-18
*/
@Service(value = "noticeServiceImpl")
public class NoticeServiceImpl extends ServiceImpl<NoticeMapper, Notice> implements INoticeService {
}

View File

@@ -0,0 +1,76 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.PlayerAssetsMapper;
import com.lightyears.common.domain.dto.SimplePlayerAssert;
import com.lightyears.common.domain.entity.PlayerAssets;
import com.lightyears.common.domain.enums.MessageEnum;
import com.lightyears.challenge.exception.BussinessException;
import com.lightyears.challenge.service.IPlayerAssetsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-16
*/
@Slf4j
@Service
public class PlayerAssetsServiceImpl extends ServiceImpl<PlayerAssetsMapper, PlayerAssets> implements IPlayerAssetsService {
@Override
public Integer addGold(int id, int gold){
PlayerAssets playerAssets = baseMapper.selectById(id);
if(ObjectUtils.isEmpty(playerAssets)){
log.error("减少金币异常------------没有查到资产信息");
throw new BussinessException(MessageEnum.ERROR.getCode(), "减少金币异常------------没有查到资产信息!");
}
int result = 0;
try{
result = baseMapper.addGold(playerAssets.getId(), gold, playerAssets.getVersion());
}catch (Exception ex){
log.error("写入金币异常", ex);
throw new BussinessException(MessageEnum.ERROR.getCode(), "写入金币异常!");
}
if(result < 1){
this.addGold(id, gold);
}
return gold;
}
@Override
public Integer reduceGold(int id, int gold){
PlayerAssets playerAssets = baseMapper.selectById(id);
if(ObjectUtils.isEmpty(playerAssets)){
log.error("减少金币异常------------没有查到资产信息");
throw new BussinessException(MessageEnum.ERROR.getCode(), "减少金币异常------------没有查到资产信息!");
}
int result = 0;
if(playerAssets.getNumber() < gold){
return -999;
}
try {
result = baseMapper.reduceGold(playerAssets.getId(), gold, playerAssets.getVersion());
} catch (Exception ex){
log.error("写入金币异常", ex);
throw new BussinessException(MessageEnum.ERROR.getCode(), "写入金币异常!");
}
if(result < 1){
this.reduceGold(id, gold);
}
return playerAssets.getNumber() - gold;
}
@Override
public List<SimplePlayerAssert> getPlayerAssets(int playerId){
return baseMapper.getPlayerAssets(playerId);
}
}

View File

@@ -0,0 +1,20 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.PlayerMapper;
import com.lightyears.challenge.service.IPlayerService;
import com.lightyears.common.domain.entity.Player;
import org.springframework.stereotype.Service;
/**
* <p>
* 扫雷玩家表 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-09
*/
@Service
public class PlayerServiceImpl extends ServiceImpl<PlayerMapper, Player> implements IPlayerService {
}

View File

@@ -0,0 +1,20 @@
package com.lightyears.challenge.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lightyears.challenge.dao.RecordMapper;
import com.lightyears.common.domain.entity.Record;
import com.lightyears.challenge.service.IRecordService;
import org.springframework.stereotype.Service;
/**
* <p>
* 游戏存档 服务实现类
* </p>
*
* @author hellor
* @since 2022-03-09
*/
@Service
public class RecordServiceImpl extends ServiceImpl<RecordMapper, Record> implements IRecordService {
}

View File

@@ -0,0 +1,37 @@
package com.lightyears.challenge.util;
import cn.hutool.core.date.DateTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
/**
* 日期转换cron表达式
*/
public class CronUtils {
/***
* 功能描述日期转换cron表达式
* @param dateStr
* @return
*/
public static String formatDateByPattern(String dateStr) {
String formatTimeStr = null;
if (Objects.nonNull(dateStr)) {
LocalDateTime time = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
formatTimeStr = time.format(DateTimeFormatter.ofPattern("ss mm HH dd MM ?"));
}
return formatTimeStr;
}
/***
* @param dateTime : 时间点
* @return
*/
public static String getCron(DateTime dateTime) {
return formatDateByPattern(dateTime.toString());
}
}

View File

@@ -0,0 +1,26 @@
package com.lightyears.challenge.util;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class GetBeanUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext context) {
GetBeanUtil.applicationContext = context;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static Object getBean(Class classObj) {
return applicationContext.getBean(classObj);
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}

View File

@@ -0,0 +1,51 @@
package com.lightyears.challenge.util;
import java.security.MessageDigest;
/**
* Created by tanhao on 2019/3/18.
*/
public class MD5Utils {
private static final String hexDigIts[] = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
/**
* MD5加密
* @param origin 字符
* @param charsetname 编码 UTF-8
* @return
*/
public static String MD5Encode(String origin, String charsetname){
String resultString = null;
try{
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if(null == charsetname || "".equals(charsetname)){
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
}else{
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
}
}catch (Exception e){
}
return resultString;
}
public static String byteArrayToHexString(byte b[]){
StringBuffer resultSb = new StringBuffer();
for(int i = 0; i < b.length; i++){
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
public static String byteToHexString(byte b){
int n = b;
if(n < 0){
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigIts[d1] + hexDigIts[d2];
}
}

View File

@@ -0,0 +1,383 @@
package com.lightyears.challenge.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* spring redis 工具类
**/
@Component
public class RedisCache {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 判断key是否存在
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 缓存基本的对象Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
/**
* 删除指定前缀的缓存
* @param key
* @return
*/
public Long deleteByPrefix(final String key) {
Set<String> keys = redisTemplate.keys(key.concat("*"));
return redisTemplate.delete(keys);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时 0 表头1 第二个元素依次类推index<0时-1表尾-2倒数第二个元素依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSetAll(String key, List<? extends Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> long setCacheSet(final String key, final Set<T> dataSet) {
Long count = redisTemplate.opsForSet().add(key, dataSet);
return count == null ? 0 : count;
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public <T> Set<T> getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
}

View File

@@ -0,0 +1,44 @@
package com.lightyears.challenge.util;
import cn.hutool.crypto.digest.MD5;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lightyears.common.domain.dto.ResModeBase;
import com.lightyears.common.domain.enums.MessageEnum;
import lombok.extern.slf4j.Slf4j;
/**
* 返回 数据 指定数据结构
*
* @author Melody
*/
@Slf4j
public class ResultUtil {
public static final ObjectMapper mapper = new ObjectMapper();
public static ResModeBase result(int code, String mes) {
return result(code, mes, null);
}
public static ResModeBase result(int code, String mes, Object data) {
String key = "";
String dataStr = "";
if(data == null){
key = MD5.create().digestHex(MD5.create().digestHex(StaticUtil.PRIVATE_KEY));
} else {
try {
if (data instanceof String){
dataStr = data.toString();
} else {
dataStr = mapper.writeValueAsString(data);
}
key = MD5.create().digestHex(MD5.create().digestHex(dataStr.concat(StaticUtil.PRIVATE_KEY)));
}catch (JsonProcessingException ex){
log.error("json解析错误", ex);
return new ResModeBase(MessageEnum.SERVER_ERROR.getCode(), MessageEnum.SERVER_ERROR.getMessage(), key, null);
}
}
return new ResModeBase(code, mes, key, data);
}
}

View File

@@ -0,0 +1,46 @@
package com.lightyears.challenge.util;
import java.util.concurrent.ScheduledFuture;
/**
* 任务执行的包装类
*/
public class ScheduledFutureHolder {
private ScheduledFuture<?> scheduledFuture;
private Class<? extends Runnable> runnableClass;
private String corn;
public ScheduledFuture<?> getScheduledFuture() {
return scheduledFuture;
}
public void setScheduledFuture(ScheduledFuture<?> scheduledFuture) {
this.scheduledFuture = scheduledFuture;
}
public Class<? extends Runnable> getRunnableClass() {
return runnableClass;
}
public void setRunnableClass(Class<? extends Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public String getCorn() {
return corn;
}
public void setCorn(String corn) {
this.corn = corn;
}
@Override
public String toString() {
return "ScheduledFutureHolder{" +
"scheduledFuture=" + scheduledFuture +
", runnableClass=" + runnableClass +
", corn='" + corn + '\'' +
'}';
}
}

View File

@@ -0,0 +1,50 @@
package com.lightyears.challenge.util;
import java.util.List;
import java.util.Map;
/**
* 文 件 名 : 特殊处理工具
* 创 建 人HL
* 日 期2019-8-12
* 修 改 人HL
* 日 期2019-8-12
* 描 述: 分页、
* 版 本 号2.0
*/
public class SpecialTool<T> {
public static SpecialTool specialTool = new SpecialTool();
//时间格式
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
//集合判断是否为空
public boolean ifGather(Object o) {
if ((o instanceof List && null == o) || (o instanceof Map && null == o)) {
return true;
}
return false;
}
//字符串判断是否为空
public boolean isEmpty(String s) {
if (null == s || s.equals("")) {
return true;
}
return false;
}
/**
* 将字符串的首字母转大写
* @param str 需要转换的字符串
* @return
*/
private static String captureName(String str) {
// 进行字母的ascii编码前移效率要高于截取字符串进行转换的操作
char[] cs=str.toCharArray();
cs[0]-=32;
return String.valueOf(cs);
}
}

View File

@@ -0,0 +1,56 @@
package com.lightyears.challenge.util;
import java.util.HashMap;
import java.util.Map;
/**
* 静态工具栏 :目前数据较小 且又想减少服务器压力,特建此类 做静态缓存
*/
public class StaticUtil {
// ------------------------系统类-----------------------
//金币极限操作 防范静态变量
public static Map<String,Boolean> goldSyn = new HashMap<String,Boolean>();
// 数据加解密盐
public static final String PRIVATE_KEY = "123144123";
// ---------------------------------redis -----------------------------------------
// 在线用户信息
public static final String ONLINE_USER_PUBLIC_KEY="mineClearance:onlineUser:";
// 在线用户TOKEN
public static final String ONLINE_USER_TOKEN="mineClearance:onlineToken:";
// 排行榜
public static final String RANK_LIST = "mineClearance:rankList:";
// 闯关排行
public static final String CLEARANCE_RANK_LIST = "mineClearance:clearanceList";
// 挑战榜所有缓存前缀
public static final String CHALLENGE="mineClearance:challenge:*";
// 开启中的挑战榜信息
public static final String CHALLENGE_INSTANCE="mineClearance:challenge:instance:";
// 开启中的挑战榜排名信息 mineClearance:challenge:rank:instance
public static final String CHALLENGE_INSTANCE_RANK="mineClearance:challenge:rank:";
// 开启中的挑战榜每个排名的信息 mineClearance:challenge:rankDetail:instance:rank
public static final String CHALLENGE_INSTANCE_RANK_DETAIL="mineClearance:challenge:rankDetail:";
// 正在挑战的用户mineClearance:challenge:onlineUser: instanceId : rank: playerId
public static final String CHALLENGE_ONLINE_USER="mineClearance:challenge:onlineUser:";
// -------------------------------------公告类------------------------------------------
// 挑战榜结算 奖励发放备注
public static final String CHALLENGE_REMARK = "你在挑战榜:<b>%s</b> 的名次为:<b>%s</b>, 获得<color=orange>%s</color> %s";
// 挑战榜奖励发放公告 标题
public static final String CHALLENGE_NOTICE_TITLE = "挑战榜奖励发放";
// 闯关信息提示 已有多少人到达
public static final String CLEARANCE_LOG_TEXT_HAVE = "当前已有<b> %s </b>的玩家到达这一层!";
// 闯关信息提示 已超过多少人
public static final String CLEARANCE_LOG_TEXT_OVER = "你已超过<b> %s </b>的玩家!";
//----------------------------挑战榜task--------------------------
// 锁榜时间
public static final String LOCKE_TIME = " 23:00:00";
// 结算时间
public static final String SETTLEMENT_TIME = " 23:45:00";
// 挑战榜初始化时间
public static final String CHALLENGE_INIT_TIME = " 1:00:00";
// 挑战榜redis刷新时间
public static final String CHALLENGE_REFRESH_TIME = " 1:05:00";
}

View File

@@ -0,0 +1,67 @@
qbs-switch:
swagger-open: true #swagger开关(true:打开, false:关闭)
spring:
application:
name: mine-clearance-challenge
main:
allow-bean-definition-overriding: true
allow-circular-references: true
# 全局配置响应日期格式和时区为东八区,解决日期类型返回前端少八个小时的问题
jackson:
time-zone: GMT+8
datasource:
username: root
password: 43626546
url: jdbc:mysql://42.192.76.87:3306/saolei_v2_db?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 20
max-active: 80
min-idle: 20
max-wait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictabkeIdleTimeMillis: 1800000
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters去掉后监控界面sql无法统计。wall用于防火墙
filters: stat,wall
# cloud:
# nacos:
# discovery:
# server-addr: localhost:8848
redis:
# Redis服务器地址
host: localhost
# Redis数据库索引默认为0
database: 0
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password: 123456
# 连接超时时间
timeout: 1000ms
lettuce:
pool:
# 连接池最大连接数
max-active: 8
# 连接池最大空闲连接数
max-idle: 8
# 连接池最小空闲连接数
min-idle: 0
# 连接池最大阻塞等待时间,负值表示没有限制
max-wait: -1ms
mybatis-plus:
mapper-locations: classpath*:mapper/**/*Mapper.xml
type-aliases-package: com.lightyears.common.domain
global-config:
banner: false
db-config:
id-type: input
configuration:
# 控制台SQL日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: false

View File

@@ -0,0 +1,73 @@
qbs-switch:
swagger-open: false #swagger开关(true:打开, false:关闭)
spring:
application:
name: mine-clearance-challenge
main:
allow-bean-definition-overriding: true
allow-circular-references: true
# 全局配置响应日期格式和时区为东八区,解决日期类型返回前端少八个小时的问题
jackson:
time-zone: GMT+8
datasource:
username: root
password: 1476346288@mysql
#password: 1813547935mysql
# 挑战
url: jdbc:mysql://172.26.101.6:3986/saolei_v2_db?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull
# 本地
# url: jdbc:mysql://39.106.21.14:3986/saolei_v2_db?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 20
max-active: 80
min-idle: 20
max-wait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictabkeIdleTimeMillis: 1800000
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters去掉后监控界面sql无法统计。wall用于防火墙
filters: stat,wall
# cloud:
# nacos:
# discovery:
# server-addr: localhost:8848
redis:
# Redis服务器地址
# host: localhost
host: 172.26.101.6
# Redis数据库索引默认为0
database: 0
# Redis服务器连接端口
port: 7963
# Redis服务器连接密码默认为空
password: 1476346288@redis
#password: 123456
lettuce:
pool:
# 连接池最大连接数
max-active: 8
# 连接池最大空闲连接数
max-idle: 8
# 连接池最小空闲连接数
min-idle: 0
# 连接池最大阻塞等待时间,负值表示没有限制
# max-wait: -1ms
max-wait: -1ms
shutdown-timeout: 100ms
mybatis-plus:
mapper-locations: classpath*:mapper/**/*Mapper.xml
type-aliases-package: com.lightyears.common.domain
global-config:
banner: false
db-config:
id-type: input
configuration:
# 控制台SQL日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: false

View File

@@ -0,0 +1,21 @@
server:
port: 18632
tomcat:
uri-encoding: UTF-8
#最大等待连接数
accept-count: 1000
#最大线程数
server.tomcat.max-threads: 800
#最小工作线程数
server.tomcat.min-spare-threads: 100
logging:
config: classpath:log.xml
rocketmq:
name-server: localhost:9876
producer:
group: mineClearance
spring:
profiles:
active: prod
appconfig:
version: 197.0

View File

@@ -0,0 +1,72 @@
<configuration>
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
<!-- appender是configuration的子节点是负责写日志的组件。 -->
<!-- ConsoleAppender把日志输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %p (%file:%line\)- %m%n</pattern>
<!-- 控制台也要使用UTF-8不要使用GBK否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是sys.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过1KB时对当前日志进行分割 重命名-->
<appender name="syslog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/challenge/sys.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名log/sys.2022-3-09.0.log -->
<fileNamePattern>logs/challenge/sys.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<!-- 记录日志的编码 -->
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<!-- rocketmq日志 -->
<appender name="RocketmqClientAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/rocketmq_client.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/rocketmq_client.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--保留时间,单位:天-->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0} %X{ServiceId} - %m%n</pattern>
</encoder>
</appender>
<!-- 控制台输出日志级别 -->
<root level="info">
<appender-ref ref="STDOUT" />
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- com.lightyears为根包也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
<!-- 级别依次为【从高到低】FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<logger name="com.lightyears.challenge" level="DEBUG">
<appender-ref ref="syslog" />
</logger>
<!-- Rocketmq日志配置 -->
<logger name="RocketmqClient" additivity="false">
<level value="ERROR" />
<appender-ref ref="RocketmqClientAppender"/>
</logger>
</configuration>

View File

@@ -0,0 +1,5 @@
<?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.lightyears.challenge.dao.AssertLogMapper">
</mapper>

View File

@@ -0,0 +1,5 @@
<?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.lightyears.challenge.dao.ListBaseMapper">
</mapper>

View File

@@ -0,0 +1,32 @@
<?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.lightyears.challenge.dao.ListInstanceMapper">
<update id="updateInstanceAwardSize">
UPDATE sl_list_instance
SET award_size = award_size + #{awardSize}
where id = #{instanceId}
and assets_type = #{assetsType}
</update>
<select id="getListInstances" resultType="com.lightyears.common.domain.dto.ListInstanceDto">
SELECT
id,
list_id as listId,
`name`,
list_date AS listDate,
mine_num_section AS mineNumSection,
map_size AS mapSize,
in_pond_fee AS inPondFee,
award_size AS awardSize,
entry_threshold AS entryThreshold,
`status`,
assets_type as assetsType,
tickets_num as ticketsNum,
distribution as distribution
FROM
sl_list_instance
WHERE
`status` = 1
</select>
</mapper>

View File

@@ -0,0 +1,81 @@
<?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.lightyears.challenge.dao.ListRankMapper">
<update id="initRank">
UPDATE `sl_list_rank`
SET
`player_name` = NULL,
`player_id` = NULL,
`challenge_time` = NULL,
`game_data` = NULL
WHERE
`instance_id` = ${instanceId}
and `player_id` = ${playerId}
</update>
<select id="getRankList" resultType="com.lightyears.common.domain.dto.ListRankDto">
SELECT
r.id as id,
r.instance_id AS instanceId,
r.rank_num AS rankNum,
r.player_id AS playerId,
r.player_name AS playerName,
r.challenge_time AS challengeTime,
r.game_data AS gameData
FROM
sl_list_rank r,
sl_list_instance n,
sl_player sp
WHERE
n.id = r.instance_id
AND r.player_id = sp.user_id
<if test="instanceId != null and instanceId != 0">
and r.instance_id = #{instanceId}
</if>
<if test="playerId != null and playerId != 0">
and r.player_id = ${playerId}
</if>
<if test="state != null and state > -1">
and n.status = ${state}
</if>
ORDER BY
rank_num ASC
</select>
<select id="getNewRankList" resultType="com.lightyears.common.domain.dto.ListRankDto">
SELECT
r.id as id,
r.instance_id AS instanceId,
r.rank_num AS rankNum,
r.player_id AS playerId,
r.player_name AS playerName,
r.challenge_time AS challengeTime,
r.game_data AS gameData
FROM
sl_list_rank r
LEFT JOIN sl_list_instance n on n.id = r.instance_id
where
n.status in (1, 3)
<if test="instanceId != null and instanceId != 0">
and r.instance_id = #{instanceId}
</if>
<if test="playerId != null and playerId != 0">
and r.player_id = ${playerId}
</if>
ORDER BY
rank_num ASC
</select>
<select id="getRankByInsRank" resultType="com.lightyears.common.domain.dto.ListRankDto">
SELECT
id,
instance_id as instanceId,
rank_num as rankNum,
player_id AS playerId,
player_name AS playerName,
challenge_time AS challengeTime,
game_data as gameData
FROM
sl_list_rank
WHERE
instance_id = #{instanceId}
AND rank_num = #{rank}
</select>
</mapper>

View File

@@ -0,0 +1,4 @@
<?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.lightyears.challenge.dao.LogMapper">
</mapper>

View File

@@ -0,0 +1,4 @@
<?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.lightyears.challenge.dao.NoticeMapper">
</mapper>

View File

@@ -0,0 +1,14 @@
<?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.lightyears.challenge.dao.PlayerAssetsMapper">
<update id="addGold">
update sl_player_assets set number = number + #{gold}, version = version +1 where id = #{id} and version = ${version}
</update>
<update id="reduceGold">
update sl_player_assets set number = number - #{gold}, version = version +1 where id = #{id} and version = ${version}
</update>
<!-- 获取用户的资产信息 -->
<select id="getPlayerAssets" resultType="com.lightyears.common.domain.dto.SimplePlayerAssert">
select type, number from sl_player_assets where player_id = #{playerId}
</select>
</mapper>

View File

@@ -0,0 +1,5 @@
<?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.lightyears.challenge.dao.PlayerMapper">
</mapper>

View File

@@ -0,0 +1,5 @@
<?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.lightyears.challenge.dao.RecordMapper">
</mapper>