1、需求
一个抽奖活动中,每个用户可以多次抽奖机会
2、相应类
1、奖品信息类Prize
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Prize {
private Long id;
private String name;
private Integer number;
private double winRate;
}
2、用户类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String name;
}
3、抽奖活动类
@Data
public class Lottery {
private Long id;
private Integer count;
private List<Long> prizeIdList;
}
4、抽奖结果类
@Data
public class LotteryResult {
private Long userId;
private Boolean isWin;
private Prize prize;
}
3、初始化相应信息
1、controller层
@PostMapping("init")
public Lottery init() {
return lotteryService.init();
}
2、service接口层
Lottery init();
3、service接口实现类
@Autowired
private RedisService redisService;
private final static String INFO_USER_KEY = "info:user:";
private final static String INFO_PRIZE_KEY = "info:prize:";
private final static String INFO_LOTTERY_KEY = "info:lottery:";
private final static String USER_COUNT_KEY = "userCount:";
@Override
public Lottery init() {
User zhangsan = new User(100L, "张三");
User lisi = new User(200L, "李四");
String zhangsanInfoKey = INFO_USER_KEY + zhangsan.getId();
String zhangsanJson = JSON.toJSONString(zhangsan);
redisService.addInitToCache(zhangsanInfoKey, zhangsanJson);
String lisiInfoKey = INFO_USER_KEY + lisi.getId();
String lisiJson = JSON.toJSONString(lisi);
redisService.addInitToCache(lisiInfoKey, lisiJson);
Prize iPhone15 = new Prize(1000L, "iPhone15", 10, 0.5d);
Prize rolex = new Prize(2000L, "劳力士-手表", 10, 0.1d);
Map<String, Object> iPhone15Map = entityToMap(iPhone15);
Map<String, Object> rolexMap = entityToMap(rolex);
String iPhone15InfoKey = INFO_PRIZE_KEY + iPhone15.getId();
String rolexInfoKey = INFO_PRIZE_KEY + rolex.getId();
redisService.addPrizeMapToCache(iPhone15InfoKey, iPhone15Map);
redisService.addPrizeMapToCache(rolexInfoKey, rolexMap);
Lottery lottery = new Lottery();
lottery.setId(10086L);
lottery.setCount(10);
lottery.setPrizeIdList(Arrays.asList(1000L, 2000L));
String lotteryInfoKey = INFO_LOTTERY_KEY + lottery.getId();
String lotteryJson = JSON.toJSONString(lottery);
redisService.addInitToCache(lotteryInfoKey, lotteryJson);
return lottery;
}
public Map<String, Object> entityToMap(Object obj) {
if (obj == null) {
return null;
}
Map<String, Object> map = new HashMap<>();
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
Object o = field.get(obj);
String name = field.getName();
map.put(name, o);
} catch (Exception e) {
e.printStackTrace();
}
}
return map;
}
4、开始抽奖
1、controller层
@GetMapping("start/{userId}/{lotteryId}")
public LotteryResult start(@PathVariable("userId") Long userId, @PathVariable("lotteryId") Long lotteryId) {
return lotteryService.start(userId, lotteryId);
}
2、service接口层
LotteryResult start(Long userId, Long lotteryId);
3、service接口实现类
@Override
public LotteryResult start(Long userId, Long lotteryId) {
String userInfoKey = INFO_USER_KEY + userId;
Object userObj = redisService.getInitInfoFromCache(userInfoKey);
if (userObj == null) {
throw new RuntimeException("用户不存在");
}
String lotteryInfoKey = INFO_LOTTERY_KEY + lotteryId;
Object lotteryObj = redisService.getInitInfoFromCache(lotteryInfoKey);
if (lotteryObj == null) {
throw new RuntimeException("抽奖活动不存在");
}
User user = JSON.parseObject(userObj.toString(), User.class);
Lottery lottery = JSON.parseObject(lotteryObj.toString(), Lottery.class);
Integer count = lottery.getCount();
String userCountKey = USER_COUNT_KEY + userId;
Integer userCount = redisService.getUserCountFromCache(userCountKey);
if (userCount == null) {
userCount = count;
}
if (userCount == 0) {
throw new RuntimeException("已没抽奖次数");
}
List<Long> prizeIdList = lottery.getPrizeIdList();
Long prizeId = draw(prizeIdList);
redisService.addUserCountToCache(userCountKey, userCount -1);
LotteryResult lotteryResult = new LotteryResult();
lotteryResult.setUserId(userId);
if (prizeId == null) {
lotteryResult.setIsWin(false);
System.out.println("您没中奖");
return lotteryResult;
}else {
Prize prize = redisService.getPrizeInfoToCache(INFO_PRIZE_KEY + prizeId);
lotteryResult.setIsWin(true);
lotteryResult.setPrize(prize);
redisService.editPrizeNumberToCache(INFO_PRIZE_KEY + prizeId, "number", prize.getNumber() - 1);
System.out.println("您中奖了,奖品是:" + prize.getName());
}
return lotteryResult;
}
private Long draw(List<Long> prizeIdList) {
double index = 0.0d;
List<Double> probabilityPool = new ArrayList<>();
List<Prize> prizeList = new ArrayList<>();
for (int i = 0; i < prizeIdList.size(); i++) {
Long prizeId = prizeIdList.get(i);
Prize prize = redisService.getPrizeInfoToCache(INFO_PRIZE_KEY + prizeId);
if (prize == null) {
continue;
}
if (prize.getNumber() <= 0) {
continue;
}
prizeList.add(prize);
probabilityPool.add(index + prize.getWinRate());
index += prize.getWinRate();
}
Random random = new Random();
double d = random.nextDouble();
for (int i = 0; i < prizeList.size(); i++) {
if (i == 0) {
if (probabilityPool.get(i) > d) {
return prizeList.get(i).getId();
}
}else {
if (probabilityPool.get(i - 1) < d && d <= probabilityPool.get(i)) {
return prizeList.get(i).getId();
}
}
}
return null;
}
5、redis
1、redis接口层
public interface RedisService {
void addInitToCache(String key, String value);
void addPrizeMapToCache(String key, Map<String, Object> map);
Object getInitInfoFromCache(String key);
Integer getUserCountFromCache(String key);
Prize getPrizeInfoToCache(String key);
void addUserCountToCache(String key, Integer count);
void editPrizeNumberToCache(String key, String field, Integer number);
}
2、redis接口实现类
@Component
public class RedisServiceImpl implements RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public void addInitToCache(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
@Override
public void addPrizeMapToCache(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
}
@Override
public Object getInitInfoFromCache(String key) {
return redisTemplate.opsForValue().get(key);
}
@Override
public Integer getUserCountFromCache(String key) {
Object o = redisTemplate.opsForValue().get(key);
if (o != null) {
return Integer.valueOf(o.toString());
}
return null;
}
@Override
public Prize getPrizeInfoToCache(String key) {
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
Map<String, Object> map = hashOperations.entries(key);
if (map != null) {
Prize prize = JSON.parseObject(JSON.toJSONString(map), Prize.class);
return prize;
}
return null;
}
@Override
public void addUserCountToCache(String key, Integer count) {
redisTemplate.opsForValue().set(key, count);
}
@Override
public void editPrizeNumberToCache(String key, String field, Integer number) {
redisTemplate.opsForHash().put(key, field, number);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本