Commit 40d50d1d authored by libin's avatar libin

Merge branch 'luck_draw_feature' into dev

parents 88a2e828 17c72286
......@@ -15,6 +15,8 @@ public class RabbitConstant {
public static final String ORDER_TOPIC = ORDER+ TOPIC_EXC;
public static final String INTEGRAL = "integral";
public static final String INTEGRAL_TOPIC = INTEGRAL + TOPIC_EXC;
public static final String ACTIVITY_PRIZE="activity:prize";
public static final String ACTIVITY_PRIZE_TOPIC=ACTIVITY_PRIZE+TOPIC_EXC;
/**************************key*********************************/
//用户
......@@ -35,11 +37,15 @@ public class RabbitConstant {
public static final String KEY_WALLET_WITH_DRAW="wallet.withdraw";
//抽奖
public static final String KEY_ACTIVITY_PRIZE_RECORD="prize:record";
static {
exchangeTopicSet = new HashSet<String>() {{
add(ADMIN_TOPIC);
add(ORDER_TOPIC);
add(INTEGRAL_TOPIC);
add(ACTIVITY_PRIZE_TOPIC);
}};
}
}
package com.xxfc.platform.activity.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/12/13 15:11
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ActivityLotteryDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Integer userId;
private String phone;
private Integer serialNumber;
private Integer activityId;
private Integer prizeType;
private String prizeName;
private String iconPath;
private Integer hasWinning;
private String expiryDateCode;
private Date lotteryTime;
private Integer goodsId;
private Integer prizeGoodsType;
}
......@@ -3,10 +3,7 @@ package com.xxfc.platform.activity.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
......
......@@ -10,7 +10,6 @@ import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import tk.mybatis.spring.annotation.MapperScan;
......@@ -28,7 +27,6 @@ import tk.mybatis.spring.annotation.MapperScan;
"com.github.wxiaoqi.security.common.support"
})
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableAsync
@EnableDiscoveryClient
@EnableScheduling
@EnableAceAuthClient
......
......@@ -202,7 +202,6 @@ public class ActivityAttendanceRecordBiz extends BaseBiz<ActivityAttendanceRecor
timeStr};
}
@Async
public void updateLotteryNumByActivityIdAndUserIdAndPrizeType(Integer activityId,Integer userId,Integer prizeType){
mapper.updateLotteryNumByActivityIdAndUserIdAndPrizeType(activityId,userId,prizeType);
}
......
......@@ -4,15 +4,15 @@ import com.ace.cache.annotation.Cache;
import com.ace.cache.annotation.CacheClear;
import com.github.wxiaoqi.security.admin.feign.dto.AppUserDTO;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.config.rabbit.RabbitConstant;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.util.ReferralCodeUtil;
import com.xxfc.platform.activity.config.RedissonLock;
import com.xxfc.platform.activity.constant.PrizeGoodsTypeEnum;
import com.xxfc.platform.activity.constant.PrizeTypeEnum;
import com.xxfc.platform.activity.dto.ActivityLotteryDTO;
import com.xxfc.platform.activity.dto.CouponDTO;
import com.xxfc.platform.activity.dto.UserCouponSendDTO;
import com.xxfc.platform.activity.entity.ActivityPrize;
import com.xxfc.platform.activity.entity.ActivityWinningRecord;
import com.xxfc.platform.activity.mapper.ActivityPrizeMapper;
import com.xxfc.platform.activity.util.LotteryUtils;
import com.xxfc.platform.activity.vo.ActivityPrizeVo;
......@@ -21,12 +21,12 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
......@@ -49,10 +49,9 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize> {
private final ActivityWinningRecordBiz activityWinningRecordBiz;
private final ActivityAttendanceRecordBiz activityAttendanceRecordBiz;
private final UserCouponBiz userCouponBiz;
private final CouponBiz couponBiz;
private final RabbitTemplate rabbitTemplate;
private final RedisTemplate<String, Object> redisTemplate;
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> valueOperations;
......@@ -157,6 +156,9 @@ public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize
*/
public LotteryVo activityLottery(Integer activityId, Integer prizeType, String lotteryDate, AppUserDTO appUserDTO) {
LotteryVo lotteryVo = new LotteryVo();
ActivityLotteryDTO activityLotteryDTO = new ActivityLotteryDTO();
activityLotteryDTO.setHasWinning(0);
//查询奖品信息
List<ActivityPrize> activityPrizes = ((ActivityPrizeBiz) AopContext.currentProxy()).findActivityPrizeByType(prizeType);
ActivityPrize notActivityPrize = activityPrizes.stream().filter(x -> x.getPrizeGoodsType() == 0).findFirst().orElseGet(() -> {
ActivityPrize activityPrize = new ActivityPrize();
......@@ -166,6 +168,8 @@ public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize
activityPrize.setSerialNumber(8);
return activityPrize;
});
//用户对应活动类型抽奖次数
String lotteryNumKey = String.format("%s%d:%d:%d",USER_LOTTERY_PRE_KEY, appUserDTO.getUserid(), activityId, prizeType);
Object lotteryNum = valueOperations.get(lotteryNumKey);
boolean hasLotteryNum = lotteryNum == null ? activityAttendanceRecordBiz.hasNumberOfLuckyDrawByType(activityId, prizeType, appUserDTO.getUserid()) : ((Integer) lotteryNum) > 0;
......@@ -197,16 +201,13 @@ public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize
}
}
ActivityWinningRecord activityWinningRecord = new ActivityWinningRecord();
activityWinningRecord.setActivityId(activityId);
activityWinningRecord.setPrizeType(prizeType);
activityWinningRecord.setUserId(appUserDTO.getUserid());
activityWinningRecord.setHasWinning(0);
//判断是否有库存
boolean hasStock = activityPrize.getPrizeGoodsType() != PrizeGoodsTypeEnum.NO_PRIZE.getCode()
&& activityPrize.getTotalStock() != null
&& activityPrize.getTotalStock()!=0
&& prizeStock != null
&& (Integer) prizeStock != 0;
if (hasStock) {
String lockKey = String.format("%s%d:%d:%d", LOTTERY_PRE_KEY, activityId, prizeType, activityPrize.getSerialNumber());
RLock rLock = redissonLock.getRLock(lockKey);
......@@ -217,14 +218,12 @@ public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize
log.info("tryLock success, key = [{}]", lockKey);
try {
if (prizeStock != null && (Integer) prizeStock > 0) {
//更新库存
((ActivityPrizeBiz) AopContext.currentProxy()).updatePrizeStock(prizeType, activityPrize.getSerialNumber());
//更新缓存库存
//更新奖品的缓存库存
valueOperations.decrement(prizeStockKey);
//设置为已中奖
activityWinningRecord.setHasWinning(1);
activityWinningRecord.setIconPath(activityPrize.getIconPath());
activityWinningRecord.setLotteryTime(new Date());
activityLotteryDTO.setHasWinning(1);
activityLotteryDTO.setIconPath(activityPrize.getIconPath());
activityLotteryDTO.setLotteryTime(new Date());
} else {
activityPrize = notActivityPrize;
}
......@@ -240,35 +239,35 @@ public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize
log.info("tryLock fail, key = [{}]", lockKey);
}
} catch (InterruptedException e) {
e.printStackTrace();
log.error("tryLock fail, key = [{}]", lockKey);
}
if (PrizeTypeEnum.LOCALE.getCode() == prizeType) {
//兑奖码生成
String expireDateCodeKey = String.format("%s:%s%d",lotteryDate.substring(0,4),LOTTERY_PRE_KEY, activityId);
//兑奖次数自增
Long expireDateCodeCounter = valueOperations.increment(expireDateCodeKey);
if (expireDateCodeCounter == 1) {
redisTemplate.expire(expireDateCodeKey, expirDays, TimeUnit.DAYS);
}
String expiryDateCode = ReferralCodeUtil.encode(expireDateCodeCounter.intValue());
activityWinningRecord.setExpiryDateCode(expiryDateCode);
activityLotteryDTO.setExpiryDateCode(expiryDateCode);
lotteryVo.setExpiryDateCode(expiryDateCode);
}
//发放优惠券
if (activityPrize.getPrizeGoodsType() == PrizeGoodsTypeEnum.COUPON.getCode()) {
UserCouponSendDTO userCouponSendDTO = new UserCouponSendDTO();
userCouponSendDTO.setCouponId(activityPrize.getGoodsId());
userCouponSendDTO.setCouponNum(1);
userCouponSendDTO.setPhone(appUserDTO.getUsername());
userCouponBiz.sendCoupon(userCouponSendDTO);
activityWinningRecord.setGoodsId(activityPrize.getGoodsId());
}
}
activityWinningRecord.setPrizeName(activityPrize.getName());
activityWinningRecordBiz.saveRecord(activityWinningRecord);
activityLotteryDTO.setActivityId(activityId);
activityLotteryDTO.setPrizeType(prizeType);
activityLotteryDTO.setUserId(appUserDTO.getUserid());
activityLotteryDTO.setPhone(appUserDTO.getUsername());
activityLotteryDTO.setPrizeName(activityPrize.getName());
Optional.ofNullable(activityPrize.getGoodsId()).ifPresent(goodsId->activityLotteryDTO.setGoodsId(goodsId));
activityLotteryDTO.setSerialNumber(activityPrize.getSerialNumber());
activityLotteryDTO.setPrizeGoodsType(activityPrize.getPrizeGoodsType());
lotteryVo.setSerialNumber(activityPrize.getSerialNumber());
//更改对应抽奖类型的抽奖次数
activityAttendanceRecordBiz.updateLotteryNumByActivityIdAndUserIdAndPrizeType(activityId, appUserDTO.getUserid(), prizeType);
//减少用户抽奖次数
valueOperations.decrement(lotteryNumKey);
//发送抽奖结果消息
rabbitTemplate.convertAndSend(RabbitConstant.ACTIVITY_PRIZE_TOPIC,RabbitConstant.KEY_ACTIVITY_PRIZE_RECORD,activityLotteryDTO);
} else {
lotteryVo.setMessage("抽奖次数已用完!!!");
}
......@@ -281,7 +280,6 @@ public class ActivityPrizeBiz extends BaseBiz<ActivityPrizeMapper, ActivityPrize
* @param prizeType
* @param serialNumber
*/
@Async
public void updatePrizeStock(Integer prizeType, Integer serialNumber) {
mapper.updatePrizeStock(prizeType, serialNumber);
}
......
......@@ -25,6 +25,7 @@ public class RabbitActivityConfig extends RabbitCommonConfig {
//优惠券
public static final String COUPON_CANCEL_QUEUE = "coupon.cancel.queue";
public static final String PRIZE_RECORD_QUEUE="prize:record:queue";
static {
myQueue = new ArrayList<BindDTO>(){{
......@@ -35,6 +36,7 @@ public class RabbitActivityConfig extends RabbitCommonConfig {
add(new BindDTO(ACTIVITY_NEW_QUEUE, ADMIN_TOPIC, KEY_APPUSER_AUTH));
add(new BindDTO(INTEGRAL_HANDLE_QUEUE, INTEGRAL_TOPIC, INTEGRAL_ROUTING_KEY));
add(new BindDTO(COUPON_CANCEL_QUEUE, ORDER_TOPIC, KEY_ORDER_CANCEL));
add(new BindDTO(PRIZE_RECORD_QUEUE,ACTIVITY_PRIZE_TOPIC,KEY_ACTIVITY_PRIZE_RECORD));
}};
}
......
package com.xxfc.platform.activity.handler;
import com.rabbitmq.client.Channel;
import com.xxfc.platform.activity.biz.ActivityAttendanceRecordBiz;
import com.xxfc.platform.activity.biz.ActivityPrizeBiz;
import com.xxfc.platform.activity.biz.ActivityWinningRecordBiz;
import com.xxfc.platform.activity.biz.UserCouponBiz;
import com.xxfc.platform.activity.config.RabbitActivityConfig;
import com.xxfc.platform.activity.constant.PrizeGoodsTypeEnum;
import com.xxfc.platform.activity.dto.ActivityLotteryDTO;
import com.xxfc.platform.activity.dto.UserCouponSendDTO;
import com.xxfc.platform.activity.entity.ActivityWinningRecord;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/12/13 11:22
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class ActivityPrizeMqHandler {
private final ActivityPrizeBiz activityPrizeBiz;
private final ActivityAttendanceRecordBiz activityAttendanceRecordBiz;
private final ActivityWinningRecordBiz activityWinningRecordBiz;
private final UserCouponBiz userCouponBiz;
private final RedisTemplate<String, Object> redisTemplate;
@Resource(name = "redisTemplate")
private ValueOperations valueOperations;
private final String R_CONSUME="lottery:reconsume";
private final int R_CONSUME_MAX_NUM=3;
@RabbitListener(queues = RabbitActivityConfig.PRIZE_RECORD_QUEUE)
public void processActivityPrizeMsg(ActivityLotteryDTO activityLotteryDTO, Channel channel){
log.info("抽奖消息的数据【{}】",activityLotteryDTO);
try {
if (activityLotteryDTO.getHasWinning() == 1) {
//更新库存
log.info("更新库存:参数【prizeType:{}==serialNumber:{}】",activityLotteryDTO.getPrizeType(), activityLotteryDTO.getSerialNumber());
activityPrizeBiz.updatePrizeStock(activityLotteryDTO.getPrizeType(), activityLotteryDTO.getSerialNumber());
//发放优惠券
if (activityLotteryDTO.getPrizeGoodsType() == PrizeGoodsTypeEnum.COUPON.getCode()) {
UserCouponSendDTO userCouponSendDTO = new UserCouponSendDTO();
userCouponSendDTO.setCouponId(activityLotteryDTO.getGoodsId());
userCouponSendDTO.setCouponNum(1);
userCouponSendDTO.setPhone(activityLotteryDTO.getPhone());
log.info("抽中优惠券发送:【参数:{}】",userCouponSendDTO);
userCouponBiz.sendCoupon(userCouponSendDTO);
}
}
ActivityWinningRecord activityWinningRecord = new ActivityWinningRecord();
BeanUtils.copyProperties(activityLotteryDTO, activityWinningRecord);
activityWinningRecord.setCrtTime(new Date());
log.info("抽奖记录【{}】",activityWinningRecord);
activityWinningRecordBiz.saveRecord(activityWinningRecord);
//更改对应抽奖类型的抽奖次数
log.info("更改对应抽奖类型的抽奖次数【activityId:{}==userId:{}==prizeType:{}】",activityLotteryDTO.getActivityId(), activityLotteryDTO.getUserId(), activityLotteryDTO.getPrizeType());
activityAttendanceRecordBiz.updateLotteryNumByActivityIdAndUserIdAndPrizeType(activityLotteryDTO.getActivityId(), activityLotteryDTO.getUserId(), activityLotteryDTO.getPrizeType());
}catch (Exception ex){
log.error("抽奖消息消费失败【{}】",ex);
try {
Long reConsumeCounter = valueOperations.increment(R_CONSUME);
if(reConsumeCounter <= R_CONSUME_MAX_NUM ) {
channel.basicRecover(false);
log.info("抽奖消息重回队列成功");
}
if (reConsumeCounter==1){
redisTemplate.expire(R_CONSUME,1, TimeUnit.DAYS);
}
} catch (IOException e) {
log.error("消费抽奖消息重回队列失败【{}】",e);
}
}
}
}
......@@ -84,6 +84,10 @@ public class Banner {
@ApiModelProperty(value = "ios跳转地址")
private String iosUrl;
@Column(name = "applet_url")
@ApiModelProperty("小程序跳转地址")
private String appletUrl;
/**
* 是否删除,0否,1是
*/
......
......@@ -26,6 +26,8 @@ public class BannerVo {
private String iosUrl;
private String appletUrl;
/**
* seo html标签优化
*/
......
......@@ -6,6 +6,7 @@ import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.app.entity.Banner;
import com.xxfc.platform.app.entity.vo.BannerVo;
import com.xxfc.platform.app.mapper.BannerMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.time.Instant;
......@@ -26,12 +27,7 @@ public class BannerBiz extends BaseBiz<BannerMapper,Banner> {
List<Banner> banners = mapper.findBannerListByType(type,location,platform);
banners.forEach(banner -> {
BannerVo bannerVo = new BannerVo();
bannerVo.setCover(banner.getCover());
bannerVo.setUrl(banner.getUrl());
bannerVo.setTitle(banner.getTitle());
bannerVo.setId(banner.getId());
bannerVo.setAlt(banner.getAlt());
bannerVo.setIosUrl(banner.getIosUrl());
BeanUtils.copyProperties(banner,bannerVo);
bannerVos.add(bannerVo);
});
return bannerVos;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment