抽奖活动 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()); }}