Authored by caoyan

Merge branch 'wechart_free' of http://git.yoho.cn/yoho30/yohobuy-activity into wechart_free

# Conflicts:
#	controller/src/main/java/com/yoho/activity/controller/LotteryController.java
#	dal/src/main/resources/META-INF/mybatis/LotteryRecordMapper.xml
#	service/src/main/java/com/yoho/activity/service/ILotteryService.java
#	service/src/main/java/com/yoho/activity/service/impl/LotteryServiceImpl.java
... ... @@ -89,8 +89,7 @@ public class CacheAop {
expire = DEFAULT_CACHE_SECONDS;
}
yhValueOperations.set(key, CacheKeyHelper.value2String(value));
long timeout = 5;
yhRedisTemplate.longExpire(key, timeout, TimeUnit.SECONDS);
yhRedisTemplate.longExpire(key, expire, TimeUnit.SECONDS);
}
private Object getFromCache(String key, Class<?> valueType) {
... ... @@ -102,25 +101,25 @@ public class CacheAop {
}
private String getCacheKey(Method method, Object[] args) {
Cacheable cachable = method.getAnnotation(Cacheable.class);
String keyPre = cachable.keyPre();
if (StringUtils.isBlank(keyPre)) {
keyPre = DEFAULT_KEY_PRE + method.getName();
keyPre = DEFAULT_KEY_PRE + method.getDeclaringClass().getSimpleName() + ":" + method.getName() + ":";
}
int[] excludeParams = cachable.excludeParams();
String cacheValueKey = getValueStrings(args, excludeParams);
String cacheKey = keyPre + cacheValueKey;
// 最大250,超过限制需要MD5
// 最大250,超过限制需要MD5
if (cacheKey.length() > 250) {
cacheKey = MD5.md5(cacheKey);
}
return cacheKey;
}
/**
* 获取参数的签名
* public for test
... ...
package com.yoho.activity.common.cache;
public interface CacheKeyAndTime {
/** 活动信息缓存时间. */
int LOTTERY_INTO = 300;
/** 用户抽奖记录. */
int LOTTERY_USER_LOTTERY = 3600;
}
... ...
... ... @@ -3,6 +3,7 @@
*/
package com.yoho.activity.controller;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
... ... @@ -22,6 +23,8 @@ import com.yoho.activity.common.vo.LotteryRespData;
import com.yoho.activity.common.vo.LotteryVO;
import com.yoho.activity.service.ILotteryService;
import com.yoho.error.exception.ServiceException;
import com.yoho.lottery.dal.model.Lottery;
import com.yoho.lottery.dal.model.Prize;
@Controller
@RequestMapping("/lottery")
... ... @@ -48,6 +51,9 @@ public class LotteryController {
checkLotteryId(lotteryId);
LotteryRespData respData = lotteryService.getLotteryInfo(lotteryId);
// clear properties
clearUnuseProp(respData.getLottery(), respData.getPrizes());
logger.info("End getLotteryInfo with req {}", vo);
return new ApiResponse(respData);
... ... @@ -96,28 +102,60 @@ public class LotteryController {
LotteryRespData respData = lotteryService.lucky(lotteryId, userId, orderCode);
clearPrize(respData.getPrize());
logger.info("End lucky with req {}", vo);
return new ApiResponse(respData);
}
private void checkLotteryId(Integer lotteryId) {
if (lotteryId == null|| lotteryId <= 0) {
logger.warn("LotteryId is empty");
logger.warn("LotteryId is invalid {}", lotteryId);
throw new ServiceException(500, "活动编号不合法");
}
}
private void checkUserId(Integer userId) {
if (userId == null || userId <= 0) {
logger.warn("UserId is empty");
logger.warn("UserId is invalid {}", userId);
throw new ServiceException(500, "用户id不合法");
}
}
private void checkOrderCode(String orderCode) {
if (StringUtils.isBlank(orderCode)) {
logger.warn("OrderCode is empty");
logger.warn("OrderCode is invalid {}", orderCode);
throw new ServiceException(500, "订单编号不合法");
}
}
private void clearUnuseProp(Lottery lottery, List<Prize> prize) {
if (lottery != null) {
lottery.setUserLimit(null);
lottery.setPersonTotal(null);
lottery.setLimitByFlag(null);
lottery.setProbability(null);
lottery.setPid(null);
}
if (prize != null) {
for (Iterator<Prize> iterator = prize.iterator(); iterator.hasNext();) {
Prize p = iterator.next();
if (!lotteryService.hasRealPrize(p)) {
iterator.remove();
} else {
clearPrize(p);
}
}
}
}
private void clearPrize(Prize p) {
if (p != null) {
p.setId(null);
p.setGiftId(null);
p.setPrizeType(null);
p.setTotal(null);
}
}
}
... ...
... ... @@ -16,9 +16,14 @@ public interface LotteryRecordMapper {
LotteryRecord selectByPrimaryKey(@Param("id") Integer id, @Param("shardFactor") int shardFactor);
int updateByPrimaryKey(@Param("record") LotteryRecord record, @Param("shardFactor") int shardFactor);
List<LotteryRecord> selectByIds(@Param("ids") List<Integer> id, @Param("shardFactor") int shardFactor);
List<LotteryRecord> selectOrderRecords(@Param("lotteryId") Integer lotteryId, @Param("userId") Integer userId,
@Param("orderCode")String orderCode, @Param("shardFactor") int shardFactor);
List<Integer> selectOrderRecordIds(@Param("lotteryId") Integer lotteryId, @Param("userId") Integer userId,
@Param("orderCode")String orderCode, @Param("shardFactor") int shardFactor);
Integer selectUserLotteryPrizeCount(@Param("lotteryId") Integer lotteryId, @Param("userId") Integer userId,
@Param("shardFactor") int shardFactor);
... ...
... ... @@ -15,4 +15,6 @@ public interface PrizeMapper {
List<Prize> selectAll();
int updateByPrimaryKey(Prize record);
int subtractPrize(Integer id);
}
\ No newline at end of file
... ...
... ... @@ -16,6 +16,8 @@ public class Prize {
private Integer total;
private String remark;
private Integer remain;
private String image;
... ... @@ -97,4 +99,12 @@ public class Prize {
+ prizeType + ", prizeValue=" + prizeValue + ", total=" + total + ", remark=" + remark + ", image="
+ image + "]";
}
public Integer getRemain() {
return remain;
}
public void setRemain(Integer remain) {
this.remain = remain;
}
}
\ No newline at end of file
... ...
... ... @@ -45,7 +45,15 @@
from lottery_record_${shardFactor}
where id = #{id,jdbcType=INTEGER}
</select>
<select id="selectByIds" resultMap="BaseResultMap">
select id, lottery_id, uid, status, flag, prize_id, mod_time
from lottery_record_${shardFactor}
where id in
<foreach collection="ids" item="id" index="index"
open="(" close=")" separator=",">
#{id}
</foreach>
</select>
<select id="selectAll" resultMap="BaseResultMap">
select <include refid="Base_Column_List" />
from lottery_record_${shardFactor}
... ... @@ -57,6 +65,18 @@
where lottery_id = #{lotteryId,jdbcType=INTEGER}
and uid = #{userId,jdbcType=INTEGER}
<if test="orderCode != null and orderCode !=''">
and flag = #{orderCode,jdbcType=VARCHAR}
</if>
<if test="lotteryId != null">
and lottery_id = #{lotteryId,jdbcType=INTEGER}
</if>
</select>
<select id="selectOrderRecordIds" resultType="java.lang.Integer">
select id
from lottery_record_${shardFactor}
where lottery_id = #{lotteryId,jdbcType=INTEGER}
and uid = #{userId,jdbcType=INTEGER}
<if test="orderCode != null and orderCode !=''">
and flag = #{orderCode,jdbcType=INTEGER}
</if>
</select>
... ...
... ... @@ -9,6 +9,7 @@
<result column="prize_type" jdbcType="VARCHAR" property="prizeType" />
<result column="prize_value" jdbcType="VARCHAR" property="prizeValue" />
<result column="total" jdbcType="INTEGER" property="total" />
<result column="remain" jdbcType="INTEGER" property="remain" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
<result column="image" jdbcType="VARCHAR" property="image" />
</resultMap>
... ... @@ -19,11 +20,11 @@
<insert id="insert" parameterType="com.yoho.lottery.dal.model.Prize">
insert into prize (id, lottery_id, gift_id,
name, prize_type, prize_value,
total, remark, image
total, remark, remain, image
)
values (#{id,jdbcType=INTEGER}, #{lotteryId,jdbcType=INTEGER}, #{giftId,jdbcType=INTEGER},
#{name,jdbcType=VARCHAR}, #{prizeType,jdbcType=VARCHAR}, #{prizeValue,jdbcType=VARCHAR},
#{total,jdbcType=INTEGER}, #{remark,jdbcType=VARCHAR}, #{image,jdbcType=VARCHAR}
#{total,jdbcType=INTEGER}, #{remark,jdbcType=VARCHAR}, #{remain,jdbcType=INTEGER}, #{image,jdbcType=VARCHAR}
)
</insert>
<update id="updateByPrimaryKey" parameterType="com.yoho.lottery.dal.model.Prize">
... ... @@ -35,21 +36,27 @@
prize_value = #{prizeValue,jdbcType=VARCHAR},
total = #{total,jdbcType=INTEGER},
remark = #{remark,jdbcType=VARCHAR},
remain = #{remain,jdbcType=INTEGER},
image = #{image,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
<update id="subtractPrize" parameterType="java.lang.Integer">
update prize
set remain = remain - 1
where id = #{id,jdbcType=INTEGER} and remain &gt; 0
</update>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select id, lottery_id, gift_id, name, prize_type, prize_value, total, remark, image
select id, lottery_id, gift_id, name, prize_type, prize_value, total, remark, remain, image
from prize
where id = #{id,jdbcType=INTEGER}
</select>
<select id="selectByLotteryId" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select id, lottery_id, gift_id, name, prize_type, prize_value, total, remark, image
select id, lottery_id, gift_id, name, prize_type, prize_value, total, remark, remain, image
from prize
where lottery_id = #{lotteryId,jdbcType=INTEGER}
</select>
<select id="selectAll" resultMap="BaseResultMap">
select id, lottery_id, gift_id, name, prize_type, prize_value, total, remark, image
select id, lottery_id, gift_id, name, prize_type, prize_value, total, remark, remain, image
from prize
</select>
</mapper>
\ No newline at end of file
... ...
... ... @@ -4,7 +4,8 @@ import java.util.List;
import com.yoho.activity.common.vo.LotteryOrderVO;
import com.yoho.activity.common.vo.LotteryRespData;
import com.yoho.service.model.order.response.Orders;
import com.yoho.lottery.dal.model.LotteryRecord;
import com.yoho.lottery.dal.model.Prize;
/**
* 描述:微信抽奖接口
... ... @@ -50,4 +51,6 @@ public interface ILotteryService {
*/
List<LotteryOrderVO> getValidOrderList(Integer userId, Integer limit, Integer page);
boolean hasRealPrize(Prize prize);
LotteryRecord[] getLotteryRecordByIds(List<Integer> ids, int shardFactor);
}
... ...
... ... @@ -5,7 +5,6 @@ package com.yoho.activity.service.impl;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
... ... @@ -20,9 +19,14 @@ import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import com.yoho.activity.common.cache.CacheAop;
import com.yoho.activity.common.cache.CacheKeyAndTime;
import com.yoho.activity.common.cache.Cacheable;
import com.yoho.activity.common.helper.SendCouponHelper;
import com.yoho.activity.common.redis.GracefulRedisTemplate;
... ... @@ -37,7 +41,6 @@ import com.yoho.lottery.dal.LotteryMapper;
import com.yoho.lottery.dal.LotteryRecordMapper;
import com.yoho.lottery.dal.PrizeMapper;
import com.yoho.lottery.dal.model.Lottery;
import com.yoho.lottery.dal.model.LotteryPrizeInfo;
import com.yoho.lottery.dal.model.LotteryRecord;
import com.yoho.lottery.dal.model.Prize;
import com.yoho.service.model.order.request.OrderListRequest;
... ... @@ -46,7 +49,7 @@ import com.yoho.service.model.order.response.Orders;
import com.yoho.service.model.order.response.OrdersGoods;
@Service
public class LotteryServiceImpl implements ILotteryService {
public class LotteryServiceImpl implements ILotteryService , ApplicationContextAware {
private static Logger logger = LoggerFactory.getLogger(LotteryServiceImpl.class);
... ... @@ -81,8 +84,12 @@ public class LotteryServiceImpl implements ILotteryService {
@Autowired
private GracefulRedisTemplate gracefulRedisTemplate;
private CacheAop cacheAop;
private ILotteryService lotteryService;
@Override
@Cacheable(expireTime = 300)
@Cacheable(expireTime = CacheKeyAndTime.LOTTERY_INTO)
public LotteryRespData getLotteryInfo(Integer lotteryId) {
LotteryRespData data = new LotteryRespData();
... ... @@ -91,9 +98,6 @@ public class LotteryServiceImpl implements ILotteryService {
checkLottery(lotteryId, lottery);
// clear properties
clearUnuseProp(lottery, prize);
data.setLottery(lottery);
data.setPrizes(prize);
return data;
... ... @@ -101,12 +105,12 @@ public class LotteryServiceImpl implements ILotteryService {
@Override
public LotteryRespData getOrderLotteryState(Integer lotteryId, Integer userId, String orderCode) {
Lottery lottery = lotteryMapper.selectByPrimaryKey(lotteryId);
checkLottery(lotteryId, lottery);
LotteryRespData lotteryInfo = lotteryService.getLotteryInfo(lotteryId);
LotteryRespData data = new LotteryRespData();
List<LotteryRecord> records = lotteryRecordMapper.selectOrderRecords(lotteryId, userId, orderCode,
lotteryId % 10);
List<Integer> recordIds = lotteryRecordMapper.selectOrderRecordIds(null, userId, orderCode,
userId % 10);
LotteryRecord[] records = lotteryService.getLotteryRecordByIds(recordIds, userId % 10);
// 批量查询:内部
if (StringUtils.isBlank(orderCode)) {
Map<String, LotteryRecord> lotteryRecordMap = new HashMap<>();
... ... @@ -116,24 +120,31 @@ public class LotteryServiceImpl implements ILotteryService {
data.setLotteryRecordMap(lotteryRecordMap);
} else {
// 检查使用
if (records.isEmpty()) {
if (records.length == 0) {
data.setOrderLotteryCode(STATE_NOT_USE);
data.setOrderLotteryMessage("参加抽奖");
} else {
LotteryRecord rec = records.get(0);
LotteryRecord rec = records[0];
boolean havePrize;
Prize prize = null;
if (rec.getPrizeId() == null || rec.getPrizeId() <= 0) {
havePrize = false;
} else {
prize = prizeMapper.selectByPrimaryKey(rec.getPrizeId());
List<Prize> prizes = lotteryInfo.getPrizes();
for(Prize p : prizes) {
if(p.getId().equals(rec.getPrizeId())) {
prize = p;
}
}
if (prize == null) {
logger.warn("错误的奖品id:活动id{} 奖品id{}", lotteryId, rec.getPrizeId());
}
havePrize = !hasRealPrize(prize);
}
if (havePrize) {
data.setOrderLotteryCode(STATE_USE_HAVA_PRIZE);
data.setOrderLotteryMessage("已中奖");
data.setPrize(prize);
clearPrize(prize);
} else {
data.setOrderLotteryCode(STATE_USE_NO_PRIZE);
data.setOrderLotteryMessage("已抽奖");
... ... @@ -144,37 +155,40 @@ public class LotteryServiceImpl implements ILotteryService {
}
@Override
public synchronized LotteryRespData lucky(Integer lotteryId, Integer userId, String orderCode) {
public LotteryRespData lucky(Integer lotteryId, Integer userId, String orderCode) {
logger.info("用户{}的订单{}进行抽奖!", userId, orderCode);
// 已抽奖检查
LotteryRespData orderLotteryState = getOrderLotteryState(lotteryId, userId, orderCode);
if (orderLotteryState.getOrderLotteryCode() != STATE_NOT_USE) {
LotteryRespData orderLotteryState = getOrderLotteryState(lotteryId, userId, null);
Map<String, LotteryRecord> recordMap = orderLotteryState.getLotteryRecordMap();
if (recordMap.containsKey(orderCode)) {
logger.info("用户{}的订单{}不符合抽奖条件!", userId, orderCode);
return orderLotteryState;
}
// 本活动中奖次数
int lotteryCount = lotteryRecordMapper.selectUserLotteryPrizeCount(lotteryId, userId, lotteryId % 10);
// int lotteryCount = lotteryRecordMapper.selectUserLotteryPrizeCount(lotteryId, userId, userId % 10);
// 只能中一次
if (lotteryCount > 0) {
if (recordMap.size() > 0) {
logger.info("用户{}的订单{}已经中过奖!", userId, orderCode);
return savePrizeAndGetResp(lotteryId, userId, orderCode, null);
}
// 查询抽奖统计信息
List<LotteryPrizeInfo> lotteryPrizeInfo = lotteryRecordMapper.selectLotteryPrizeInfo(lotteryId, lotteryId % 10);
/*List<LotteryPrizeInfo> lotteryPrizeInfo = lotteryRecordMapper.selectLotteryPrizeInfo(lotteryId, userId % 10);
Map<Integer, Integer> usedMap = new HashMap<>();
for (LotteryPrizeInfo pi : lotteryPrizeInfo) {
usedMap.put(pi.getPrizeId(), pi.getCount());
}
}*/
// 查询奖品总数信息
List<Prize> prizeList = prizeMapper.selectByLotteryId(lotteryId);
LotteryRespData lotteryInfo = lotteryService.getLotteryInfo(lotteryId);
List<Prize> prizeList = lotteryInfo.getPrizes();
Map<Integer, Integer> allMap = new HashMap<>();
for (Prize p : prizeList) {
allMap.put(p.getId(), p.getTotal());
}
/*
// 奖品剩余计算
Map<Integer, Integer> remainMap = new HashMap<>();
for (Integer prizeId : allMap.keySet()) {
... ... @@ -184,39 +198,70 @@ public class LotteryServiceImpl implements ILotteryService {
used = 0;
}
remainMap.put(prizeId, all - used);
}
}*/
// 随机抽取一个
Integer prizeId = selectOne(allMap);
logger.info("用户{}的订单{}抽到奖项{}!", userId, orderCode, prizeId);
// 奖品已经抽完
Integer remain = remainMap.get(prizeId);
if (remain <= 0) {
logger.info("用户{}的订单{}抽到奖项{},该奖项剩余量为0!", userId, orderCode, prizeId);
prizeId = null;
}
// 未抽到
if (prizeId == null) {
return savePrizeAndGetResp(lotteryId, userId, orderCode, null);
}
Prize prize = null;
for(Prize p : prizeList) {
if(p.getId().equals(prizeId)) {
prize = p;
}
}
if (prize == null) {
logger.warn("错误的奖品id:活动id{} 奖品id{}", lotteryId, prizeId);
return savePrizeAndGetResp(lotteryId, userId, orderCode, null);
}
int update = 0;
if (prize.getRemain() > 0) {
// 更新剩余奖品
update = prizeMapper.subtractPrize(prizeId);
}
// 奖品已经抽完
if (update == 0) {
logger.info("用户{}的订单{}抽到奖项{},该奖项剩余量为0!", userId, orderCode, prizeId);
try {
cacheAop.clearCache(LotteryServiceImpl.class.getMethod("getLotteryInfo", Integer.class),
new Object[] { lotteryId });
} catch (Exception e) {
logger.warn("清除LotteryServiceImpl.getLotteryInfo lotteryId={}错误", lotteryId);
}
return savePrizeAndGetResp(lotteryId, userId, orderCode, null);
}
LotteryRespData data = savePrizeAndGetResp(lotteryId, userId, orderCode, prizeId);
Prize prize = prizeMapper.selectByPrimaryKey(prizeId);
/*Prize prize = prizeMapper.selectByPrimaryKey(prizeId);
if (!hasRealPrize(prize)) {
logger.info("用户{}的订单{}抽到奖项{},该奖项为nothing!", userId, orderCode, prizeId);
data.setOrderLotteryCode(STATE_USE_NO_PRIZE);
data.setOrderLotteryMessage(MSG_NO_PRIZE);
return data;
}
}*/
data.setPrize(prize);
givePrize(userId, orderCode, prize);
clearPrize(prize);
return data;
}
@Cacheable(expireTime = CacheKeyAndTime.LOTTERY_USER_LOTTERY)
public LotteryRecord[] getLotteryRecordByIds(List<Integer> ids, int shardFactor) {
if (ids.isEmpty()) {
return new LotteryRecord[0];
}
List<LotteryRecord> rec = lotteryRecordMapper.selectByIds(ids, shardFactor);
return rec.toArray(new LotteryRecord[rec.size()]);
}
private void givePrize(Integer userId, String orderCode, Prize prize) {
logger.info("用户{}的订单{}抽到奖项{},进行发奖!", userId, orderCode, prize);
... ... @@ -246,7 +291,7 @@ public class LotteryServiceImpl implements ILotteryService {
record.setPrizeId(prizeId);
record.setStatus((byte) 0);
record.setModTime((int) (System.currentTimeMillis() / 1000));
lotteryRecordMapper.insert(record, lotteryId % 10);
lotteryRecordMapper.insert(record, userId % 10);
LotteryRespData state = new LotteryRespData();
if (prizeId == null) {
... ... @@ -365,6 +410,10 @@ public class LotteryServiceImpl implements ILotteryService {
return goodsVoList;
}
public boolean hasRealPrize(Prize prize) {
return prize != null && !StringUtils.equals("nothing", prize.getPrizeType());
}
private void checkLottery(Integer lotteryId, Lottery lottery) {
if (lottery == null) {
... ... @@ -373,37 +422,6 @@ public class LotteryServiceImpl implements ILotteryService {
}
}
private void clearUnuseProp(Lottery lottery, List<Prize> prize) {
if (lottery != null) {
lottery.setUserLimit(null);
lottery.setPersonTotal(null);
lottery.setLimitByFlag(null);
lottery.setProbability(null);
lottery.setPid(null);
}
for (Iterator<Prize> iterator = prize.iterator(); iterator.hasNext();) {
Prize p = iterator.next();
if (!hasRealPrize(p)) {
iterator.remove();
} else {
clearPrize(p);
}
}
}
private boolean hasRealPrize(Prize prize) {
return !StringUtils.equals("nothing", prize.getPrizeType());
}
private void clearPrize(Prize p) {
p.setId(null);
p.setGiftId(null);
p.setPrizeType(null);
p.setTotal(null);
}
private Integer selectOne(Map<Integer, Integer> remainMap) {
int count = 0;
for (Map.Entry<Integer, Integer> entry : remainMap.entrySet()) {
... ... @@ -425,4 +443,9 @@ public class LotteryServiceImpl implements ILotteryService {
}
return null;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
lotteryService = (ILotteryService) applicationContext.getBean("lotteryServiceImpl");
}
}
... ...