zoukankan      html  css  js  c++  java
  • 抽奖活动 mark


    import lombok.extern.slf4j.Slf4j;
    import org.redisson.api.RBucket;
    import org.redisson.api.RLock;
    import org.redisson.api.RMapCache;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    import java.math.BigDecimal;
    import java.util.*;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.stream.Collectors;


    /**
    * LotteryActivityRedisService 描述
    * 抽奖活动
    * @author tomas
    * @create 2018/10/24
    **/
    @Slf4j
    @Service("lotteryActivityRedisServiceImpl")
    public class LotteryActivityRedisServiceImpl extends ActivityRedisService implements LotteryActivityRedisService {


    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ActivityInfoMapper mapper;

    /**
    * 初始化 活动信息
    * @param activityCode
    * @return
    */
    @Override
    public ResultModel init(String activityCode){
    try {
    ActivityModel activityInfo = mapper.selectByCode(activityCode);
    if(null!=activityInfo ){
    RBucket<ActivityModel> activityBucket = redissonClient.getBucket(String.format(ACTIVITY_KEY,activityCode));
    activityBucket.set(activityInfo);
    if(new Date().after(activityInfo.getBeginTime())){
    return ResultModel.getError("非可初始化活动时间");
    }
    //1.初始化奖品
    String awardPoolMapKey = String.format(ACTIVITY_PRIZE_POOL_MAP_KEY,activityCode);
    Prize p1=Prize.builder().id(6).prizeName("30天免单券").prizeType("一等奖").prizeTotalNum(6).remainingPrize(6).prizeRate(0.002).build();
    Prize p2=Prize.builder().id(7).prizeName("7天免单券").prizeType("二等奖").prizeTotalNum(30).remainingPrize(30).prizeRate(0.01).build();
    Prize p3=Prize.builder().id(8).prizeName("7折优惠券").prizeType("三等奖").prizeTotalNum(0).remainingPrize(0).prizeRate(0.9988).def(true).build();
    //Prize p4=Prize.builder().id(0L).prizeName("谢谢参与").prizeType("一等奖").prizeTotalNum(100000000L).remainingPrize(100000000L).prizeRate(0.001).build();
    List<Prize> list=new ArrayList<>();
    list.add(p1);
    list.add(p2);
    list.add(p3);
    RMapCache<Integer, Prize> mapCache = redissonClient.getMapCache(awardPoolMapKey);
    for (int i = 0; i < list.size(); i++) {
    //将奖项数据初始化到redis中
    Prize p=list.get(i);
    mapCache.put(p.getId(),p,10, TimeUnit.DAYS);
    }
    //todo 多线程操作/异步操作
    System.out.println("数据加载完成");
    }
    return ResultModel.getSuccess("初始化活动成功");

    }catch (Exception e){
    log.error("init activity Error activityCode ={} msg={} ",activityCode,e.getMessage());
    }
    return ResultModel.getError("初始化活动失败");
    }

    /**
    * 根据 code 和 userId 检查用户参与活动情况
    * @param model
    * @return
    */
    public ResultModel check(ActivityParamModel model){

    return ResultModel.getSuccess();
    }

    /**
    * 参与抽奖
    * @param model
    * @return
    */
    public ResultModel lottery(ActivityParamModel model){

    /* 获取活动奖品列表 */
    List<Prize> selectPrizeList = new ArrayList<>();

    //获取可抽取的奖品及其的概率集合
    Map<String, Object> optionalAwardMap = this.getAllAwardProbability(model.getCode());
    //获取可选的奖品集合
    selectPrizeList = (List<Prize>) optionalAwardMap.get("selectPrizeList");
    //获取可选奖品集合的总概率
    double probabilityTotal = (double) optionalAwardMap.get("probabilityTotal");
    if (probabilityTotal < 1) {
    //当中奖概率不等于100%时,补充默认奖品
    selectPrizeList = this.supplementDefaultAward( selectPrizeList, probabilityTotal, model.getCode());
    }
    //生成抽奖用的概率集合
    List<Double> probabilityResult = this.generatorAwardProbability(selectPrizeList);
    if(probabilityResult.size()<=0){
    return ResultModel.getError("没有可抽奖奖品");
    }
    /* 实例化抽奖算法,并抽奖 */
    AliasMethod aliasMethod = new AliasMethod(probabilityResult);
    /* 开始抽奖 */
    int index = aliasMethod.next();
    // 返回抽中奖品
    Prize selectPrize = selectPrizeList.get(index);
    if (selectPrize != null) {
    //判断是否是默认的奖品,不是默认奖品 需要 redis 减Remaining 数量
    if (!selectPrize.isDef()) {
    String awardPoolMapKey = String.format(ACTIVITY_PRIZE_POOL_MAP_KEY,model.getCode());
    //默认返回数量为0
    if (selectPrize.getRemainingPrize()!= null && selectPrize.getRemainingPrize() >= 1 ) {
    RLock lock = redissonClient.getLock(awardPoolMapKey.concat(String.valueOf(selectPrize.getId())));
    lock.lock(200, TimeUnit.MILLISECONDS);
    selectPrize.setRemainingPrize(new AtomicInteger(selectPrize.getRemainingPrize()).decrementAndGet());
    redissonClient.getMapCache(awardPoolMapKey).put(selectPrize.getId(),selectPrize);
    lock.unlock();
    }else {
    return lottery(model);
    }
    }
    //判断是否 是安慰奖
    if(!selectPrize.isComfort()){

    }


    }
    return ResultModel.getSuccess(selectPrize);
    }


    /**
    * 分享功能
    * @param model
    * @return
    */
    public ResultModel share(ActivityParamModel model){

    return ResultModel.getSuccess();
    }


    /**
    * 结束 活动开关
    * @param activityCode
    * @return
    */
    public ResultModel stop(String activityCode){

    return ResultModel.getSuccess();
    }


    /**
    * @param selectAwardList 奖品选项
    * @return
    * @Describe 生成奖品概率
    */
    private List<Double> generatorAwardProbability(List<Prize> selectAwardList) {
    List<Double> prob = new ArrayList<>();
    try {
    /* 遍历所有奖品,取得奖品概率生成随机算法计算规则 */
    for (Prize prize : selectAwardList) {
    double rate =prize.getPrizeRate().doubleValue();
    prob.add(rate);
    }
    return prob;
    } catch (Exception e) {
    log.error(e.getMessage());
    return new ArrayList<>();
    }

    }


    /**
    * @param selectAwardList
    * @param probabilityTotal
    * @return
    * @Describe 补充默认的奖品
    */
    private List<Prize> supplementDefaultAward(List<Prize> selectAwardList, double probabilityTotal,String activityCode) {
    for (Prize prize : selectAwardList) {
    if(prize.isDef()){
    String awardPoolMapKey = String.format(ACTIVITY_PRIZE_POOL_MAP_KEY,activityCode);
    BigDecimal bigDecimal = new BigDecimal(1 - probabilityTotal);
    prize.setPrizeRate(prize.getPrizeRate()+bigDecimal.doubleValue());
    RLock lock = redissonClient.getLock(awardPoolMapKey.concat(String.valueOf(prize.getId())).concat("supply"));
    lock.lock(200, TimeUnit.MILLISECONDS);
    redissonClient.getMapCache(awardPoolMapKey).put(prize.getId(),prize);
    lock.unlock();
    }
    }
    return selectAwardList;
    }


    /**
    * @param activityCode 活动id
    * @return
    * @Describe 获取所有的奖品概率
    */
    private Map<String, Object> getAllAwardProbability(String activityCode) {
    //返回的结果集
    Map<String, Object> result = new HashMap<String, Object>();
    /* 中奖率累计 */
    double probabilityTotal = 0.0;
    /* 获取活动对应的奖品列表 */
    List<Prize> prizeList = this.getPrizeList(activityCode);
    List<Prize> selectPrizeList = new ArrayList<>();
    /* 奖品结果集 */
    for (Prize prize : prizeList) {
    //查询奖品剩余的数量
    //只有数量大于零 的奖品才能放到 selectPrizeList 中
    if (null!=prize && prize.getRemainingPrize() > 0) {
    // 取出当前概率
    double probability = prize.getPrizeRate();
    probabilityTotal += probability;
    selectPrizeList.add(prize);
    } else {
    continue;
    }
    }
    result.put("probabilityTotal", probabilityTotal);
    result.put("selectPrizeList", selectPrizeList);
    return result;
    }

    /**
    * @Describe 获取活动对应的奖品列表
    * @param activityCode
    * @return List<Prize>
    */
    private List<Prize> getPrizeList(String activityCode) {
    String awardPoolMapKey = String.format(ACTIVITY_PRIZE_POOL_MAP_KEY,activityCode);
    RMapCache<Integer, Prize> awardPoolMap = redissonClient.getMapCache(awardPoolMapKey);
    return awardPoolMap.readAllValues().stream().collect(Collectors.toList());
    }
    }
  • 相关阅读:
    pop指令的执行过程
    ipad 4.2 开发环境
    XP远程桌面
    停机问题、哥德尔定理
    看MIT的线性代数
    VizA项目继续推进
    port systemc to mac os x
    关于jar
    普桑
    拉突爾
  • 原文地址:https://www.cnblogs.com/xmanblue/p/9849584.html
Copyright © 2011-2022 走看看