抽奖功能实现
1. 需求分析
抽奖可以获得积分,礼券,小样,正品等
若库存为0,则用户不能在抽中此奖
每个奖项的中奖概率
每天抽奖次数的限制
每次抽奖是否需要消耗积分的限制
有没有批量抽奖功能
2.表结构设计
会员表,积分表,是以前就有的,本次新增抽奖功能,需要新增一下的表:
首先要有库存表,暂且定义为BPRIZE表
其次要记录用户抽中的奖项,暂且定义为HPRIZE表
3. 后台代码实现
Controller
@RestController @RequestMapping(value = "draw") public class DrawController extends BaseController { @Autowired DrawService drawService; @Autowired CouponService couponService; @Autowired SocialProviderService socialProviderService; @ApiOperation(value = "抽奖历史记录", notes = "抽奖历史记录") @GetMapping(value = "history", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) private ResponseBean prizeHistory(@RequestParam("userId") String userId, @RequestParam("social") String social, @RequestParam("page") int page, @RequestParam("size") int size) { ResponseBean responseBean = new ResponseBean(); List<HPrizerecord> hPrizerecords = drawService.getPrizeHistory(userId, social, page, size); responseBean.setData(hPrizerecords); return responseBean; } @ApiOperation(value = "抽奖榜单", notes = "抽奖榜单") @GetMapping(value = "billboard", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) private ResponseBean billboard(@RequestParam("topN") int topN, @RequestParam("levelList") String levelList, @RequestParam("social") String social) { ResponseBean responseBean = new ResponseBean(); // 查找SopId SSocialProvider socialProvider = socialProviderService.findSocialProvider(social); // 格式化等级 (str-> list(int)) List<Integer> level = Arrays.stream(levelList.split(",")).map(a -> { return Integer.parseInt(a); }).collect(Collectors.toList()); // 查询 JSONArray billboard = drawService.getBillboard(topN, level, socialProvider.getSopId()); responseBean.setData(billboard); return responseBean; } @ApiOperation(value = "抽奖", notes = "抽奖") @PostMapping(produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) private ResponseBean<BPrize> draw(@RequestParam("userId") String userId, @RequestParam("social") String social) throws Exception { ResponseBean responseBean = new ResponseBean(); BPrize bPrize = drawService.draw(userId, social, super.getSid()); responseBean.setData(bPrize); return responseBean; } }
具体实现
@Service public class DrawServiceImpl implements DrawService { @Autowired HPrizerecordMapper hPrizerecordMapper; @Autowired SaveDrawRecord saveDrawRecord; @Autowired SocialService socialService; @Autowired SocialProviderService socialProviderService; @Autowired BCustomerService bCustomerService; @Autowired BPrizeService bPrizeService; @Autowired PEService peService; @Autowired CustomerService customerService; @Autowired SendMemberInfoToEcrmMqTask sendMemberInfoToEcrmMqTask; @Value("${sys.name}") private String sysName; int freeCount=2; int dalyMaxDrawCount=5; @Value("${cc.draw.pe.code}") String luckyDrawPeEventCode; @Value("${cc.draw.max.probability}") int maxProbability; static Random rand = new Random(); @Value("#{'${cc.draw.actual.prizeLevel}'.split(',')}") private List<Integer> actualPrizeLevel; @Override public List<HPrizerecord> getPrizeHistory(String userId, String social, int page, int size) { int cstId = socialService.findCstIdBySocialAndSocialId(userId, social); if (size == 0 ){ size = 10; } if (page<=0){ page = 1; } return hPrizerecordMapper.getPrizeHistory(cstId, page, size); } @Override public BPrize draw(String userId, String social, String sid) throws Exception { int cstId = socialService.findCstIdBySocialAndSocialId(userId, social); // 今天一共抽了几次奖 int todayCount = getDrawCountToday(cstId); // 如果超过最大次数,直接返回, 不进行抽奖 if (todayCount >= dalyMaxDrawCount){ throw new DrawCountLimitException(); } // 超过规定的一个次数就要开始扣积分 if (todayCount >= freeCount) { // 扣减积分, 如果扣减失败, 会抛出异常,这边不用管 peService.sendEvent(cstId, sysName, luckyDrawPeEventCode); sendMemberInfoToEcrmMqTask.syncMemberInfoToECRM(cstId, luckyDrawPeEventCode); } boolean drawEnd = false; BPrize bPrize = null; while (!drawEnd) { int x = rand.nextInt(maxProbability); bPrize = bPrizeService.getPrize(x); // 如果抽中的是实物奖品 if (bPrize!=null && actualPrizeLevel.indexOf(bPrize.getPrizeLevel())>=0){ // 判断当日是否有中过实物奖品 boolean isWinningTheActualPrizeFlag = isWinningTheActualPrize(cstId); // 如果isWinningTheActualPrizeFlag 为false , 抽奖成功 if (!isWinningTheActualPrizeFlag) { drawEnd = true; } } if (bPrize != null) { drawEnd = true; } } // 如果礼品里面配置了PEcode 调用PE积分调整 String peCode = bPrize.getPointCode(); if (StringUtils.isNotBlank(peCode)) { peService.sendEvent(cstId, sysName, peCode); sendMemberInfoToEcrmMqTask.syncMemberInfoToECRM(cstId, luckyDrawPeEventCode); } // 记录到抽奖历史 saveDrawRecord.savePrizerecordHistory(cstId, bPrize, sid); return bPrize; } private boolean isWinningTheActualPrize(int cstId) { // 查询今天是否中过实物奖项 List<HPrizerecord> hPrizerecords = hPrizerecordMapper.getWinningTheActualPrizeToday(cstId,actualPrizeLevel); if (null != hPrizerecords ||!hPrizerecords.isEmpty() || hPrizerecords.size()>0) { return true; } return false; } @Override public JSONArray getBillboard(int topN, List<Integer> levelList, Integer sopId) { List<Map> records = hPrizerecordMapper.selectBillboard(topN, levelList, sopId); return (JSONArray) JSONArray.toJSON(records); } private int getDrawCountToday(int cstId) { return hPrizerecordMapper.getDrawCountToday(cstId); } }
4. 前端UI实现
------------------------- A little Progress a day makes you a big success... ----------------------------