概要
竞猜模块的流程涉及到主播开启竞猜,用户参与竞猜,以及用户参与一方之后就不能再参与另一方,还有竞猜的结算,竞猜结算要考虑到平局和流局的情况
整体架构流程
下面是创建竞猜的代码案例
hash存储,大key是guessing,小key是主播id,value是竞猜对象数据,同时会创建两个hash奖池用来存储红蓝方的参与人的id及下注的金额
//hash存竞猜信息
BoundHashOperations guessing = redisTemplate.boundHashOps("guessing");
tbGuessingVo.setGuessStatus("0");
guessing.put(tbGuessingVo.getAid(),tbGuessingVo);
TbGuessing tbGuessing = new TbGuessing();
BeanUtils.copyProperties(tbGuessingVo,tbGuessing);
tbGuessingMapper.insert(tbGuessing);
//hash存竞猜选项1
TbGuessingOptions options = new TbGuessingOptions();
options.setGuessId(tbGuessing.getGuessId());
options.setAttr1(0);
options.setOnum(0L);
options.setOmoney(0L);
BoundHashOperations guessing1 = redisTemplate.boundHashOps(tbGuessing.getGuessId()+":"+options.getAttr1());
guessing1.put(options.getOnum(),options.getOmoney());
tbGuessingOptionsMapper.insert(options);
//hash存竞猜选项2
TbGuessingOptions options1 = new TbGuessingOptions();
options1.setGuessId(tbGuessing.getGuessId());
options1.setAttr1(1);
options1.setOnum(0L);
options1.setOmoney(0L);
BoundHashOperations guessing2 = redisTemplate.boundHashOps(tbGuessing.getGuessId()+":"+options1.getAttr1());
guessing2.put(options1.getOnum(),options1.getOmoney());
tbGuessingOptionsMapper.insert(options1);
然后是用户参与竞猜
一开始会判断前端传来的竞猜选项是红蓝哪一方,然后判断该用户是否在另一方下过注,如果下过就直接报错,然后向前端提示已经在另一方下过注,否则就查出该用户选择的阵营然后判断该用户是否在改阵营下过注,如果下过就在原基础上进行一个追加,没有就创建一个该用户的记录,最后远程调用用户服务对用户的金额进行一个扣减.
//判断用户选择的竞猜选项
if (tbGuessingVo.getAttr1() == 0){
//判断是否在另一个奖池下过注没
BoundHashOperations hashOps1 = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + 1);
if (hashOps1.get(uid) != null){
throw new RuntimeException("竞猜选项已存在");
}
//查出对应的竞猜选项,然后进行追加竞猜选项的人数和分数
BoundHashOperations hashOps = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + tbGuessingVo.getAttr1());
//判断用户是否竞猜过
if (hashOps.get(uid) != null){
Long o = (Long)hashOps.get(uid);
o += (long)tbGuessingVo.getNum();
hashOps.put(uid,o);
hashOps.delete(0L);
}else{
hashOps.put(uid,(long)tbGuessingVo.getNum());
hashOps.delete(0L);
}
}else{
//判断是否在另一个奖池下过注没
BoundHashOperations hashOps1 = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + 0);
if (hashOps1.get(uid) != null){
throw new RuntimeException("竞猜选项已存在");
}
//查出对应的竞猜选项,然后进行追加竞猜选项的分数
BoundHashOperations hashOps = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + tbGuessingVo.getAttr1());
//判断用户是否竞猜过
if (hashOps.get(uid) != null){
Long o = (Long) hashOps.get(uid);
o += (long)tbGuessingVo.getNum();
hashOps.put(uid,o);
hashOps.delete(0L);
}else{
hashOps.put(uid,(long)tbGuessingVo.getNum());
hashOps.delete(0L);
}
}
tbUserApi.subtractMoney(uid,(long)tbGuessingVo.getNum());
最后是竞猜的结算
首先判断竞猜状态是结束还是流盘,如果是结束就把竞猜记录入库然后查寻redis,查出胜利方和失败方的全部人的id,以及下注金额,然后进行一个入库,我们是通过向胜利方,算出他们每个人下注的占比进行瓜分失败方的总奖池,然后他们下注的金额会原路返回.通过把用户id和赢得的金额进行封装存入list,最后远程调用用户服务进行用户的金额添加.如果是流盘就把用户下注的金额进行原路返还(平局和流盘是一样的).
TbGuessing tbGuessing = new TbGuessing();
BeanUtils.copyProperties(tbGuessingVo,tbGuessing);
//结束竞猜
if (tbGuessingVo.getGuessStatus().equals("3")){
tbGuessingMapper.updateById(tbGuessing);
//存入竞猜记录表
TbGuessingHistory history = new TbGuessingHistory();
history.setUid(uid);
history.setGuessId(tbGuessingVo.getGuessId());
history.setLid(tbGuessingVo.getLid());
tbspHistoryMapper.insert(history);
//从redis取出竞猜选项总金额和猜对的人数
if (tbGuessingVo.getAttr1() == 0){
//查出失败方奖池中的金额
BoundHashOperations ops1 = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + 1);
Set keys1 = ops1.keys();
AtomicReference<Long> num1 = new AtomicReference<>((long) 0);
keys1.forEach(key -> {
num1.updateAndGet(v -> v + 1);
});
List<Long> values1 = ops1.values();
Long sum1 = Long.valueOf(0);
for (Long intValue : values1) {
sum1 += intValue;
}
//入库数据
TbGuessingOptions options1 = new TbGuessingOptions();
options1.setGuessId(tbGuessingVo.getGuessId());
options1.setOnum(num1.get());
options1.setOmoney(sum1);
options1.setAttr1(1);
tbGuessingOptionsMapper.updateByGuessIdAndAttr1(options1);
//获取胜利方奖池总额
BoundHashOperations ops = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + tbGuessingVo.getAttr1());
Set keys = ops.keys();
AtomicReference<Long> num = new AtomicReference<>((long) 0);
keys.forEach(key -> {
num.updateAndGet(v -> v + 1);
});
List<Long> values = ops.values();
Long sum = Long.valueOf(0);
for (Long intValue : values) {
sum += intValue;
}
//入库数据
TbGuessingOptions options = new TbGuessingOptions();
options.setGuessId(tbGuessingVo.getGuessId());
options.setOnum(num.get());
options.setOmoney(sum);
options.setAttr1(0);
tbGuessingOptionsMapper.updateByGuessIdAndAttr1(options);
List<TbUser> list = new ArrayList<>();
//向胜利方发放虚拟币
for (Object key : keys) {
//获取每个人的押注
Object value = ops.get(key);
//计算用户赢得的虚拟币
Long money = (sum1 / sum * (Long) value + (Long) value);
//远程调用给用户增加金额
TbUser tbUser = new TbUser();
tbUser.setUid((Long) key);
tbUser.setPurse(BigDecimal.valueOf(money));
list.add(tbUser);
}
tbUserApi.addMoney1(list);
} else if (tbGuessingVo.getAttr1() == 1) {
//查出失败方奖池中的金额
BoundHashOperations ops1 = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + 0);
Set keys1 = ops1.keys();
AtomicReference<Long> num1 = new AtomicReference<>((long) 0);
keys1.forEach(key -> {
num1.updateAndGet(v -> v + 1);
});
List<Long> values1 = ops1.values();
Long sum1 = Long.valueOf(0);
for (Long intValue : values1) {
sum1 += intValue;
}
//入库数据
TbGuessingOptions options1 = new TbGuessingOptions();
options1.setGuessId(tbGuessingVo.getGuessId());
options1.setOnum(num1.get());
options1.setOmoney(sum1);
options1.setAttr1(0);
tbGuessingOptionsMapper.updateByGuessIdAndAttr1(options1);
//获取胜利方奖池总额
BoundHashOperations ops = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + tbGuessingVo.getAttr1());
Set keys = ops.keys();
AtomicReference<Long> num = new AtomicReference<>((long) 0);
keys.forEach(key -> {
num.updateAndGet(v -> v + 1);
});
List<Long> values = ops.values();
Long sum = Long.valueOf(0);
for (Long intValue : values) {
sum += intValue;
}
//入库数据
TbGuessingOptions options = new TbGuessingOptions();
options.setGuessId(tbGuessingVo.getGuessId());
options.setOnum(num.get());
options.setOmoney(sum);
options.setAttr1(1);
tbGuessingOptionsMapper.updateByGuessIdAndAttr1(options);
//向胜利方发放虚拟币
List<TbUser> list = new ArrayList<>();
for (Object key : keys) {
//获取每个人的押注
Object value = ops.get(key);
//计算用户赢得的虚拟币
Long money = (sum1 / sum * (Long) value + (Long) value);
//远程调用给用户增加金额
TbUser tbUser = new TbUser();
tbUser.setUid((Long) key);
tbUser.setPurse(BigDecimal.valueOf(money));
list.add(tbUser);
}
tbUserApi.addMoney1(list);
}
}else if (tbGuessingVo.getGuessStatus().equals("4")){
//流盘
tbGuessingMapper.updateById(tbGuessing);
List<TbUser> list = new ArrayList<>();
BoundHashOperations ops = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + 0);
Set keys = ops.keys();
for (Object key : keys) {
Long value = (long)ops.get(key);
TbUser tbUser = new TbUser();
tbUser.setUid((Long) key);
tbUser.setPurse( BigDecimal.valueOf(value));
}
BoundHashOperations ops1 = redisTemplate.boundHashOps(tbGuessingVo.getGuessId() + ":" + 1);
Set keys1 = ops1.keys();
for (Object key : keys1) {
Long value = (long)ops1.get(key);
TbUser tbUser = new TbUser();
tbUser.setUid((Long) key);
tbUser.setPurse(BigDecimal.valueOf(value));
}
tbUserApi.addMoney1(list);
}
小结
结算代码没有优化,使用redis的时候注意存入数据的类型要和取出来的一致