星级厨房重构-梳理解耦优化客户端接口

This commit is contained in:
2023-03-03 22:21:02 +08:00
parent 77ccea6c2c
commit b10f99c7a2
37 changed files with 1068 additions and 988 deletions

View File

@@ -19,11 +19,10 @@ import com.accompany.admin.vo.luckysea.LuckySeaActAdminRoundDetailVo;
import com.accompany.admin.vo.luckysea.LuckySeaActAdminUserDrawRecord;
import com.accompany.admin.vo.luckysea.LuckySeaActPlatformStatVo;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.service.activities.LuckySeaItemService;
import com.accompany.business.service.activities.luckySea.LuckySeaItemService;
import com.accompany.common.constant.Constant;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.enumeration.BusinessStatusCodeEnum;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.service.SysConfService;
import com.alibaba.fastjson.JSON;

View File

@@ -184,32 +184,6 @@ public class MyApiService {
actValentineCpService.settlement(now, true);
}
public void pushLuckySeaAWechat(String date) {
Date yesterday = DateTimeUtil.convertStrToDate(date, DateTimeUtil.DEFAULT_DATE_PATTERN);
Date beginTimeOfDay = DateTimeUtil.getBeginTimeOfDay(yesterday);
Date endTimeOfDay = DateTimeUtil.getEndTimeOfDay(yesterday);
List<LuckySeaRankListVo> rankList = luckySeaActMapper.listDiamondRank(0, 1, beginTimeOfDay, endTimeOfDay);
for (LuckySeaRankListVo vo: rankList){
MarkdownMessage msg = new MarkdownMessage();
msg.add(MarkdownMessage.getHeaderText(3, String.format("%s 星级厨房奖励榜榜一大佬", date)));
msg.add(MarkdownMessage.getReferenceText(String.format("平台ID [%d]", vo.getErbanNo())));
msg.add(MarkdownMessage.getReferenceText(String.format("昵称 [%s]", vo.getNick())));
msg.add(MarkdownMessage.getReferenceText(String.format("当日累计收礼钻石价值 [%d]", vo.getNum().longValue())));
enterpriseWechatPushService.pushMessageByKey(webSecurityConfig.getActivityEnterpriseWechatPushKey(), msg);
}
rankList = luckySeaActMapper.listLuckyManRank(0, 1, beginTimeOfDay, endTimeOfDay);
for (LuckySeaRankListVo vo: rankList){
MarkdownMessage msg = new MarkdownMessage();
msg.add(MarkdownMessage.getHeaderText(3, String.format("%s 星级厨房欧皇榜榜一大佬", date)));
msg.add(MarkdownMessage.getReferenceText(String.format("平台ID [%d]", vo.getErbanNo())));
msg.add(MarkdownMessage.getReferenceText(String.format("昵称 [%s]", vo.getNick())));
msg.add(MarkdownMessage.getReferenceText(String.format("当日累计收礼钻石价值 [%d]", vo.getNum().longValue())));
enterpriseWechatPushService.pushMessageByKey(webSecurityConfig.getActivityEnterpriseWechatPushKey(), msg);
}
}
public void initRegion() {
UsersExample example = new UsersExample();
example.createCriteria().andRegionIsNull();

View File

@@ -14,15 +14,14 @@ import com.accompany.admin.controller.BaseController;
import com.accompany.admin.params.LuckySeaItemSaveReqParams;
import com.accompany.admin.service.activity.LuckySeaActAdminService;
import com.accompany.admin.util.ExcelUtils;
import com.accompany.admin.vo.ChargeRecordPersonAdminVo;
import com.accompany.admin.vo.luckysea.LuckySeaActAdminRoundDetailVo;
import com.accompany.admin.vo.luckysea.LuckySeaActAdminUserDrawRecord;
import com.accompany.admin.vo.luckysea.LuckySeaActPlatformStatVo;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.service.activities.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.LuckySeaActInfoService;
import com.accompany.business.service.activities.impl.ActivitiesLuckySeaServiceImpl;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.LuckySeaActInfoService;
import com.accompany.business.service.activities.luckySea.impl.ActivitiesLuckySeaServiceImpl;
import com.accompany.business.service.api.QinniuService;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
@@ -45,7 +44,6 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
@@ -246,7 +244,7 @@ public class LuckySeaActAdminController extends BaseController {
throw new ServiceException("当前正在开奖,请等待开奖结束再修改库存");
}
Double stockValue = Double.valueOf(stock.trim());
Long stockLongValue = (long) (stockValue * ActivitiesLuckySeaServiceImpl.HANDLE_STOCK_MULTIPLE);
Long stockLongValue = stockValue.longValue() * ActivitiesLuckySeaServiceImpl.HANDLE_STOCK_MULTIPLE;
jedisService.set(RedisKey.LUCKY_SEA_ACT_STOCK.getKey(), String.valueOf(stockLongValue));
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS);
}

View File

@@ -101,16 +101,6 @@ public class MyApiController {
return new BusiResult<>(BusiStatus.SUCCESS);
}
@RequestMapping("/pushLuckySeaWechat")
@ResponseBody
public BusiResult<Void> pushLuckySeaAWechat(Long roomId, String date) {
if (null == roomId || !roomId.equals(603L)){
throw new ServiceException(BusiStatus.PARAMERROR);
}
myApiService.pushLuckySeaAWechat(date);
return new BusiResult<>(BusiStatus.SUCCESS);
}
@RequestMapping("/initRegion")
@ResponseBody
public BusiResult<Void> initRegion(Long roomId) {

View File

@@ -1195,10 +1195,6 @@ public class Constant {
* 深海奇缘活动开关配置
*/
public static final String LUCKY_SEA_SWITCH = "lucky_sea_switch";
/**
* 深海奇缘活动模式
*/
public static final String LUCKY_SEA_MODEL = "lucky_sea_model";
/**
* 深海奇缘活动模式
*/

View File

@@ -1051,8 +1051,6 @@ public enum RedisKey {
LOCK_USER_PIECE,
/** 深海奇缘活动更新用户碎片数分布式锁 **/
LOCK_LUCKY_SEA_UPDATE_PIECE,
/** 深海奇缘活动更新用户单轮消耗碎片数分布式锁 **/
LOCK_LUCKY_SEA_UPDATE_COST_PIECE,
/** 深海奇缘活动库存**/
LUCKY_SEA_ACT_STOCK,
/** 深海奇缘活动用户抽奖分布式锁 **/

View File

@@ -1,20 +1,9 @@
/*
* 文 件 名: LuckySeaUserDrawResult
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/1/5
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.model.activity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@@ -40,11 +29,9 @@ public class LuckySeaUserDrawResult {
private String roundId;
@TableField("item_type")
@ApiModelProperty("配置类型")
private Byte itemType;
@TableField("item_name")
@ApiModelProperty("配置类型")
private String itemName;
@TableField(value = "result")

View File

@@ -15,19 +15,13 @@ import com.accompany.business.service.activities.vo.LuckySeaRankListVo;
import com.accompany.business.vo.activities.LuckySeaActRoundRankUserVo;
import com.accompany.business.vo.activities.LuckySeaActRoundStatVo;
import com.accompany.business.vo.activities.LuckySeaActUserDrawItemVO;
import com.accompany.business.vo.activities.LuckySeaActUserOneRoundDrawResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* <br>接口描述:
* <br>功能详细描述:
*
* @author H1
* @date [2021/1/4]
*/
@Mapper
public interface LuckySeaActMapper {
/**
* 获取深海奇缘活动钻石榜单

View File

@@ -1,33 +0,0 @@
/*
* 文 件 名: LuckySeaActDrawParams
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/1/4
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.param.activity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <br>类描述: 深海奇缘活动抽奖请求参数
* <br>功能详细描述:
*
* @author H1
* @date [2021/1/4]
*/
@Data
@ApiModel
public class LuckySeaActDrawParams {
@ApiModelProperty(value = "选择的itemId")
private Long itemId;
@ApiModelProperty(value = "选择的数量")
private Long num;
}

View File

@@ -1,32 +0,0 @@
/*
* 文 件 名: WishStarCupAddKeyParams
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/12/7
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.param.activity;
import com.accompany.business.enums.UserActPropertyObjType;
import lombok.Builder;
import lombok.Data;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2021/12/7]
*/
@Data
@Builder
public class WishStarCupAddKeyParams {
private UserActPropertyObjType objType;
private Long uid;
private Integer keyNum;
private String deviceId;
private Long goldNum;
}

View File

@@ -14,10 +14,9 @@ import com.accompany.business.config.LuckySeaPreWarningConfig;
import com.accompany.business.dto.activity.LuckySeaBroadCastDTO;
import com.accompany.business.dto.activity.LuckySeaGoldPreWarningDTO;
import com.accompany.business.mybatismapper.activity.LuckySeaPreWarningMapper;
import com.accompany.business.service.activities.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.impl.ActivitiesLuckySeaServiceImpl;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.impl.ActivitiesLuckySeaServiceImpl;
import com.accompany.business.service.push.EnterpriseWechatPushService;
import com.accompany.common.config.SystemConfig;
import com.accompany.common.config.WebSecurityConfig;
import com.accompany.common.constant.Constant;
import com.accompany.common.push.MarkdownMessage;

View File

@@ -1,56 +0,0 @@
/*
* 文 件 名: LuckySeaActInfoServiceImpl
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2020/12/31
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities.impl;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.accompany.business.mybatismapper.activity.LuckySeaActInfoMapper;
import com.accompany.business.service.activities.LuckySeaActInfoService;
import com.accompany.common.constant.Constant;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class LuckySeaActInfoServiceImpl extends ServiceImpl<LuckySeaActInfoMapper, LuckySeaActInfo> implements LuckySeaActInfoService {
@Override
public LuckySeaActInfo getByCurrTime() {
Date currDate = new Date();
QueryWrapper<LuckySeaActInfo> wrapper = new QueryWrapper<>();
wrapper.lambda().le(LuckySeaActInfo::getStartTime, currDate).orderByDesc(LuckySeaActInfo::getCreateTime);
IPage<LuckySeaActInfo> queryPage = new Page<>(1, 1);
IPage<LuckySeaActInfo> actPageInfo = page(queryPage, wrapper);
LuckySeaActInfo info = null;
if (actPageInfo != null && !CollectionUtils.isEmpty(actPageInfo.getRecords())) {
info = actPageInfo.getRecords().get(0);
}
return info;
}
}

View File

@@ -1,31 +0,0 @@
/*
* 文 件 名: LuckySeaItemServiceImpl
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2020/12/31
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities.impl;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.mybatismapper.activity.LuckySeaItemMapper;
import com.accompany.business.service.activities.LuckySeaItemService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
@Service
@Slf4j
public class LuckySeaItemServiceImpl extends ServiceImpl<LuckySeaItemMapper, LuckySeaItem> implements LuckySeaItemService {
}

View File

@@ -1,89 +0,0 @@
/*
* 文 件 名: LuckySeaUserDrawRecordServiceImpl
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/1/4
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities.impl;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.model.activity.LuckySeaUserDrawRecord;
import com.accompany.business.mybatismapper.activity.LuckySeaUserDrawRecordMapper;
import com.accompany.business.service.activities.LuckySeaItemService;
import com.accompany.business.service.activities.LuckySeaUserDrawRecordService;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.service.common.JedisLockService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2021/1/4]
*/
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class LuckySeaUserDrawRecordServiceImpl extends ServiceImpl<LuckySeaUserDrawRecordMapper, LuckySeaUserDrawRecord>
implements LuckySeaUserDrawRecordService {
@Autowired
private LuckySeaItemService luckySeaItemService;
@Autowired
private JedisLockService jedisLockService;
@Override
public void updateUserDrawRecord(Long uid, Long roomUid, String roundId, Long itemId, Long costPieceNum) {
LuckySeaItem item = luckySeaItemService.getById(itemId);
if (null == item) {
log.error("选择的配置item不存在, itemId: " + item);
throw new ServiceException("选择的配置item不存在");
}
String lockVal = jedisLockService.lock(RedisKey.LOCK_LUCKY_SEA_UPDATE_COST_PIECE.getKey(uid.toString()));
try {
QueryWrapper<LuckySeaUserDrawRecord> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(LuckySeaUserDrawRecord::getUid, uid).eq(LuckySeaUserDrawRecord::getRoundId, roundId)
.eq(LuckySeaUserDrawRecord::getItemId, itemId);
LuckySeaUserDrawRecord record = getOne(wrapper);
log.info("更新用户单轮消耗碎片数操作前, uid:{},roundId:{},itemId:{},costPiece:{}",
uid, roundId, item, record == null ? 0 : record.getCostPriceNum());
if (record == null) {
record = new LuckySeaUserDrawRecord();
record.setUid(uid);
record.setRoomUid(roomUid);
record.setRoundId(roundId);
record.setItemId(itemId);
record.setItemName(item.getName());
record.setItemUrl(item.getImgUrl());
record.setItemMultiple(item.getMultiple());
record.setCostPriceNum(costPieceNum);
record.setDrawStatus(Constant.status.invalid);
record.setCreateTime(new Date());
} else {
record.setRoomUid(roomUid);
record.setCostPriceNum(record.getCostPriceNum() + costPieceNum);
}
record.setUpdateTime(new Date());
saveOrUpdate(record);
log.info("更新用户单轮消耗碎片数操作后, uid:{},roomUid:{},roundId:{},itemId:{},costPiece:{}",
uid, roomUid, roundId, item, record.getCostPriceNum());
} finally {
jedisLockService.unlock(RedisKey.LOCK_LUCKY_SEA_UPDATE_COST_PIECE.getKey(uid.toString()), lockVal);
}
}
}

View File

@@ -1,11 +1,8 @@
package com.accompany.business.service.activities;
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.config.LuckySeaActConfig;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.param.activity.LuckySeaActDrawParams;
import com.accompany.business.service.activities.vo.LuckySeaActUserDrawRecordVo;
import com.accompany.business.service.activities.vo.LuckySeaActUserInfo;
import com.accompany.business.service.activities.vo.LuckySeaRankVo;
@@ -38,12 +35,6 @@ public interface ActivitiesLuckySeaService {
*/
LuckySeaActUserInfo getUserLuckySeaActInfo(Long uid);
/**
* 获取深海奇缘活动配置奖项列表
* @return
*/
List<LuckySeaItem> listLuckySeaItem();
/**
* 获取深海奇缘活动信息列表
* @param count
@@ -72,9 +63,8 @@ public interface ActivitiesLuckySeaService {
/**
* 深海奇缘活动用户抽奖
* @param uid
* @param params
*/
void draw(Long uid, LuckySeaActDrawParams params);
void draw(Long uid, Long itemId, Long num);
/**
* 获取深海奇缘活动各阶段时间配置
@@ -103,14 +93,6 @@ public interface ActivitiesLuckySeaService {
*/
void updateUserDrawRecordAsync(String roundId, List<LuckySeaItem> itemList);
/**
* 创建新的一轮游戏
* @return
* @param startTime
* @param chooseStageConfigTime
*/
String createNewRoundAct(Date startTime, Integer chooseStageConfigTime);
/**
* 更新游戏状态
* @param roundId

View File

@@ -0,0 +1,17 @@
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.config.LuckySeaActConfig;
/**
* <br>接口描述: 深海奇缘活动信息service
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
public interface LuckySeaActConfigService {
LuckySeaActConfig getLuckySeaTimeConfig();
Double getLuckySeaActTicket();
}

View File

@@ -1,18 +1,11 @@
/*
* : LuckySeaActInfoService
* :
* : <描述>
* 创建人: H1
* 创建时间: 2020/12/31
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities;
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Date;
import java.util.List;
/**
* <br>接口描述: 深海奇缘活动信息service
* <br>功能详细描述:
@@ -26,4 +19,10 @@ public interface LuckySeaActInfoService extends IService<LuckySeaActInfo> {
* @return
*/
LuckySeaActInfo getByCurrTime();
List<LuckySeaActInfo> listActInfo(String roundId, Integer count);
Long getStock();
LuckySeaActInfo createNeewRoundAct(Date nextRoundStartTime, Integer chooseStageTime);
}

View File

@@ -0,0 +1,9 @@
package com.accompany.business.service.activities.luckySea;
public interface LuckySeaDrawService {
void draw(Long uid, Long itemId, Long num);
void start();
}

View File

@@ -1,18 +1,10 @@
/*
* : LuckySeaItemService
* :
* : <描述>
* 创建人: H1
* 创建时间: 2020/12/31
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities;
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.model.activity.LuckySeaItem;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <br>接口描述: 深海奇缘活动配置item
* <br>功能详细描述:
@@ -22,4 +14,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface LuckySeaItemService extends IService<LuckySeaItem> {
LuckySeaItem getItemById(Long uid);
List<LuckySeaItem> listSingleItem();
}

View File

@@ -0,0 +1,16 @@
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.service.activities.vo.LuckySeaRankVo;
/**
* <br>接口描述: 深海奇缘活动信息service
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
public interface LuckySeaRankService {
LuckySeaRankVo listRank(Integer type, Integer page, Integer pageSize, Long uid);
}

View File

@@ -1,15 +1,6 @@
/*
* : LuckySeaUserDrawRecordService
* :
* : <描述>
* 创建人: H1
* 创建时间: 2021/1/4
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities;
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.model.activity.LuckySeaUserDrawRecord;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -25,8 +16,7 @@ public interface LuckySeaUserDrawRecordService extends IService<LuckySeaUserDraw
* 更新用户抽奖记录
* @param uid
* @param roundId
* @param itemId
* @param costPieceNum
*/
void updateUserDrawRecord(Long uid, Long roomUid, String roundId, Long itemId, Long costPieceNum);
boolean updateUserDrawRecord(Long uid, Long roomUid, String roundId, LuckySeaItem item, Long costPieceNum);
}

View File

@@ -1,14 +1,4 @@
/*
* : LuckySeaUserDrawResultService
* :
* : <描述>
* 创建人: H1
* 创建时间: 2021/1/5
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities;
package com.accompany.business.service.activities.luckySea;
import com.accompany.business.model.activity.LuckySeaUserDrawResult;
import com.baomidou.mybatisplus.extension.service.IService;

View File

@@ -1,14 +1,4 @@
/*
* : ActivitiesLuckySeaServiceImpl
* :
* : <描述>
* 创建人: H1
* 创建时间: 2020/12/29
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities.impl;
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.config.LuckySeaActConfig;
import com.accompany.business.constant.activities.ActivitesPackTypeEnum;
@@ -19,12 +9,9 @@ import com.accompany.business.model.ActivityPack;
import com.accompany.business.model.UserPurse;
import com.accompany.business.model.activity.*;
import com.accompany.business.mybatismapper.activity.LuckySeaActMapper;
import com.accompany.business.mybatismapper.activity.LuckySeaUserDrawResultMapper;
import com.accompany.business.param.activity.LuckySeaActDrawParams;
import com.accompany.business.service.activities.*;
import com.accompany.business.service.activities.luckySea.*;
import com.accompany.business.service.activities.vo.LuckySeaActUserDrawRecordVo;
import com.accompany.business.service.activities.vo.LuckySeaActUserInfo;
import com.accompany.business.service.activities.vo.LuckySeaRankListVo;
import com.accompany.business.service.activities.vo.LuckySeaRankVo;
import com.accompany.business.service.activity.ActivityPackService;
import com.accompany.business.service.purse.UserPurseService;
@@ -35,23 +22,23 @@ import com.accompany.business.service.user.UserActPropertyInfoV2Service;
import com.accompany.business.service.user.UsersService;
import com.accompany.business.vo.activities.*;
import com.accompany.common.constant.Constant;
import com.accompany.common.exception.ApiException;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.BlankUtil;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.common.utils.RandomUtil;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.enumeration.BillObjTypeEnum;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.model.Users;
import com.accompany.core.service.SysConfService;
import com.accompany.core.service.common.JedisLockService;
import com.accompany.core.service.common.JedisService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
@@ -61,25 +48,20 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/29]
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService {
@Autowired
private UserInOutRoomRecordService userInOutRoomRecordService;
private RedissonClient redissonClient;
@Autowired
private JedisLockService jedisLockService;
private LuckySeaActConfigService configService;
@Autowired
private ActivityPackService activityPackService;
@Autowired
@@ -93,46 +75,30 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
@Autowired
private LuckySeaActInfoService luckySeaActInfoService;
@Autowired
private LuckySeaRankService rankService;
@Autowired
private LuckySeaActMapper luckySeaActMapper;
@Autowired
private LuckySeaDrawService drawService;
@Autowired
private LuckySeaUserDrawRecordService luckySeaUserDrawRecordService;
@Autowired
private SysConfService sysConfService;
@Autowired
private LuckySeaUserDrawResultService luckySeaUserDrawResultService;
private LuckySeaUserDrawResultService userDrawResultService;
@Autowired
private JedisService jedisService;
@Autowired
private LuckySeaUserDrawResultMapper luckySeaUserDrawResultMapper;
@Autowired
private BillRecordService billRecordService;
@Autowired
private UserActPropertyInfoV2Service userActPropertyInfoV2Service;
@Autowired
private LuckySeaPushMsgService luckySeaPushMsgService;
@Autowired
private Executor taskExecutor;
/**
* 默认返回的游戏记录数
*/
private final static Integer DEFAULT_RETURN_RECORD_NUM = 5;
/**
* 选择阶段默认时间()
*/
private final static Integer DEFAULT_CHOOSE_STAGE_TIME = 30;
/**
* 开奖阶段默认时间()
*/
private final static Integer DEFAULT_WAITING_DRAW_STAGE_TIME = 5;
/**
* 开奖结束阶段默认时间()
*/
private final static Integer DEFAULT_DRAW_OVER_STAGE_TIME = 3;
/**
* 处理库存时需要换算的倍数
*/
public final static Integer HANDLE_STOCK_MULTIPLE = 100000;
private final static Integer CACHE_EXPIRE_SECOND = 3;
@Override
@@ -147,12 +113,14 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
throw new ServiceException("购买礼包数必须大于0");
}
log.info("updateUserLuckySeaActPiece, uid = {}, packId = {}, packNum = {}", uid, packId, packNum);
String lock = null;
boolean locked = false;
RLock lock = redissonClient.getLock(RedisKey.LOCK_LUCKY_SEA_UPDATE_PIECE.getKey(uid.toString()));
try {
lock = jedisLockService.lock(RedisKey.LOCK_LUCKY_SEA_UPDATE_PIECE.getKey(uid.toString()), 10 * 1000);
if (BlankUtil.isBlank(lock)){
throw new ApiException(BusiStatus.REQUEST_FAST);
locked = lock.tryLock(3, TimeUnit.SECONDS);
if (!locked){
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
ActivityPack pack = activityPackService.getPackById(packId);
if (null == pack) {
throw new ServiceException("购买的产品不存在");
@@ -160,87 +128,96 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
int pieceNum = pack.getTicketNum() * packNum;
userActPropertyInfoService.updatePiece(uid, (long)pieceNum);
log.info("updateTicketNum, num = {}",pieceNum);
}finally {
jedisLockService.unlock(RedisKey.LOCK_LUCKY_SEA_UPDATE_PIECE.getKey(uid.toString()), lock);
} catch (InterruptedException e) {
log.error("[春日游园]", e);
throw new ServiceException(BusiStatus.SERVER_BUSY);
} finally {
if (locked){
lock.unlock();
}
}
}
@Override
public LuckySeaActUserInfo getUserLuckySeaActInfo(Long uid) {
if (null == uid) {
throw new ServiceException("uid不能为空");
}
Users user = usersService.getUsersByUid(uid);
if (user == null) {
if (null == user) {
throw new ServiceException(BusiStatus.USERNOTEXISTS);
}
LuckySeaActUserInfo info = new LuckySeaActUserInfo();
info.setAvatar(user.getAvatar());
info.setNick(user.getNick());
// 获取用户钱包钻石数
UserPurse userPurse = userPurseService.queryUserPurse(uid);
info.setDiamonds(userPurse != null ? userPurse.getDiamonds() : 0);
Date today = new Date();
Date tomorrow = DateTimeUtil.addDays(today, 1);
String todayStr = DateTimeUtil.convertDate(today, DateTimeUtil.DEFAULT_DATE_PATTERN);
String tomorrowStr = DateTimeUtil.convertDate(tomorrow, DateTimeUtil.DEFAULT_DATE_PATTERN);
Double diamondIncome = luckySeaActMapper.countUserDiamondIncome(uid, todayStr, tomorrowStr);
info.setTodayReward(diamondIncome);
info.setDiamonds(null != userPurse? userPurse.getDiamonds() : 0);
/*Date today = new Date();
Date todayStart = DateTimeUtil.getBeginTimeOfDay(today);
Date todayEnd = DateTimeUtil.getEndTimeOfDay(today);
String todayStartStr = DateTimeUtil.convertDate(todayStart, DateTimeUtil.DEFAULT_DATETIME_PATTERN);
String todayEndStr = DateTimeUtil.convertDate(todayEnd, DateTimeUtil.DEFAULT_DATE_PATTERN);
Double diamondIncome = luckySeaActMapper.countUserDiamondIncome(uid, todayStartStr, todayEndStr);
info.setTodayReward(diamondIncome);*/
return info;
}
@Override
public List<LuckySeaItem> listLuckySeaItem() {
String cacheKey = RedisKey.lucky_sea_item.getKey();
String cacheVal = jedisService.get(cacheKey);
if (StringUtils.isNotBlank(cacheVal)){
return JSON.parseArray(cacheVal, LuckySeaItem.class);
}
QueryWrapper<LuckySeaItem> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(LuckySeaItem::getStatus, Constant.status.valid)
.orderByAsc(LuckySeaItem::getMultiple);
List<LuckySeaItem> itemList = luckySeaItemService.list(wrapper);
jedisService.setex(cacheKey, CACHE_EXPIRE_SECOND, JSON.toJSONString(itemList));
return itemList;
}
@Override
public List<LuckySeaActInfo> listLuckySeaActInfo(Integer count, String roundId) {
if (null == count) {
count = DEFAULT_RETURN_RECORD_NUM;
}
String cacheKey = RedisKey.lucky_sea_act_info.getKey(String.valueOf(count), roundId);
String cacheVal = jedisService.get(cacheKey);
if (StringUtils.isNotBlank(cacheVal)){
return JSON.parseArray(cacheVal, LuckySeaActInfo.class);
}
QueryWrapper<LuckySeaActInfo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(LuckySeaActInfo::getStatus, Constant.LuckySeaActStatus.DRAW_OVER).ne(LuckySeaActInfo::getRoundId, roundId)
.orderByDesc(LuckySeaActInfo::getStartTime);
wrapper.last(String.format("limit %d", count));
List<LuckySeaActInfo> actList = luckySeaActInfoService.list(wrapper);
jedisService.setex(cacheKey, CACHE_EXPIRE_SECOND, JSON.toJSONString(actList));
return actList;
return luckySeaActInfoService.listActInfo(roundId, count);
}
@Override
public LuckySeaActInfoVo getNewestLuckySeaActInfo(Long uid) {
LuckySeaActInfoVo vo = new LuckySeaActInfoVo();
LuckySeaActInfo info = luckySeaActInfoService.getByCurrTime();
if (null == info){
return vo;
}
BeanUtils.copyProperties(info, vo);
LuckySeaActConfig luckySeaTimeConfig = getLuckySeaTimeConfig();
if (null != info) {
BeanUtils.copyProperties(info, vo);
if (vo.getShowResultStageStartTime() == null) {
vo.setShowResultStageStartTime(DateTimeUtil.addSeconds(vo.getDrawStageStartTime(), luckySeaTimeConfig.getWaitingDrawStageTime()));
}
if (Constant.LuckySeaActStatus.DRAW_OVER.equals(info.getStatus())) {
// 获取排行榜前三
List<LuckySeaActRoundRankUserVo> topThreeUser = luckySeaActMapper.listTopThreeInOneRound(info.getRoundId());
vo.setRankUserList(topThreeUser);
if (null != uid) {
if (vo.getShowResultStageStartTime() == null) {
vo.setShowResultStageStartTime(DateTimeUtil.addSeconds(vo.getDrawStageStartTime(), luckySeaTimeConfig.getWaitingDrawStageTime()));
}
if (Constant.LuckySeaActStatus.DRAW_OVER.equals(info.getStatus())) {
vo.setEndTime(DateTimeUtil.addSeconds(vo.getShowResultStageStartTime(), luckySeaTimeConfig.getDrawOverStageTime()));
CountDownLatch cdl = new CountDownLatch(2);
taskExecutor.execute(()->{
try {
// 获取排行榜前三
List<LuckySeaActRoundRankUserVo> topThreeUser = luckySeaActMapper.listTopThreeInOneRound(info.getRoundId());
if (!CollectionUtils.isEmpty(topThreeUser)){
List<Long> uids = topThreeUser.stream().map(LuckySeaActRoundRankUserVo::getUid).distinct().collect(Collectors.toList());
Map<Long, Users> usersMap = usersService.getUsersMapByUids(uids);
for (LuckySeaActRoundRankUserVo e: topThreeUser){
Users u = usersMap.get(e.getUid());
if (null == u){
continue;
}
e.setErbanNo(u.getErbanNo());
e.setNick(u.getNick());
e.setAvatar(u.getAvatar());
}
}
vo.setRankUserList(topThreeUser);
} catch (Exception e){
log.error("[春日游园]", e);
} finally {
cdl.countDown();
}
});
taskExecutor.execute(()->{
try {
// 获取用户中奖信息
LuckySeaActUserOneRoundDrawResult result = new LuckySeaActUserOneRoundDrawResult();
List<LuckySeaActUserDrawItemVO> userRecords = listUserDrawItemInfo(uid, info.getRoundId());
result.setDrawRecords(userRecords);
@@ -257,10 +234,19 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
}
}
}
vo.setUserDrawResult(result);
} catch (Exception e){
log.error("[春日游园]", e);
} finally {
cdl.countDown();
}
vo.setEndTime(DateTimeUtil.addSeconds(vo.getShowResultStageStartTime(), luckySeaTimeConfig.getDrawOverStageTime()));
});
try {
cdl.await(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error("[春日游园]", e);
throw new ServiceException(BusiStatus.SERVERERROR);
}
}
return vo;
@@ -268,128 +254,76 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
@Override
public LuckySeaRankVo listRank(Integer type, Integer page, Integer pageSize, Long uid) {
if (null == type) {
throw new ServiceException("榜单type不能为空");
}
if (null == page) {
page = Constant.DEFAULT_PAGE;
}
if (null == pageSize) {
pageSize = Constant.DEFAULT_PAGE_SIZE;
}
int start = (page - 1) * pageSize;
LuckySeaRankVo vo = new LuckySeaRankVo();
List<LuckySeaRankListVo> rankList = new ArrayList<>();
LuckySeaRankListVo userRankInfo = new LuckySeaRankListVo();
Date beginTimeOfDay = DateTimeUtil.getBeginTimeOfDay(new Date());
Date endTimeOfDay = DateTimeUtil.getEndTimeOfDay(new Date());
if (type.equals(Constant.LuckySeaRankType.DIAMOND_RANK)) {
rankList = luckySeaActMapper.listDiamondRank(start, pageSize, beginTimeOfDay, endTimeOfDay);
userRankInfo = luckySeaActMapper.listUserDiamondRank(uid, beginTimeOfDay, endTimeOfDay);
} else if (type.equals(Constant.LuckySeaRankType.LUCKY_MAN_RANK)) {
rankList = luckySeaActMapper.listLuckyManRank(start, pageSize, beginTimeOfDay, endTimeOfDay);
userRankInfo = luckySeaActMapper.listUserLuckyManRank(uid, beginTimeOfDay, endTimeOfDay);
}
// 最多返回100条
if (page * pageSize > 100) {
rankList = new ArrayList<>();
}
vo.setRankList(rankList);
vo.setMyRankInfo(userRankInfo);
return vo;
return rankService.listRank(type, page, pageSize, uid);
}
@Override
public void draw(Long uid, LuckySeaActDrawParams param) {
if (null == uid) {
throw new ServiceException("uid不能为空");
}
String lockVal = jedisLockService.lock(RedisKey.LOCK_LUCKY_SEA_USER_DRAW.getKey(uid.toString()));
if (BlankUtil.isBlank(lockVal)) {
log.error("春日游园获取分布式锁失败uid:{}", uid);
throw new ServiceException(BusiStatus.JOIN_GAME_USER_TOO_MORE);
}
String roundId = null;
try {
Long costGoldTotal = checkDrawParam(param, uid);
LuckySeaActInfo actInfo = luckySeaActInfoService.getByCurrTime();
if (actInfo == null) {
log.error("选择失败当前时段不存在活动。actInfo:" + JSON.toJSONString(actInfo));
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
roundId = actInfo.getRoundId();
jedisService.incrBy(RedisKey.lucky_sea_curr_write_data_user_count.getKey(roundId), 1);
if (!actInfo.getStatus().equals(Constant.LuckySeaActStatus.CHOOSE_STAGE)) {
log.error("选择失败当前不处于选择阶段。actInfo:" + JSON.toJSONString(actInfo));
throw new ServiceException("選擇失敗,當前不處於選擇階段");
}
// 扣减用户钻石
log.info("【春日游园活动】 uid {} 消耗钻石总数 {}", uid, costGoldTotal);
Boolean ret = userPurseService.subDiamond(uid, (double) costGoldTotal, Constant.BusinessType.LUCKY_SEA_DRAW);
if (!ret) {
throw new ServiceException(BusiStatus.DIAMONDNUMNOTENOUGH);
}
Long roomUid = userInOutRoomRecordService.getUserCurrentRoomUid(uid);
luckySeaUserDrawRecordService.updateUserDrawRecord(uid, roomUid, actInfo.getRoundId(), param.getItemId(), param.getNum());
billRecordService.insertGeneralBillRecord(uid, null, null, BillObjTypeEnum.ACTIVITY_LUCKY_SEA_DRAW,
-Double.valueOf(costGoldTotal));
} finally {
jedisLockService.unlock(RedisKey.LOCK_LUCKY_SEA_USER_DRAW.getKey(uid.toString()), lockVal);
jedisService.decrBy(RedisKey.lucky_sea_curr_write_data_user_count.getKey(roundId), 1);
}
public void draw(Long uid, Long itemId, Long num) {
drawService.draw(uid, itemId, num);
}
@Override
public LuckySeaActConfig getLuckySeaTimeConfig() {
String luckySeaConfigStr = sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_TIME_CONFIG);
if (StringUtils.isBlank(luckySeaConfigStr)) {
LuckySeaActConfig config = new LuckySeaActConfig();
config.setChooseStageTime(DEFAULT_CHOOSE_STAGE_TIME);
config.setWaitingDrawStageTime(DEFAULT_WAITING_DRAW_STAGE_TIME);
config.setDrawOverStageTime(DEFAULT_DRAW_OVER_STAGE_TIME);
return config;
}
return JSON.parseObject(luckySeaConfigStr, LuckySeaActConfig.class);
return configService.getLuckySeaTimeConfig();
}
@Override
public List<LuckySeaActUserDrawRecordVo> listUserDrawResult(Long uid, Integer page, Integer pageSize) {
if (page == null) {
page = Constant.DEFAULT_PAGE;
}
if (pageSize == null) {
page = Constant.DEFAULT_PAGE_SIZE;
}
QueryWrapper<LuckySeaUserDrawResult> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(LuckySeaUserDrawResult::getUid, uid).orderByDesc(LuckySeaUserDrawResult::getDrawTime);
Page<LuckySeaUserDrawResult> recordVoPage = new Page<>(page, pageSize);
List<LuckySeaUserDrawResult> list = luckySeaUserDrawResultMapper.selectPage(recordVoPage, wrapper).getRecords();
Page<LuckySeaUserDrawResult> pageInfo = new Page<>(page, pageSize);
QueryWrapper<LuckySeaUserDrawResult> wrapper = Wrappers.query();
wrapper.lambda().eq(LuckySeaUserDrawResult::getUid, uid)
.orderByDesc(LuckySeaUserDrawResult::getDrawTime);
userDrawResultService.page(pageInfo, wrapper);
List<LuckySeaActUserDrawRecordVo> results = new ArrayList<>();
if (!CollectionUtils.isEmpty(list)) {
for (LuckySeaUserDrawResult result : list) {
LuckySeaActUserDrawRecordVo vo = new LuckySeaActUserDrawRecordVo();
Long reward = 0L;
LuckySeaActInfo actInfo = luckySeaActInfoService.getById(result.getRoundId());
if (actInfo != null) {
vo.setRoundId(actInfo.getRoundId());
vo.setDrawTime(actInfo.getEndTime());
vo.setDrawId(actInfo.getDrawId());
}
List<LuckySeaUserDrawResultVo> resultVos = handleDrawResult(result.getResult());
for (LuckySeaUserDrawResultVo resultVo : resultVos) {
if (null != result.getDrawId() && result.getDrawId().equals(resultVo.getItemId())) {
reward = resultVo.getCostPiece() * resultVo.getMultiple();
}
}
vo.setResults(resultVos);
vo.setDrawStatus(result.getDrawStatus());
vo.setReward(reward);
results.add(vo);
}
if (CollectionUtils.isEmpty(pageInfo.getRecords())){
return results;
}
for (LuckySeaUserDrawResult result : pageInfo.getRecords()) {
LuckySeaActUserDrawRecordVo vo = new LuckySeaActUserDrawRecordVo();
BeanUtils.copyProperties(result, vo);
long reward = 0L;
List<LuckySeaUserDrawResultVo> resultVos = handleDrawResult(result.getResult());
for (LuckySeaUserDrawResultVo resultVo : resultVos) {
if (null != result.getDrawId() && result.getDrawId().equals(resultVo.getItemId())) {
reward += resultVo.getCostPiece() * resultVo.getMultiple();
}
}
vo.setResults(resultVos);
vo.setReward(reward);
results.add(vo);
}
return results;
}
/**
* 处理抽奖结果返回
* @param resultJson
* @return
*/
private List<LuckySeaUserDrawResultVo> handleDrawResult(String resultJson) {
List<LuckySeaUserDrawResultVo> results = new ArrayList<>();
if (StringUtils.isBlank(resultJson)){
return results;
}
List<LuckySeaItem> itemList = luckySeaItemService.listSingleItem();
Map<Long, String> itemUrlMap = itemList.stream().collect(Collectors.toMap(LuckySeaItem::getId, LuckySeaItem::getImgUrl));
List<LuckySeaUserDrawResultDto> dtoList = JSON.parseArray(resultJson, LuckySeaUserDrawResultDto.class);
for (LuckySeaUserDrawResultDto dto : dtoList) {
LuckySeaUserDrawResultVo vo = new LuckySeaUserDrawResultVo();
vo.setItemUrl(itemUrlMap.get(dto.getItemId()));
vo.setCostPiece(dto.getCostNum());
vo.setItemId(dto.getItemId());
vo.setMultiple(dto.getMultiple());
results.add(vo);
}
return results;
}
@@ -470,8 +404,6 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
}
}
/**
* 异步写入用户的游戏记录
* @param roundId
@@ -514,7 +446,7 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
result.setUpdateTime(new Date());
results.add(result);
}
luckySeaUserDrawResultService.saveBatch(results);
userDrawResultService.saveBatch(results);
}
}
@@ -524,7 +456,7 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
* @param itemList
* @return
*/
private Map<Long, Map<Long, LuckySeaUserDrawResultDto>> initUserDrawResultMap( Map<Long, List<LuckySeaUserDrawRecord>> userDrawRecordMap,
private Map<Long, Map<Long, LuckySeaUserDrawResultDto>> initUserDrawResultMap(Map<Long, List<LuckySeaUserDrawRecord>> userDrawRecordMap,
List<LuckySeaItem> itemList) {
Map<Long, Map<Long, LuckySeaUserDrawResultDto>> userDrawResultMap = new HashMap<>();
for (Long uid : userDrawRecordMap.keySet()) {
@@ -632,19 +564,37 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
luckySeaActInfoService.updateById(act);
QueryWrapper<LuckySeaUserDrawResult> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(LuckySeaUserDrawResult::getRoundId, roundId);
List<LuckySeaUserDrawResult> results = luckySeaUserDrawResultService.list(wrapper);
List<LuckySeaUserDrawResult> results = userDrawResultService.list(wrapper);
if (!CollectionUtils.isEmpty(results)) {
for (LuckySeaUserDrawResult result : results) {
result.setDrawTime(endTime);
}
luckySeaUserDrawResultService.updateBatchById(results);
userDrawResultService.updateBatchById(results);
}
}
@Override
public List<LuckySeaActUserDrawItemVO> listUserDrawItemInfo(Long uid, String roundId) {
List<LuckySeaActUserDrawItemVO> itemVOS = luckySeaActMapper.listUserDrawItemInfo(roundId, uid);
return itemVOS;
List<LuckySeaItem> singleItemList = luckySeaItemService.listSingleItem();
Map<Long, LuckySeaActUserDrawItemVO> voMap = singleItemList.stream().map(r->{
LuckySeaActUserDrawItemVO vo = new LuckySeaActUserDrawItemVO();
BeanUtils.copyProperties(r, vo);
vo.setCostPieceNum(0);
return vo;
}).collect(Collectors.toMap(LuckySeaActUserDrawItemVO::getId, i->i));
List<LuckySeaActUserDrawItemVO> userDrawRecord = luckySeaActMapper.listUserDrawItemInfo(roundId, uid);
if (!CollectionUtils.isEmpty(userDrawRecord)){
for (LuckySeaActUserDrawItemVO record: userDrawRecord){
LuckySeaActUserDrawItemVO vo = voMap.get(record.getId());
vo.setCostPieceNum(record.getCostPieceNum());
}
}
return voMap.values().stream()
.sorted(Comparator.comparing(LuckySeaActUserDrawItemVO::getMultiple))
.collect(Collectors.toList());
}
@Override
@@ -662,31 +612,6 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
log.info("春日游园活动,结束处理发生异常的活动, roundId:{}, 处理的投入列表statList:{}", roundId, JSON.toJSONString(statList));
}
/**
* 创建新的一轮游戏
* @return
* @param startTime
* @param chooseStageConfigTime
*/
@Transactional(rollbackFor = Exception.class)
@Override
public String createNewRoundAct(Date startTime, Integer chooseStageConfigTime) {
if (startTime == null) {
startTime = new Date();
}
String roundId = DateTimeUtil.convertDate(startTime, DateTimeUtil.LUCKY_SEA_ACT_ROUND_PATTERN);
LuckySeaActInfo act = new LuckySeaActInfo();
act.setRoundId(roundId);
act.setStartTime(startTime);
act.setStatus(Constant.LuckySeaActStatus.CHOOSE_STAGE);
act.setDrawStageStartTime(DateTimeUtil.addSeconds(startTime, chooseStageConfigTime));
act.setCreateTime(new Date());
act.setUpdateTime(new Date());
luckySeaActInfoService.save(act);
log.info("春日游园活动, 创建新的一轮游戏 roundId:{}, startTime:{}", roundId, startTime);
return roundId;
}
/**
* 处理开奖
* @param statList
@@ -731,8 +656,6 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
return drawId;
}
/**
* 初始化
* @param itemList
@@ -751,15 +674,7 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
* @return
*/
private Double getLuckySeaActTicket() {
String ticketStr = sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_TICKET);
if (StringUtils.isBlank(ticketStr)) {
throw new ServiceException("配置的门票为空");
}
Double ticket = Double.valueOf(ticketStr);
if (ticket >= 1) {
throw new ServiceException("门票配置不能大于或等于1");
}
return ticket;
return configService.getLuckySeaActTicket();
}
/**
@@ -777,59 +692,7 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
*/
@Override
public Long getStock() {
String stockStr = jedisService.get(RedisKey.LUCKY_SEA_ACT_STOCK.getKey());
if (StringUtils.isBlank(stockStr)) {
stockStr = sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_STOCK);
jedisService.set(RedisKey.LUCKY_SEA_ACT_STOCK.getKey(), String.valueOf((Long.valueOf(stockStr)*HANDLE_STOCK_MULTIPLE)));
}
return Long.valueOf(stockStr);
return luckySeaActInfoService.getStock();
}
/**
* 校验抽奖参数
* @param param
* @param uid
*/
private Long checkDrawParam(LuckySeaActDrawParams param, Long uid) {
if (null == param) {
throw new ServiceException("至少需要选中一项");
}
if (param.getItemId() == null) {
throw new ServiceException("itemId不能为空");
}
if (param.getNum() <= 0) {
throw new ServiceException("选择数量需要大于0");
}
LuckySeaItem item = luckySeaItemService.getById(param.getItemId());
if (null == item || !item.getStatus().equals(Constant.status.valid)) {
log.error("选择的配置不存在, itemId" + param.getItemId());
throw new ServiceException("选择的配置不存在");
}
// 扣减用户钻石
// log.info("【春日游园活动】 uid {} 消耗钻石总数 {}", uid, costPieceTotal);
// userPurseService.subDiamond(uid, (double)costPieceTotal, Constant.BusinessType.LUCKY_SEA_DRAW);
return param.getNum();
}
/**
* 处理抽奖结果返回
* @param resultJson
* @return
*/
private List<LuckySeaUserDrawResultVo> handleDrawResult(String resultJson) {
List<LuckySeaUserDrawResultVo> results = new ArrayList<>();
if (StringUtils.isNotBlank(resultJson)) {
List<LuckySeaUserDrawResultDto> dtoList = JSON.parseArray(resultJson, LuckySeaUserDrawResultDto.class);
for (LuckySeaUserDrawResultDto dto : dtoList) {
LuckySeaUserDrawResultVo vo = new LuckySeaUserDrawResultVo();
LuckySeaItem item = luckySeaItemService.getById(dto.getItemId());
vo.setItemUrl(item != null ? item.getImgUrl() : null);
vo.setCostPiece(dto.getCostNum());
vo.setItemId(dto.getItemId());
vo.setMultiple(dto.getMultiple());
results.add(vo);
}
}
return results;
}
}

View File

@@ -0,0 +1,69 @@
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.config.LuckySeaActConfig;
import com.accompany.business.service.activities.luckySea.LuckySeaActConfigService;
import com.accompany.common.constant.Constant;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.service.SysConfService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
@Service
@Slf4j
public class LuckySeaActConfigServiceImpl implements LuckySeaActConfigService {
@Autowired
private SysConfService sysConfService;
/**
* 选择阶段默认时间(秒)
*/
private final static Integer DEFAULT_CHOOSE_STAGE_TIME = 30;
/**
* 开奖阶段默认时间(秒)
*/
private final static Integer DEFAULT_WAITING_DRAW_STAGE_TIME = 5;
/**
* 开奖结束阶段默认时间(秒)
*/
private final static Integer DEFAULT_DRAW_OVER_STAGE_TIME = 3;
private final static Integer DEFAULT_MODE = 1;
@Override
public LuckySeaActConfig getLuckySeaTimeConfig() {
String luckySeaConfigStr = sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_TIME_CONFIG);
if (StringUtils.isNoneBlank(luckySeaConfigStr)) {
return JSON.parseObject(luckySeaConfigStr, LuckySeaActConfig.class);
}
LuckySeaActConfig config = new LuckySeaActConfig();
config.setChooseStageTime(DEFAULT_CHOOSE_STAGE_TIME);
config.setWaitingDrawStageTime(DEFAULT_WAITING_DRAW_STAGE_TIME);
config.setDrawOverStageTime(DEFAULT_DRAW_OVER_STAGE_TIME);
config.setModelType(DEFAULT_MODE);
return config;
}
@Override
public Double getLuckySeaActTicket() {
String ticketStr = sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_TICKET);
if (StringUtils.isBlank(ticketStr)) {
throw new ServiceException("配置的门票为空");
}
Double ticket = Double.valueOf(ticketStr);
if (ticket >= 1d) {
throw new ServiceException("门票配置不能大于或等于1");
}
return ticket;
}
}

View File

@@ -0,0 +1,109 @@
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.accompany.business.mybatismapper.activity.LuckySeaActInfoMapper;
import com.accompany.business.service.activities.luckySea.LuckySeaActInfoService;
import com.accompany.business.vo.activities.LuckySeaActInfoVo;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.service.SysConfService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
@Service
@Slf4j
public class LuckySeaActInfoServiceImpl extends ServiceImpl<LuckySeaActInfoMapper, LuckySeaActInfo> implements LuckySeaActInfoService {
@Autowired
private RedissonClient redissonClient;
@Autowired
private SysConfService sysConfService;
private final static Integer CACHE_EXPIRE_SECOND = 3;
/**
* 处理库存时需要换算的倍数
*/
public final static Integer HANDLE_STOCK_MULTIPLE = 100000;
@Override
public Long getStock() {
RBucket<String> stockRBucket = redissonClient.getBucket(RedisKey.LUCKY_SEA_ACT_STOCK.getKey());
if (stockRBucket.isExists()) {
return Long.valueOf(stockRBucket.get());
}
String stockStr = sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_STOCK);
Long stock = Long.parseLong(stockStr) * HANDLE_STOCK_MULTIPLE;
stockRBucket.set(String.valueOf(stock));
return stock;
}
@Override
public LuckySeaActInfo createNeewRoundAct(Date startTime, Integer chooseStageConfigTime) {
Date now = new Date();
if (startTime == null) {
startTime = now;
}
String roundId = DateTimeUtil.convertDate(startTime, DateTimeUtil.LUCKY_SEA_ACT_ROUND_PATTERN);
LuckySeaActInfo act = new LuckySeaActInfo();
act.setRoundId(roundId);
act.setStartTime(startTime);
act.setStatus(Constant.LuckySeaActStatus.CHOOSE_STAGE);
act.setDrawStageStartTime(DateTimeUtil.addSeconds(startTime, chooseStageConfigTime));
act.setCreateTime(now);
act.setUpdateTime(now);
if (!save(act)){
log.error("春日游园活动, 保存新的一轮游戏失败 roundId:{}, startTime:{}", roundId, startTime);
throw new ServiceException(BusiStatus.SERVERERROR);
}
log.info("春日游园活动, 创建新的一轮游戏 roundId:{}, startTime:{}", roundId, startTime);
return act;
}
@Override
public LuckySeaActInfo getByCurrTime() {
QueryWrapper<LuckySeaActInfo> wrapper = new QueryWrapper<>();
wrapper.lambda().orderByDesc(LuckySeaActInfo::getRoundId)
.last("limit 1");
return getOne(wrapper);
}
@Override
public List<LuckySeaActInfo> listActInfo(String roundId, Integer count) {
String cacheKey = RedisKey.lucky_sea_act_info.getKey(String.valueOf(count), roundId);
RBucket<String> cacheVal = redissonClient.getBucket(cacheKey);
if (cacheVal.isExists()){
return JSON.parseArray(cacheVal.get(), LuckySeaActInfo.class);
}
QueryWrapper<LuckySeaActInfo> wrapper = new QueryWrapper<>();
wrapper.lambda()
.lt(LuckySeaActInfo::getRoundId, roundId)
.eq(LuckySeaActInfo::getStatus, Constant.LuckySeaActStatus.DRAW_OVER)
.orderByDesc(LuckySeaActInfo::getRoundId);
wrapper.last(String.format("limit %d", count));
List<LuckySeaActInfo> actList = list(wrapper);
cacheVal.set(JSON.toJSONString(actList), CACHE_EXPIRE_SECOND, TimeUnit.SECONDS);
return actList;
}
}

View File

@@ -0,0 +1,217 @@
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.config.LuckySeaActConfig;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.service.LuckySeaPreWarningService;
import com.accompany.business.service.activities.luckySea.*;
import com.accompany.business.service.purse.UserPurseService;
import com.accompany.business.service.record.BillRecordService;
import com.accompany.business.service.room.UserInOutRoomRecordService;
import com.accompany.business.vo.activities.LuckySeaActInfoVo;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.enumeration.BillObjTypeEnum;
import com.accompany.core.exception.ServiceException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class LuckySeaDrawServiceImpl implements LuckySeaDrawService {
@Autowired
private RedissonClient redissonClient;
@Autowired
private LuckySeaActConfigService configService;
@Autowired
private LuckySeaActInfoService actInfoService;
@Autowired
private LuckySeaItemService itemService;
@Autowired
private LuckySeaUserDrawRecordService drawRecordService;
@Autowired
private UserPurseService userPurseService;
@Autowired
private BillRecordService billRecordService;
@Autowired
private UserInOutRoomRecordService userInOutRoomRecordService;
@Autowired
private ActivitiesLuckySeaService activitiesLuckySeaService;
@Autowired
private LuckySeaPreWarningService luckySeaPreWarningService;
@Override
@Transactional(rollbackFor = Exception.class)
public void draw(Long uid, Long itemId, Long num) {
String roundId = null;
boolean locked = false;
RLock lock = redissonClient.getLock(RedisKey.LOCK_LUCKY_SEA_USER_DRAW.getKey(uid.toString()));
try {
locked = lock.tryLock(5L, TimeUnit.SECONDS);
if (!locked) {
log.error("[春日游园] 获取分布式锁失败uid:{}", uid);
throw new ServiceException(BusiStatus.JOIN_GAME_USER_TOO_MORE);
}
LuckySeaItem item = itemService.getItemById(itemId);
if (null == item || !item.getStatus().equals(Constant.status.valid)) {
log.error("选择的配置不存在, itemId" + item);
throw new ServiceException("選擇的配置不存在");
}
Date now = new Date();
LuckySeaActInfo actInfo = actInfoService.getByCurrTime();
if (actInfo == null || !Constant.LuckySeaActStatus.CHOOSE_STAGE.equals(actInfo.getStatus())
|| now.compareTo(actInfo.getDrawStageStartTime()) >= 0) {
log.error("选择失败当前时段不存在活动。actInfo:" + JSON.toJSONString(actInfo));
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
// 扣减用户钻石
if (!userPurseService.subDiamond(uid, num.doubleValue(), Constant.BusinessType.LUCKY_SEA_DRAW)) {
throw new ServiceException(BusiStatus.DIAMONDNUMNOTENOUGH);
}
log.info("[春日游园] uid {} 消耗钻石总数 {}", uid, num);
RAtomicLong atomic = redissonClient.getAtomicLong(RedisKey.lucky_sea_curr_write_data_user_count.getKey(actInfo.getRoundId()));
atomic.incrementAndGet();
roundId = actInfo.getRoundId();
Long roomUid = userInOutRoomRecordService.getUserCurrentRoomUid(uid);
if (!drawRecordService.updateUserDrawRecord(uid, roomUid, roundId, item, num)){
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
billRecordService.insertGeneralBillRecord(uid, null, null, BillObjTypeEnum.ACTIVITY_LUCKY_SEA_DRAW, num.doubleValue());
} catch (InterruptedException e) {
throw new ServiceException(BusiStatus.SERVER_BUSY);
} finally {
if (StringUtils.isNoneBlank(roundId)){
RAtomicLong atomic = redissonClient.getAtomicLong(RedisKey.lucky_sea_curr_write_data_user_count.getKey(roundId));
atomic.decrementAndGet();
}
if (locked){
lock.unlock();
}
}
}
@Override
public void start() {
String roundId = null;
Date nextRoundStartTime = null;
Long stock = actInfoService.getStock();
// 获取游戏的配置
List<LuckySeaItem> itemList = itemService.listSingleItem();
LuckySeaActConfig timeConfig = configService.getLuckySeaTimeConfig();
int totalTime = timeConfig.getWaitingDrawStageTime() + timeConfig.getChooseStageTime() + timeConfig.getDrawOverStageTime();
// 加锁,确保创建与开奖是单线程执行
boolean locked = false;
RLock lock = redissonClient.getLock(RedisKey.lucky_sea_run_task.getKey());
try {
locked = lock.tryLock(10, totalTime, TimeUnit.SECONDS);
if (!locked){
log.error("春日游园活动, 获取锁失败");
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
long drawMills = 0L;
boolean needCreateNewAct = true;
boolean needWaitUserDraw = true;
Integer waitUserDrawTime = timeConfig.getChooseStageTime();
// 处理异常活动
LuckySeaActInfo lastLuckySeaActInfo = actInfoService.getByCurrTime();
// 处理上轮游戏
if (null != lastLuckySeaActInfo && StringUtils.isNotBlank(lastLuckySeaActInfo.getRoundId())) {
roundId = lastLuckySeaActInfo.getRoundId();
if (Constant.LuckySeaActStatus.CHOOSE_STAGE.equals(lastLuckySeaActInfo.getStatus())){
needCreateNewAct = false;
Long intervalSecond = (System.currentTimeMillis() - lastLuckySeaActInfo.getStartTime().getTime()) / 1000;
log.info("春日游园活动, 上一轮投注时间发生异常的活动到现在的间隔时间{}秒, roundId:{}", intervalSecond, roundId);
if (intervalSecond <= timeConfig.getChooseStageTime()) {
waitUserDrawTime = timeConfig.getChooseStageTime() - intervalSecond.intValue();
log.info("春日游园活动, 上一轮投注时间发生异常的活动留给用户的下注时间{}秒", waitUserDrawTime);
} else {
log.info("春日游园活动, 上一轮投注时间发生异常的活动直接进行开奖, roundId:{}", roundId);
needWaitUserDraw = false;
}
} else if (Constant.LuckySeaActStatus.DRAWING.equals(lastLuckySeaActInfo.getStatus())){
needCreateNewAct = false;
needWaitUserDraw = false;
log.info("春日游园活动, 上一轮投注时间发生异常的活动直接进行开奖, roundId:{}", roundId);
}
}
// 创建新的一轮游戏
if (needCreateNewAct) {
lastLuckySeaActInfo = actInfoService.createNeewRoundAct(nextRoundStartTime, timeConfig.getChooseStageTime());
roundId = lastLuckySeaActInfo.getRoundId();
}
// 等待用户投碎片
if (needWaitUserDraw) {
log.info("春日游园活动, 开始等待用户投入碎片, currTime: {}", System.currentTimeMillis());
Thread.sleep(waitUserDrawTime * 1000);
log.info("春日游园活动, 结束等待用户投入碎片, currTime: {}", System.currentTimeMillis());
}
activitiesLuckySeaService.updateLuckyActStatus(roundId, Constant.LuckySeaActStatus.DRAWING);
// 开奖
drawMills = activitiesLuckySeaService.luckySeaActDraw(itemList, roundId, timeConfig, stock);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
if (locked){
lock.unlock();
}
}
try {
} catch (Exception e) {
// 更新活动状态, 此轮游戏标识为异常,不开始下一轮游戏
log.error("春日游园活动开奖时出现异常, roundId: " + roundId, e);
activitiesLuckySeaService.updateLuckyActStatus(roundId, Constant.LuckySeaActStatus.GAME_ABNORMAL);
activitiesLuckySeaService.compensateUserPieceWhenGameAbnormal(roundId, stock);
break;
} finally {
jedisLockService.unlock(RedisKey.lucky_sea_run_task.getKey(), lockVal);
}
try {
// 异步更新用户抽奖记录
activitiesLuckySeaService.updateUserDrawRecordAsync(roundId, itemList);
// 等待开奖动画与页面渲染开奖结果时间
long sleepMills = (timeConfig.getDrawOverStageTime() + timeConfig.getWaitingDrawStageTime()) * 1000
- drawMills;
if (sleepMills > 0) {
log.info("春日游园活动, 等待开奖动画与页面渲染开奖结果时间{}毫秒", sleepMills);
Thread.sleep(sleepMills);
}
log.info("春日游园活动此轮结束, roundId:{}", roundId);
// 异步更新活动endTime
nextRoundStartTime = new Date();
activitiesLuckySeaService.endLuckyAct(roundId, nextRoundStartTime);
// 进行预警数据统计
luckySeaPreWarningService.handleGoldPreWarning();
} catch (Exception e) {
// 更新活动状态
log.error("春日游园活动更新用户抽奖记录与分发奖励时出现异常, roundId: " + roundId, e);
activitiesLuckySeaService.updateLuckyActStatus(roundId, Constant.LuckySeaActStatus.SUCCESS_DRAW_UPDATE_DATA_FAIL);
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* 文 件 名: LuckySeaItemServiceImpl
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2020/12/31
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.mybatismapper.activity.LuckySeaItemMapper;
import com.accompany.business.service.activities.luckySea.LuckySeaItemService;
import com.accompany.business.util.SpringContextHolder;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2020/12/31]
*/
@Service
@Slf4j
public class LuckySeaItemServiceImpl extends ServiceImpl<LuckySeaItemMapper, LuckySeaItem> implements LuckySeaItemService, InitializingBean {
private RMap<Long, LuckySeaItem> cacheMap;
private final static Integer CACHE_EXPIRE_SECOND = 3;
@Override
public LuckySeaItem getItemById(Long itemId) {
LuckySeaItem item = cacheMap.get(itemId);
if (null != item){
return item;
}
List<LuckySeaItem> dbList = listSingleItemByDB();
if (CollectionUtils.isEmpty(dbList)){
return item;
}
Optional<LuckySeaItem> optional = dbList.stream().filter(e->itemId.equals(e.getId())).findAny();
if (optional.isPresent()){
item = optional.get();
}
return item;
}
@Override
public List<LuckySeaItem> listSingleItem() {
Collection<LuckySeaItem> cacheList = cacheMap.values();
if (!CollectionUtils.isEmpty(cacheList)){
return cacheList.stream()
.sorted(Comparator.comparing(LuckySeaItem::getMultiple))
.collect(Collectors.toList());
}
return listSingleItemByDB();
}
private List<LuckySeaItem> listSingleItemByDB() {
QueryWrapper<LuckySeaItem> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(LuckySeaItem::getStatus, Constant.status.valid)
.orderByAsc(LuckySeaItem::getMultiple);
List<LuckySeaItem> itemList = list(wrapper);
cacheMap.putAll(itemList.stream().collect(Collectors.toMap(LuckySeaItem::getId, e->e)));
cacheMap.expire(CACHE_EXPIRE_SECOND, TimeUnit.SECONDS);
return itemList;
}
@Override
public void afterPropertiesSet() throws Exception {
cacheMap = SpringContextHolder.getBean(RedissonClient.class).getMap(RedisKey.lucky_sea_item.getKey());
}
}

View File

@@ -1,4 +1,4 @@
package com.accompany.business.service.activities.impl;
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.model.activity.LuckySeaRoomTipConfig;
import com.accompany.business.model.activity.LuckySeaUserDrawRecord;

View File

@@ -0,0 +1,77 @@
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.mybatismapper.activity.LuckySeaActMapper;
import com.accompany.business.service.activities.luckySea.LuckySeaRankService;
import com.accompany.business.service.activities.vo.LuckySeaRankListVo;
import com.accompany.business.service.activities.vo.LuckySeaRankVo;
import com.accompany.business.service.user.UsersService;
import com.accompany.common.constant.Constant;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.model.Users;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Slf4j
public class LuckySeaRankServiceImpl implements LuckySeaRankService {
@Autowired
private UsersService usersService;
@Autowired
private LuckySeaActMapper luckySeaActMapper;
@Override
public LuckySeaRankVo listRank(Integer type, Integer page, Integer pageSize, Long uid) {
LuckySeaRankVo vo = new LuckySeaRankVo();
List<LuckySeaRankListVo> rankList = null;
LuckySeaRankListVo userRankInfo = null;
Date now = new Date();
Date beginTimeOfDay = DateTimeUtil.getBeginTimeOfDay(now);
Date endTimeOfDay = DateTimeUtil.getEndTimeOfDay(now);
int start = (page - 1) * pageSize;
if (type.equals(Constant.LuckySeaRankType.DIAMOND_RANK)) {
rankList = luckySeaActMapper.listDiamondRank(start, pageSize, beginTimeOfDay, endTimeOfDay);
userRankInfo = luckySeaActMapper.listUserDiamondRank(uid, beginTimeOfDay, endTimeOfDay);
} else if (type.equals(Constant.LuckySeaRankType.LUCKY_MAN_RANK)) {
rankList = luckySeaActMapper.listLuckyManRank(start, pageSize, beginTimeOfDay, endTimeOfDay);
userRankInfo = luckySeaActMapper.listUserLuckyManRank(uid, beginTimeOfDay, endTimeOfDay);
}
if (null == rankList){
rankList = new ArrayList<>();
}
if (null == userRankInfo){
userRankInfo = new LuckySeaRankListVo();
userRankInfo.setUid(uid);
}
vo.setRankList(rankList);
vo.setMyRankInfo(userRankInfo);
List<LuckySeaRankListVo> all = new ArrayList<>(rankList);
all.add(userRankInfo);
List<Long> uids = all.stream().map(LuckySeaRankListVo::getUid).distinct().collect(Collectors.toList());
Map<Long, Users> usersMap = usersService.getUsersMapByUids(uids);
for (LuckySeaRankListVo e: all){
Users u = usersMap.get(e.getUid());
if (null == u){
continue;
}
e.setErbanNo(u.getErbanNo());
e.setNick(u.getNick());
e.setAvatar(u.getAvatar());
}
return vo;
}
}

View File

@@ -0,0 +1,72 @@
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.model.activity.LuckySeaUserDrawRecord;
import com.accompany.business.mybatismapper.activity.LuckySeaUserDrawRecordMapper;
import com.accompany.business.service.activities.luckySea.LuckySeaUserDrawRecordService;
import com.accompany.common.constant.Constant;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2021/1/4]
*/
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class LuckySeaUserDrawRecordServiceImpl extends ServiceImpl<LuckySeaUserDrawRecordMapper, LuckySeaUserDrawRecord>
implements LuckySeaUserDrawRecordService {
@Override
public boolean updateUserDrawRecord(Long uid, Long roomUid, String roundId, LuckySeaItem item, Long costPieceNum) {
Date now = new Date();
Long itemId = item.getId();
boolean succeed = false;
QueryWrapper<LuckySeaUserDrawRecord> wrapper = Wrappers.query();
wrapper.lambda().eq(LuckySeaUserDrawRecord::getUid, uid).eq(LuckySeaUserDrawRecord::getRoundId, roundId)
.eq(LuckySeaUserDrawRecord::getItemId, itemId);
LuckySeaUserDrawRecord record = getOne(wrapper);
log.info("更新用户单轮消耗碎片数操作前, uid:{},roundId:{},itemId:{},costPiece:{}",
uid, roundId, itemId, record == null ? 0 : record.getCostPriceNum());
if (record == null) {
record = new LuckySeaUserDrawRecord();
record.setUid(uid);
record.setRoomUid(roomUid);
record.setRoundId(roundId);
record.setItemId(itemId);
record.setItemName(item.getName());
record.setItemUrl(item.getImgUrl());
record.setItemMultiple(item.getMultiple());
record.setCostPriceNum(costPieceNum);
record.setDrawStatus(Constant.LuckySeaUserStatus.NOT_WIN);
record.setCreateTime(now);
record.setUpdateTime(now);
succeed = save(record);
} else {
UpdateWrapper<LuckySeaUserDrawRecord> updateWrapper = Wrappers.update();
updateWrapper.lambda().eq(LuckySeaUserDrawRecord::getId, record.getId())
.eq(LuckySeaUserDrawRecord::getDrawStatus, Constant.LuckySeaUserStatus.NOT_WIN)
.set(LuckySeaUserDrawRecord::getRoomUid, roomUid)
.set(LuckySeaUserDrawRecord::getCostPriceNum, record.getCostPriceNum() + costPieceNum)
.set(LuckySeaUserDrawRecord::getUpdateTime, now);
succeed = update(updateWrapper);
}
log.info("更新用户单轮消耗碎片数操作后, succeed:{},uid:{},roomUid:{},roundId:{},itemId:{},costPiece:{}",
succeed, uid, roomUid, roundId, itemId,
succeed? record.getCostPriceNum() + costPieceNum: record.getCostPriceNum());
return succeed;
}
}

View File

@@ -8,13 +8,12 @@
* 修改内容:
* 修改时间:
*/
package com.accompany.business.service.activities.impl;
package com.accompany.business.service.activities.luckySea.impl;
import com.accompany.business.model.activity.LuckySeaUserDrawResult;
import com.accompany.business.mybatismapper.activity.LuckySeaUserDrawResultMapper;
import com.accompany.business.service.activities.LuckySeaUserDrawResultService;
import com.accompany.business.service.activities.luckySea.LuckySeaUserDrawResultService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

View File

@@ -11,7 +11,7 @@ import com.accompany.business.mybatismapper.UserActivityPackRecordMapper;
import com.accompany.business.param.neteasepush.NeteaseSendMsgParam;
import com.accompany.business.service.SendSysMsgService;
import com.accompany.business.service.activities.ActivitiesDrawService;
import com.accompany.business.service.activities.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.box.BoxPrizeContext;
import com.accompany.business.service.box.BoxPrizeStrategyFactory;
import com.accompany.business.service.purse.UserPurseService;

View File

@@ -1,13 +1,3 @@
/*
* 文 件 名: LuckySeaActUserDrawItemVO
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/1/12
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.vo.activities;
import com.accompany.business.model.activity.LuckySeaItem;
@@ -24,8 +14,21 @@ import lombok.Data;
*/
@Data
@ApiModel
public class LuckySeaActUserDrawItemVO extends LuckySeaItem {
public class LuckySeaActUserDrawItemVO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("图片")
private String imgUrl;
@ApiModelProperty("倍数")
private Integer multiple;
@ApiModelProperty(value = "用户此轮投的碎片数")
private Integer costPieceNum;
}

View File

@@ -18,87 +18,80 @@
</resultMap>
<select id="listDiamondRank" resultMap="luckySeaRankListVo">
select u.uid, u.avatar, u.erban_no, u.nick,
IFNULL(SUM(cost_piece_num * item_multiple),0) num
from lucky_sea_user_draw_record d, users u, lucky_sea_act_info a
where draw_status = 1 and d.uid = u.uid and d.round_id = a.round_id
select uid, SUM(cost_piece_num * item_multiple) num
from lucky_sea_user_draw_record
where draw_status = 1
<if test="null != startTime">
and a.end_time >= #{startTime}
and update_time >= #{startTime}
</if>
<if test="null != endTime">
and a.end_time &lt;= #{endTime}
and update_time &lt;= #{endTime}
</if>
group by d.uid
order BY num desc
group by uid
order by num desc
limit #{start}, #{pageSize}
</select>
<select id="listLuckyManRank" resultMap="luckySeaRankListVo">
select u.uid, u.avatar, u.erban_no, u.nick, count(1) num
from lucky_sea_user_draw_record d, users u, lucky_sea_act_info a
where draw_status = 1 and d.uid = u.uid and d.round_id = a.round_id
<select id="listUserDiamondRank" resultMap="luckySeaRankListVo">
select uid, SUM(cost_piece_num * item_multiple) num
from lucky_sea_user_draw_record
where uid = #{uid}
and draw_status = 1
<if test="null != startTime">
and a.end_time >= #{startTime}
and update_time >= #{startTime}
</if>
<if test="null != endTime">
and a.end_time &lt;= #{endTime}
and update_time &lt;= #{endTime}
</if>
group by d.uid
group by uid
</select>
<select id="listLuckyManRank" resultMap="luckySeaRankListVo">
select uid, count(distinct round_id) num
from lucky_sea_user_draw_record
where draw_status = 1
<if test="null != startTime">
and update_time >= #{startTime}
</if>
<if test="null != endTime">
and update_time &lt;= #{endTime}
</if>
group by uid
order by num desc
limit #{start}, #{pageSize}
</select>
<select id="listUserDiamondRank" resultMap="luckySeaRankListVo">
SELECT u.uid, u.avatar, u.erban_no, u.nick, IFNULL(t.num, 0) num
FROM users u
LEFT JOIN
(SELECT r.uid, IFNULL(SUM(r.cost_piece_num * r.item_multiple),0) num FROM
lucky_sea_user_draw_record r LEFT JOIN lucky_sea_act_info a ON r.round_id = a.round_id
WHERE r.draw_status = 1
<if test="null != startTime">
and a.end_time >= #{startTime}
</if>
<if test="null != endTime">
and a.end_time &lt;= #{endTime}
</if>
GROUP BY r.uid) t ON u.uid = t.uid
WHERE u.uid = #{uid}
</select>
<select id="listUserLuckyManRank" resultMap="luckySeaRankListVo">
SELECT u.uid, u.avatar, u.erban_no, u.nick, IFNULL(t.num, 0) num
FROM users u
LEFT JOIN
(SELECT r.uid, count(1) num FROM
lucky_sea_user_draw_record r LEFT JOIN lucky_sea_act_info a ON r.round_id = a.round_id
WHERE r.draw_status = 1
select uid, count(distinct round_id) num
from lucky_sea_user_draw_record
where uid = #{uid}
and draw_status = 1
<if test="null != startTime">
and a.end_time >= #{startTime}
and update_time >= #{startTime}
</if>
<if test="null != endTime">
and a.end_time &lt;= #{endTime}
and update_time &lt;= #{endTime}
</if>
GROUP BY r.uid) t ON u.uid = t.uid
WHERE u.uid = #{uid}
group by uid
</select>
<select id="countUserDiamondIncome" resultType="java.lang.Double">
SELECT IFNULL(SUM(d.cost_piece_num * d.item_multiple),0)
FROM `lucky_sea_user_draw_record` d , lucky_sea_act_info a where d.uid = #{uid} and d.draw_status = 1
and d.round_id = a.round_id
and DATE(a.end_time) >= #{startTime}
and DATE(a.end_time) &lt; #{endTime}
FROM `lucky_sea_user_draw_record` d
where d.uid = #{uid}
and d.create_time >= #{startTime}
and d.create_time &lt;= #{endTime}
and d.draw_status = 1
</select>
<select id="listTopThreeInOneRound" resultMap="luckySeaActRoundRankUserVo">
SELECT u.uid, u.erban_no erbanNo, u.nick, u.avatar, d.cost_piece_num * d.item_multiple prizeDiamonds
FROM `lucky_sea_user_draw_record` d, users u
where d.round_id = #{roundId}
and d.draw_status = 1
and d.uid = u.uid
ORDER BY d.cost_piece_num DESC, d.uid ASC
LIMIT 3
SELECT uid, cost_piece_num * item_multiple prizeDiamonds
FROM `lucky_sea_user_draw_record`
where round_id = #{roundId}
and draw_status = 1
group by uid
ORDER BY cost_piece_num DESC, uid ASC
LIMIT 3
</select>
<select id="countUserInputPiece" resultType="java.lang.Long">
@@ -127,25 +120,16 @@
</update>
<resultMap id="luckySeaActUserDrawItemVO" type="com.accompany.business.vo.activities.LuckySeaActUserDrawItemVO">
<result column="id" property="id" jdbcType="BIGINT"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="image_url" property="imgUrl" jdbcType="VARCHAR"/>
<result column="multiple" property="multiple" jdbcType="INTEGER"/>
<result column="costPieceNum" property="costPieceNum" jdbcType="INTEGER"/>
<result column="item_id" property="id" jdbcType="BIGINT"/>
<result column="cost_piece_num" property="costPieceNum" jdbcType="INTEGER"/>
</resultMap>
<select id="listUserDrawItemInfo" resultMap="luckySeaActUserDrawItemVO">
SELECT i.id, i.name,i.image_url,i.multiple,
IFNULL(r.cost_piece_num,0) costPieceNum
from lucky_sea_item i LEFT JOIN
lucky_sea_user_draw_record r ON i.id = r.item_id
AND r.round_id = #{roundId}
and r.uid = #{uid}
WHERE i.status = 1
ORDER BY i.multiple ASC;
SELECT r.item_id, r.cost_piece_num,
from lucky_sea_user_draw_record r
where r.round_id = #{roundId} and r.uid = #{uid}
</select>
<resultMap id="luckySeaActUserRoundStatDTO" type="com.accompany.business.dto.LuckySeaActUserRoundStatDTO">
<result column="uid" property="uid" jdbcType="BIGINT"/>
<result column="costPieceNum" property="costPieceNum" jdbcType="BIGINT"/>

View File

@@ -1,29 +1,22 @@
/*
* 文 件 名: ActivitiesLuckySeaController
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2020/12/30
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.controller.activities;
import com.accompany.business.common.BaseController;
import com.accompany.business.config.LuckySeaActConfig;
import com.accompany.business.constant.activities.ActivitesPackTypeEnum;
import com.accompany.business.model.ActivityPack;
import com.accompany.business.model.activity.LuckySeaActInfo;
import com.accompany.business.param.activity.LuckySeaActDrawParams;
import com.accompany.business.service.activities.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.vo.LuckySeaActUserDrawRecordVo;
import com.accompany.business.service.activities.vo.LuckySeaActUserInfo;
import com.accompany.business.service.activities.vo.LuckySeaRankVo;
import com.accompany.business.service.activity.ActivityPackService;
import com.accompany.business.vo.activities.LuckySeaActInfoVo;
import com.accompany.business.vo.activities.LuckySeaActUserDrawItemVO;
import com.accompany.common.annotation.Authorization;
import com.accompany.common.constant.Constant;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.enumeration.BusinessStatusCodeEnum;
import com.accompany.core.vo.BaseRequestVO;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.vo.BaseResponseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@@ -31,11 +24,9 @@ import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@@ -49,64 +40,81 @@ import java.util.List;
@RequestMapping("/act/luckySea")
@Slf4j
@Api(tags = "深海奇缘活动")
public class ActivitiesLuckySeaController {
public class ActivitiesLuckySeaController extends BaseController {
@Autowired
private ActivityPackService activityPackService;
@Autowired
private ActivitiesLuckySeaService activitiesLuckySeaService;
@ApiOperation("获取游戏各阶段的时间配置")
@GetMapping("/getTimeConfig")
public BaseResponseVO<LuckySeaActConfig> getActTimeConfig() {
return new BaseResponseVO<>(activitiesLuckySeaService.getLuckySeaTimeConfig());
}
@ApiOperation("获取活动礼包列表")
@RequestMapping(value = "/listPack", method = RequestMethod.GET)
@GetMapping("/listPack")
@Deprecated
public BaseResponseVO<List<ActivityPack>> listPack() {
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activityPackService.getPackListByType(ActivitesPackTypeEnum.LUCKY_SEA.getValue().byteValue()));
}
@ApiOperation(tags = "获取用户活动信息", value = "获取用户活动信息,包含用户基本信息,碎片数、钻石数与今日收益")
@RequestMapping(value = "/getUserActInfo", method = RequestMethod.GET)
public BaseResponseVO<LuckySeaActUserInfo> getUserLuckySeaActInfo() {
BaseRequestVO baseRequestVO = new BaseRequestVO();
Long myUserId = baseRequestVO.getMyUserId();
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.getUserLuckySeaActInfo(myUserId));
}
@ApiOperation("获取活动配置列表")
@RequestMapping(value = "/listItem", method = RequestMethod.GET)
public BaseResponseVO<List<LuckySeaActUserDrawItemVO>> listItem(String roundId) {
BaseRequestVO baseRequestVO = new BaseRequestVO();
Long myUserId = baseRequestVO.getMyUserId();
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.listUserDrawItemInfo(myUserId, roundId));
}
@ApiOperation("获取指定数量的中奖纪录")
@ApiImplicitParams({
@ApiImplicitParam(name = "count", value = "需要获取的条数", required = false, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "roundId", value = "当前进行轮的roundId", required = false, dataType = "String", paramType = "query"),
})
@RequestMapping(value = "/listLuckySeaActInfo", method = RequestMethod.GET)
public BaseResponseVO<List<LuckySeaActInfo>> listLuckySeaActInfo(Integer count, String roundId) {
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.listLuckySeaActInfo(count, roundId));
return new BaseResponseVO<>(activityPackService.getPackListByType(ActivitesPackTypeEnum.LUCKY_SEA.getValue().byteValue()));
}
@ApiOperation("获取最新一次的深海奇缘活动信息")
@RequestMapping(value = "/getNewestAct", method = RequestMethod.GET)
public BaseResponseVO<LuckySeaActInfoVo> getNewestLuckySeaActInfo() {
BaseRequestVO baseRequestVO = new BaseRequestVO();
Long myUserId = baseRequestVO.getMyUserId();
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.getNewestLuckySeaActInfo(myUserId));
@GetMapping("/getNewestAct")
@Authorization
public BaseResponseVO<LuckySeaActInfoVo> getNewestLuckySeaActInfo(HttpServletRequest request) {
Long myUserId = getUid(request);
return new BaseResponseVO<>(activitiesLuckySeaService.getNewestLuckySeaActInfo(myUserId));
}
@ApiOperation(tags = "获取用户活动信息", value = "获取用户活动信息,包含用户基本信息,碎片数、钻石数与今日收益")
@GetMapping("/getUserActInfo")
@Authorization
public BaseResponseVO<LuckySeaActUserInfo> getUserLuckySeaActInfo(HttpServletRequest request) {
Long myUserId = getUid(request);
return new BaseResponseVO<>(activitiesLuckySeaService.getUserLuckySeaActInfo(myUserId));
}
@ApiOperation("获取活动配置列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "roundId", value = "当前进行轮的roundId"),
})
@GetMapping("/listItem")
@Authorization
public BaseResponseVO<List<LuckySeaActUserDrawItemVO>> listItem(HttpServletRequest request, String roundId) {
Long myUserId = getUid(request);
return new BaseResponseVO<>(activitiesLuckySeaService.listUserDrawItemInfo(myUserId, roundId));
}
@ApiOperation("获取指定数量的中奖纪录,往轮结果")
@ApiImplicitParams({
@ApiImplicitParam(name = "count", value = "需要获取的条数"),
@ApiImplicitParam(name = "roundId", value = "当前进行轮的roundId"),
})
@GetMapping("/listLuckySeaActInfo")
public BaseResponseVO<List<LuckySeaActInfo>> listLuckySeaActInfo(Integer count, String roundId) {
if (null == count){
throw new ServiceException(BusiStatus.PARAMERROR);
}
return new BaseResponseVO<>(activitiesLuckySeaService.listLuckySeaActInfo(count, roundId));
}
@ApiOperation("获取深海奇缘活动榜单信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "type", value = "榜单类型(1:钻石榜 2:欧皇榜)", required = true, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "page", value = "页数", required = false, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页大小", required = false, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "page", value = "页数", dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页大小", dataType = "Integer", paramType = "query"),
})
@RequestMapping(value = "/listRank", method = RequestMethod.GET)
public BaseResponseVO<LuckySeaRankVo> listRank(Integer type, Integer page, Integer pageSize) {
BaseRequestVO baseRequestVO = new BaseRequestVO();
Long myUserId = baseRequestVO.getMyUserId();
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.listRank(type, page, pageSize, myUserId));
@GetMapping("/listRank")
@Authorization
public BaseResponseVO<LuckySeaRankVo> listRank(HttpServletRequest request,
Integer type, Integer page, Integer pageSize) {
if (null == type || null == page || null == pageSize) {
throw new ServiceException(BusiStatus.PARAMERROR);
}
Long myUserId = getUid(request);
return new BaseResponseVO<>(activitiesLuckySeaService.listRank(type, page, pageSize, myUserId));
}
@ApiOperation("抽奖")
@@ -114,29 +122,30 @@ public class ActivitiesLuckySeaController {
@ApiImplicitParam(name = "itemId", value = "选择的配置id", required = true, dataType = "number", paramType = "body"),
@ApiImplicitParam(name = "num", value = "选择的配置数量", required = true, dataType = "number", paramType = "body")
})
@RequestMapping(value = "/draw", method = RequestMethod.POST)
public BaseResponseVO<Void> draw(LuckySeaActDrawParams param) {
BaseRequestVO baseRequestVO = new BaseRequestVO();
Long myUserId = baseRequestVO.getMyUserId();
activitiesLuckySeaService.draw(myUserId, param);
@PostMapping("/draw")
@Authorization
public BaseResponseVO<Void> draw(HttpServletRequest request, Long itemId, Long num) {
if (null == itemId || null == num || num <= 0){
throw new ServiceException(BusiStatus.PARAMERROR);
}
Long myUserId = getUid(request);
activitiesLuckySeaService.draw(myUserId, itemId, num);
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS);
}
@ApiOperation("分页获取用户的游戏记录")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "页数", required = false, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页大小", required = false, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "page", value = "页数", dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页大小", dataType = "Integer", paramType = "query"),
})
@RequestMapping(value = "/listDrawRecord", method = RequestMethod.GET)
public BaseResponseVO<List<LuckySeaActUserDrawRecordVo>> listUserDrawRecord(Integer page, Integer pageSize) {
BaseRequestVO baseRequestVO = new BaseRequestVO();
Long myUserId = baseRequestVO.getMyUserId();
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.listUserDrawResult(myUserId, page, pageSize));
@GetMapping("/listDrawRecord")
public BaseResponseVO<List<LuckySeaActUserDrawRecordVo>> listUserDrawRecord(HttpServletRequest request,
Integer page, Integer pageSize) {
if (null == page || null == pageSize) {
throw new ServiceException(BusiStatus.PARAMERROR);
}
Long myUserId = getUid(request);
return new BaseResponseVO<>(activitiesLuckySeaService.listUserDrawResult(myUserId, page, pageSize));
}
@ApiOperation("获取游戏各阶段的时间配置")
@RequestMapping(value = "/getTimeConfig", method = RequestMethod.GET)
public BaseResponseVO<LuckySeaActConfig> getActTimeConfig() {
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, activitiesLuckySeaService.getLuckySeaTimeConfig());
}
}

View File

@@ -11,8 +11,7 @@
package servicetest;
import com.accompany.business.BusinessApplication;
import com.accompany.business.dto.LuckySeaUserDrawResultDto;
import com.accompany.business.service.activities.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.vo.LuckySeaRankVo;
import com.alibaba.fastjson.JSON;
import org.junit.Test;
@@ -21,9 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.List;
/**
* <br>类描述:
* <br>功能详细描述:

View File

@@ -1,149 +1,38 @@
package com.accompany.scheduler.task.activity;
import com.accompany.business.config.LuckySeaActConfig;
import com.accompany.business.model.activity.LuckySeaItem;
import com.accompany.business.service.LuckySeaPreWarningService;
import com.accompany.business.service.activities.ActivitiesLuckySeaService;
import com.accompany.business.vo.activities.LuckySeaActInfoVo;
import com.accompany.business.service.activities.luckySea.LuckySeaDrawService;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.service.SysConfService;
import com.accompany.core.service.common.JedisLockService;
import com.accompany.scheduler.base.BaseTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* <br>类描述:
* <br>功能详细描述:
*
* @author H1
* @date [2021/1/6]
*/
@Component
@Slf4j
public class LuckySeaActTask extends BaseTask {
public class LuckySeaActTask extends BaseTask implements InitializingBean, Runnable {
@Autowired
private ActivitiesLuckySeaService activitiesLuckySeaService;
@Autowired
private SysConfService sysConfService;
@Autowired
private JedisLockService jedisLockService;
@Autowired
private LuckySeaPreWarningService luckySeaPreWarningService;
@PostConstruct
public void handleLuckySeaAct() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
runTask();
}
});
@Autowired
private LuckySeaDrawService drawService;
@Override
public void afterPropertiesSet() throws Exception {
Executors.newSingleThreadExecutor().execute(this);
}
public void runTask() {
@Override
public void run() {
while (true) {
// 活动开关是否开着
Boolean actSwitch = Optional.of(
Boolean.parseBoolean(sysConfService.getSysConfValueById(Constant.SysConfId.LUCKY_SEA_SWITCH))).orElse(false);
log.info("星级厨房活动, 开关状态: {}", actSwitch);
if (actSwitch) {
String roundId = null;
Date nextRoundStartTime = null;
Long stock = activitiesLuckySeaService.getStock();
// 获取游戏的配置
List<LuckySeaItem> itemList = activitiesLuckySeaService.listLuckySeaItem();
LuckySeaActConfig timeConfig = activitiesLuckySeaService.getLuckySeaTimeConfig();
int totalTime = timeConfig.getWaitingDrawStageTime() + timeConfig.getChooseStageTime() + timeConfig.getDrawOverStageTime();
// 加锁,确保创建与开奖是单线程执行
String lockVal = jedisLockService.lock(RedisKey.lucky_sea_run_task.getKey(), 10 * 1000, totalTime * 1000);
if (StringUtils.isBlank(lockVal)) {
log.info("春日游园活动, 获取锁失败");
break;
}
long drawMills = 0L;
try {
boolean needCreateNewAct = true;
boolean needWaitUserDraw = true;
Integer waitUserDrawTime = timeConfig.getChooseStageTime();
// 处理异常活动
LuckySeaActInfoVo lastLuckySeaActInfo = activitiesLuckySeaService.getNewestLuckySeaActInfo(null);
if (null != lastLuckySeaActInfo && StringUtils.isNotBlank(lastLuckySeaActInfo.getRoundId())) {
if (lastLuckySeaActInfo.getStatus().equals(Constant.LuckySeaActStatus.CHOOSE_STAGE)) {
needCreateNewAct = false;
roundId = lastLuckySeaActInfo.getRoundId();
Long intervalSecond = (System.currentTimeMillis() - lastLuckySeaActInfo.getStartTime().getTime()) / 1000;
log.info("春日游园活动, 上一轮投注时间发生异常的活动到现在的间隔时间{}秒, roundId:{}", intervalSecond, roundId);
if (intervalSecond <= timeConfig.getChooseStageTime()) {
waitUserDrawTime = timeConfig.getChooseStageTime() - intervalSecond.intValue();
log.info("春日游园活动, 上一轮投注时间发生异常的活动留给用户的下注时间{}秒", waitUserDrawTime);
} else {
log.info("春日游园活动, 上一轮投注时间发生异常的活动直接进行开奖, roundId:{}", roundId);
needWaitUserDraw = false;
}
} else if (lastLuckySeaActInfo.getStatus().equals(Constant.LuckySeaActStatus.DRAWING)) {
needCreateNewAct = false;
needWaitUserDraw = false;
roundId = lastLuckySeaActInfo.getRoundId();
log.info("春日游园活动, 上一轮投注时间发生异常的活动直接进行开奖, roundId:{}", roundId);
}
}
// 创建新的一轮游戏
if (needCreateNewAct) {
roundId = activitiesLuckySeaService.createNewRoundAct(nextRoundStartTime,timeConfig.getChooseStageTime() );
}
// 等待用户投碎片
if (needWaitUserDraw) {
log.info("春日游园活动, 开始等待用户投入碎片, currTime: {}", System.currentTimeMillis());
Thread.sleep(waitUserDrawTime * 1000);
log.info("春日游园活动, 结束等待用户投入碎片, currTime: {}", System.currentTimeMillis());
}
activitiesLuckySeaService.updateLuckyActStatus(roundId, Constant.LuckySeaActStatus.DRAWING);
// 开奖
drawMills = activitiesLuckySeaService.luckySeaActDraw(itemList, roundId, timeConfig, stock);
} catch (Exception e) {
// 更新活动状态, 此轮游戏标识为异常,不开始下一轮游戏
log.error("春日游园活动开奖时出现异常, roundId: " + roundId, e);
activitiesLuckySeaService.updateLuckyActStatus(roundId, Constant.LuckySeaActStatus.GAME_ABNORMAL);
activitiesLuckySeaService.compensateUserPieceWhenGameAbnormal(roundId, stock);
break;
} finally {
jedisLockService.unlock(RedisKey.lucky_sea_run_task.getKey(), lockVal);
}
try {
// 异步更新用户抽奖记录
activitiesLuckySeaService.updateUserDrawRecordAsync(roundId, itemList);
// 等待开奖动画与页面渲染开奖结果时间
long sleepMills = (timeConfig.getDrawOverStageTime() + timeConfig.getWaitingDrawStageTime()) * 1000
- drawMills;
if (sleepMills > 0) {
log.info("春日游园活动, 等待开奖动画与页面渲染开奖结果时间{}毫秒", sleepMills);
Thread.sleep(sleepMills);
}
log.info("春日游园活动此轮结束, roundId:{}", roundId);
// 异步更新活动endTime
nextRoundStartTime = new Date();
activitiesLuckySeaService.endLuckyAct(roundId, nextRoundStartTime);
// 进行预警数据统计
luckySeaPreWarningService.handleGoldPreWarning();
} catch (Exception e) {
// 更新活动状态
log.error("春日游园活动更新用户抽奖记录与分发奖励时出现异常, roundId: " + roundId, e);
activitiesLuckySeaService.updateLuckyActStatus(roundId, Constant.LuckySeaActStatus.SUCCESS_DRAW_UPDATE_DATA_FAIL);
}
} else {
boolean actSwitch = Boolean.parseBoolean(sysConfService.getDefaultSysConfValueById(Constant.SysConfId.LUCKY_SEA_SWITCH, "false"));
log.info("春日游园活动, 开关状态: {}", actSwitch);
if (!actSwitch){
try {
log.info("春日游园活动, 开关未开启,线程进入休眠: {}", actSwitch);
Thread.sleep(60 * 1000);
@@ -152,6 +41,7 @@ public class LuckySeaActTask extends BaseTask {
log.error("春日游园活动线程休眠时出现异常", e);
}
}
drawService.start();
}
}
}