概要
流程涉及到主播发放福袋,用户参与福袋,以及福袋的开奖,案例涉及到redis
然后福袋开奖结果类似于某音,每个人获得的虚拟币相差不会太大,不会出现一家独大的情况
整体流程
以下是流程的service层代码案例
创建福袋:
BoundHashOperations bag = redisTemplate.boundHashOps("blessingBag");
//设置福袋状态
tbBlessingBagVo.setBstatus("0");
bag.put(tbBlessingBagVo.getAid(),tbBlessingBagVo);
TbBlessingBag tbBlessingBag = new TbBlessingBag();
BeanUtils.copyProperties(tbBlessingBagVo,tbBlessingBag);
tbBlessingBagMapper.insert(tbBlessingBag);
//往对应的主播账户扣除虚拟币 api(vo.aid,vo.money)
tbAncthorApi.updatePurse(tbBlessingBagVo.getAid(),tbBlessingBagVo.getMoney());
用户参与福袋:
//根据主播的bid去redis创建set用来存放参与的用户的uid
BoundSetOperations<Serializable, Integer> join = redisTemplate.boundSetOps(bid);
join.add(uid);
福袋开奖:
这里写到如果参与人数达不到中奖人数,会把福袋金额分成参与人数的份数去分配
BoundHashOperations bag = redisTemplate.boundHashOps("blessingBag");
//福袋数据
TbBlessingBag tbBlessingBag = (TbBlessingBag) bag.get(aid);
//获取福袋金额
Long a = tbBlessingBag.getMoney();
//获取福袋中奖人数
Integer participants = tbBlessingBag.getNum();
//根据福袋id从redis中取出set集合
BoundSetOperations<java.io.Serializable, Integer> setOps = redisTemplate.boundSetOps(bid);
Set<Integer> members = setOps.members();
Integer num = members.size();
//修改福袋状态
tbBlessingBag.setBstatus("1");
tbBlessingBagMapper.updateById(tbBlessingBag);
//如果参与人数小于中奖人数
if (participants > num){
//随机找出的中奖人的id集合
Set<Integer> randomValues = getRandomValues(members, num);
randomValues = randomValues.stream()
.map(i -> i + 1)
.collect(Collectors.toSet());
//随机金额数组
int[] allocations = distributeVirtualCoins(totalCoins, num);
List<TbUser> list = new ArrayList<>();
int i = 0;
for (Integer randomValue : randomValues) {
TbUser tbUser = new TbUser();
tbUser.setUid(Long.valueOf(randomValue));
tbUser.setPurse(BigDecimal.valueOf(allocations[i]));
list.add(tbUser);
TbBlessingBagWinRecord winRecord = new TbBlessingBagWinRecord();
winRecord.setBid(Long.valueOf(bid));
winRecord.setUid(Long.valueOf(randomValue));
winRecord.setWinMoney((long) allocations[i]);
tbspBagWinRecordMapper.insert(winRecord);
i++;
}
tbUserApi.addMoney1(list);
return JsonResult.SUCCESS().setData(list);
}else{
//随机找出的中奖人的id集合
Set<Integer> randomValues = getRandomValues(members, participants);
randomValues = randomValues.stream()
.map(i -> i + 1)
.collect(Collectors.toSet());
//随机金额数组
int[] allocations = distributeVirtualCoins(totalCoins, participants);
List<TbUser> list = new ArrayList<>();
int i = 0;
for (Integer randomValue : randomValues) {
TbUser tbUser = new TbUser();
tbUser.setUid(Long.valueOf(randomValue));
tbUser.setPurse(BigDecimal.valueOf(allocations[i]));
list.add(tbUser);
TbBlessingBagWinRecord winRecord = new TbBlessingBagWinRecord();
winRecord.setBid(Long.valueOf(bid));
winRecord.setUid(Long.valueOf(randomValue));
winRecord.setWinMoney((long) allocations[i]);
tbspBagWinRecordMapper.insert(winRecord);
i++;
}
tbUserApi.addMoney1(list);
return JsonResult.SUCCESS().setData(list);
}
//算随机金额
private static int[] distributeVirtualCoins(int totalCoins, int participants) {
Random random = new Random();
int[] allocations = new int[participants];
// 初始平均分配
int baseAllocation = totalCoins / participants;
int remainder = totalCoins % participants; // 计算不能平均分配的余数
// 将余数随机加到分配中去
for (int i = 0; i < participants; i++) {
if (i < remainder) {
allocations[i] = baseAllocation + 1;
} else {
allocations[i] = baseAllocation;
}
}
// 随机调整分配,但确保调整幅度小
for (int i = 0; i < allocations.length; i++) {
adjustAllocationWithinRange(allocations, i, 1); // 这里假设最大调整幅度为1
}
return allocations;
}
private static void adjustAllocationWithinRange(int[] allocations, int index, int range) {
Random random = new Random();
// 确保调整在[-range, range]内,并排除0,以实现实际的调整
int adjustment = random.nextInt(2 * range + 1) - range;
// 调整当前索引处的分配,同步调整另一随机选中的分配,以保持总和不变
if (adjustment != 0 && allocations[index] + adjustment >= 0) {
int adjustIndex = (index + random.nextInt(allocations.length - 1) + 1) % allocations.length;
if (allocations[adjustIndex] - adjustment >= 0) { // 确保调整后不会出现负数
allocations[index] += adjustment;
allocations[adjustIndex] -= adjustment;
}
}
}
//算随机人
public static Set<Integer> getRandomValues(Set<Integer> set, int count) {
List<Integer> valuesList = new ArrayList<>(set);
Collections.shuffle(valuesList); // 打乱集合顺序
Set<Integer> randomValues = new HashSet<>();
for (int i = 0; i < Math.min(count, valuesList.size()); i++) {
randomValues.add(valuesList.get(i));
}
return randomValues;
}
小结
在使用redis的时候,记得存进去的数据类型要和取出来的数据类型保持一致.