1、秒杀代码
@Service
public class SeckillOrderServiceImpl implements SeckillOrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ThreadPoolExecutor threadPoolExecutor;
@Resource
private SeckillOrderMapper seckillOrderMapper;
@Autowired
private RedissonClient redissonClient;
@Override
public UserRecode addSeckillOrder(String time, String goodsId, Integer num) {
UserRecode userRecode = new UserRecode();
String username = ThreadLocalUtil.get();
Long increment = redisTemplate.opsForValue().increment("User_Recode_Count_" + username, 1);
if (increment > 1) {
userRecode.setStatus(3);
userRecode.setMsg("重复排队,秒杀失败");
return userRecode;
}
userRecode.setTime(time);
userRecode.setGoodsId(goodsId);
userRecode.setNum(num);
userRecode.setUsername(ThreadLocalUtil.get());
userRecode.setCreateTime(new Date());
CompletableFuture.runAsync(() -> {
redisTemplate.opsForValue().set("User_Recode_Info_" + username, userRecode);
rabbitTemplate.convertAndSend("seckill_order_exchange", "seckill.order", JSONObject.toJSONString(userRecode));
redisTemplate.expire("User_Recode_Count" + username, 300, TimeUnit.SECONDS);
}, threadPoolExecutor).whenCompleteAsync((a, b) -> {
if (b != null) {
userRecode.setStatus(3);
userRecode.setMsg("排队失败,请重新排队");
redisTemplate.opsForValue().set("User_Recode_Info_" + username, userRecode);
redisTemplate.delete("User_Recode_Count_" + username);
}
});
return userRecode;
}
@Override
public void realSeckillOrderAdd(String userRecodeString) {
UserRecode userRecode = JSONObject.parseObject(userRecodeString, UserRecode.class);
String username = userRecode.getUsername();
String time = userRecode.getTime();
String nowTime = DateUtil.data2str(DateUtil.getDateMenus().get(0), DateUtil.PATTERN_YYYYMMDDHH);
if (!time.equals(nowTime)) {
seckillOrderFail(userRecode, "秒杀的商品不在活动的时间以内");
return;
}
String goodsId = userRecode.getGoodsId();
SeckillGoods seckillGoods = (SeckillGoods) redisTemplate.opsForHash().get(time, goodsId);
if (seckillGoods == null) {
seckillOrderFail(userRecode, "商品不存在");
return;
}
Integer num = userRecode.getNum();
if (num <= 0) {
seckillOrderFail(userRecode, "商品购买数量错误");
return;
}
if (num > seckillGoods.getSeckillLimit()) {
seckillOrderFail(userRecode, "商品购买超出限购");
return;
}
for (int i = 0; i < num; i++) {
Object o =
redisTemplate.opsForList().rightPop("Seckill_Goods_Stock_Queue_" + goodsId);
if (o == null) {
if (i > 0) {
redisTemplate.opsForList().leftPushAll("Seckill_Goods_Stock_Queue_" + goodsId, StockUtil.getIds(i));
}
seckillOrderFail(userRecode, "库存不足");
return;
}
}
Long increment = redisTemplate.opsForHash().increment("Seckill_Goods_Stock_Count_" + time, goodsId, -num);
SeckillOrder seckillOrder = new SeckillOrder();
seckillOrder.setId(UUID.randomUUID().toString().replaceAll("-", ""));
seckillOrder.setGoodsId(goodsId);
seckillOrder.setMoney(seckillGoods.getCostPrice().multiply(new BigDecimal(num)));
seckillOrder.setUserId(username);
seckillOrder.setCreateTime(new Date());
seckillOrder.setStatus(OrderStatus.UNPAID.getComment());
seckillOrder.setNum(num);
redisTemplate.opsForHash().put("Seckill_Order_" + time, seckillOrder.getId(), seckillOrder);
userRecode.setStatus(2);
userRecode.setMsg("秒杀成功,等待支付!");
userRecode.setOrderId(seckillOrder.getId());
userRecode.setMoney(seckillOrder.getMoney().doubleValue() + "");
redisTemplate.opsForValue().set("User_Recode_Info_" + userRecode.getUsername(), userRecode);
seckillGoods.setStockCount(increment.intValue());
redisTemplate.opsForHash().put(time, goodsId, seckillGoods);
rabbitTemplate.convertAndSend(
"seckill_order_delay_exchange",
"seckill.order.dead",
username + "",
(message -> {
MessageProperties messageProperties = message.getMessageProperties();
messageProperties.setExpiration(50000 + "");
return message;
})
);
}
2、普通新增订单
@Override
public void addOrder(OrderInfo orderInfo) {
RLock lock = redissonClient.getLock("Add_Order_Lock_" + ThreadLocalUtil.get());
try {
if (lock.tryLock()) {
try {
redisTemplate.expire("Add_Order_Lock_" + ThreadLocalUtil.get(), 60, TimeUnit.SECONDS);
if (orderInfo == null) {
throw new GmallException("参数错误,新增订单失败", 201);
}
Map<String, Object> result = cartFeign.getOrderAddInfo();
if (result == null)
throw new GmallException("本次未勾选任何购物车数据,新增订单失败", 201);
orderInfo.setTotalAmount(new BigDecimal(result.get("totalMoney").toString()));
orderInfo.setOrderStatus(OrderStatus.UNPAID.getComment());
orderInfo.setUserId(ThreadLocalUtil.get());
orderInfo.setCreateTime(new Date());
orderInfo.setExpireTime(new Date(System.currentTimeMillis() + 1800000));
orderInfo.setProcessStatus(ProcessStatus.UNPAID.getComment());
int insert = orderInfoMapper.insert(orderInfo);
if (insert <= 0) {
throw new GmallException("新增订单发送异常,失败,请重试!", 201);
}
Long orderId = orderInfo.getId();
List cartInfoList = (List) result.get("cartInfoList");
Map decountMap = saveOrderDetail(orderId, cartInfoList);
if (!productFeign.decountStock(decountMap)) {
throw new GmallException("库存不足", 201);
}
rabbitTemplate.convertAndSend(
"order_nomal_exchange",
"order.nomal",
orderId + "",
(message) -> {
MessageProperties messageProperties = message.getMessageProperties();
messageProperties.setExpiration(1800000 + "");
return message;
}
);
} catch (Exception e) {
log.error("商品不足,下单失败" + e.getMessage());
throw e;
} finally {
lock.unlock();
}
} else {
throw new GmallException("重复下单!", 201);
}
} catch (Exception e) {
throw e;
}
}
private Map saveOrderDetail(Long orderId, List cartInfoList) {
Map decountMap = new ConcurrentHashMap<>();
cartInfoList.stream().forEach(o -> {
String s = JSONObject.toJSONString(o);
CartInfo cartInfo = JSONObject.parseObject(s, CartInfo.class);
OrderDetail orderDetail = new OrderDetail();
orderDetail.setOrderId(orderId);
orderDetail.setSkuId(cartInfo.getSkuId());
orderDetail.setSkuName(cartInfo.getSkuName());
orderDetail.setImgUrl(cartInfo.getImgUrl());
orderDetail.setOrderPrice(cartInfo.getSkuPrice());
orderDetail.setSkuNum(cartInfo.getSkuNum());
int insert = orderDetailMapper.insert(orderDetail);
if (insert <= 0) {
throw new GmallException("新增详情发送异常,失败,请重试", 201);
}
decountMap.put(cartInfo.getSkuId() + "", cartInfo.getSkuNum());
});
return decountMap;
}
3、商品详情页
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ProductFeign productFeign;
@Autowired
private ThreadPoolExecutor threadPoolExecutor;
@Override
public Map<String, Object> getItemPageInfo(Long skuId) {
Map<String, Object> result = new ConcurrentHashMap<>();
if (skuId == null)
return null;
CompletableFuture<SkuInfo> future1 = CompletableFuture.supplyAsync(() -> {
SkuInfo skuInfo = productFeign.getSkuInfo(skuId);
if (skuInfo == null || skuInfo.getId() == null)
return null;
result.put("skuInfo", skuInfo);
return skuInfo;
},threadPoolExecutor);
CompletableFuture<Void> future2 = future1.thenAcceptAsync((skuInfo) -> {
if (skuInfo == null || skuInfo.getId() == null)
return;
Long category3Id = skuInfo.getCategory3Id();
BaseCategoryView category = productFeign.getCategory(category3Id);
result.put("category", category);
},threadPoolExecutor);
CompletableFuture<Void> future3 = future1.thenAcceptAsync((skuInfo) -> {
if (skuInfo == null || skuInfo.getId() == null)
return;
List<SkuImage> skuImages = productFeign.getSkuImages(skuId);
result.put("skuImages", skuImages);
},threadPoolExecutor);
CompletableFuture<Void> future4 = future1.thenAcceptAsync((skuInfo) -> {
if (skuInfo == null || skuInfo.getId() == null) {
return;
}
BigDecimal skuPrice = productFeign.getPrice(skuId);
result.put("skuPrice", skuPrice);
},threadPoolExecutor);
CompletableFuture<Void> future5 = future1.thenAcceptAsync((skuInfo) -> {
if (skuInfo == null || skuInfo.getId() == null) {
return;
}
Long spuId = skuInfo.getSpuId();
List<SpuSaleAttr> spuSaleAttrsList = productFeign.getSpuSaleAttr(skuId, spuId);
result.put("spuSaleAttrsList", spuSaleAttrsList);
},threadPoolExecutor);
CompletableFuture<Void> future6 = future1.thenAcceptAsync((skuInfo) -> {
if (skuInfo == null || skuInfo.getId() == null) {
return;
}
Map skuKeyAndValue = productFeign.getSkuKeyAndValue(skuInfo.getSpuId());
result.put("skuKeyAndValue", skuKeyAndValue);
},threadPoolExecutor);
CompletableFuture.allOf(future2, future3, future4, future5, future6).join();
return result;
}
}
3.1自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Java1126GmallCache {
String prefix() default "cache";
}
3.2 aop切面类
@Component
@Aspect
public class GmallCacheAspect {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
@Around("@annotation(com.atguigu.gmall.common.cache.Java1126GmallCache)")
public Object cacheAroundAdvice(ProceedingJoinPoint point) {
Object result = null;
try {
Object[] args = point.getArgs();
MethodSignature signature = (MethodSignature) point.getSignature();
Java1126GmallCache gmallCache = signature.getMethod().getAnnotation(Java1126GmallCache.class);
String prefix = gmallCache.prefix();
String key = prefix + Arrays.asList(args).toString();
result = cacheHit(signature, key);
if (result != null) {
return result;
}
RLock lock = redissonClient.getLock(key + ":lock");
boolean flag = lock.tryLock(100, 100, TimeUnit.SECONDS);
if (flag) {
try {
try {
result = point.proceed(point.getArgs());
if (null == result) {
Class<?> returnType = signature.getReturnType();
result = returnType.getDeclaredConstructor().newInstance();
this.redisTemplate.opsForValue().set(key, JSONObject.toJSONString(result), 300, TimeUnit.SECONDS);
} else {
this.redisTemplate.opsForValue().set(key, JSONObject.toJSONString(result), 24 * 60 * 60, TimeUnit.SECONDS);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
private Object cacheHit(MethodSignature signature, String key) {
String cache = (String) redisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(cache)) {
Class returnType = signature.getReturnType();
return JSONObject.parseObject(cache, returnType);
}
return null;
}
}
4、product
@Override
public List<JSONObject> getIndexCategory() {
List<BaseCategoryView> baseCategory1ViewList = baseCategoryViewMapper.selectList(null);
Map<Long, List<BaseCategoryView>> category1Map = baseCategory1ViewList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory1Id));
return category1Map.entrySet().stream().map(category1 -> {
JSONObject category1Json = new JSONObject();
Long category1Id = category1.getKey();
category1Json.put("categoryId", category1Id);
List<BaseCategoryView> baseCategory2ViewList = category1.getValue();
String category1Name = baseCategory2ViewList.get(0).getCategory1Name();
category1Json.put("categoryName", category1Name);
Map<Long, List<BaseCategoryView>> category2Map = baseCategory2ViewList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));
List<JSONObject> category2JsonList = category2Map.entrySet().stream().map(category2 -> {
JSONObject category2Json = new JSONObject();
Long category2Id = category2.getKey();
category2Json.put("categoryId", category2Id);
List<BaseCategoryView> baseCategory3ViewList = category2.getValue();
String category2Name = baseCategory3ViewList.get(0).getCategory2Name();
category2Json.put("categoryName", category2Name);
List<JSONObject> category3JsonList = baseCategory3ViewList.stream().map(category3 -> {
JSONObject category3Json = new JSONObject();
Long category3Id = category3.getCategory3Id();
category3Json.put("categoryId", category3Id);
String category3Name = category3.getCategory3Name();
category3Json.put("categoryName", category3Name);
return category3Json;
}).collect(Collectors.toList());
category2Json.put("childCategory", category3JsonList);
return category2Json;
}).collect(Collectors.toList());
category1Json.put("childCategory", category2JsonList);
return category1Json;
}).collect(Collectors.toList());
}
5、购物车
@Service
@Transactional(rollbackFor = Exception.class)
public class CartInfoServiceImpl implements CartInfoService {
@Autowired
private ProductFeign productFeign;
@Resource
private CartInfoMapper cartInfoMapper;
@Override
public void addCart(Long skuId, Integer num) {
if (skuId == null || num == null) {
throw new GmallException("新增购物车失败,参数错误", 201);
}
SkuInfo skuInfo = productFeign.getSkuInfo(skuId);
if (skuInfo == null || skuInfo.getId() == null) {
throw new GmallException("新增购物车失败,商品不存在", 201);
}
String username = ThreadLocalUtil.get();
CartInfo cartInfo = cartInfoMapper.selectOne(
new LambdaQueryWrapper<CartInfo>()
.eq(CartInfo::getUserId, username)
.eq(CartInfo::getSkuId, skuId));
if (cartInfo == null || cartInfo.getSkuId() == null) {
if (num <= 0) {
throw new GmallException("新增购物车失败,数量错误", 201);
}
num = num > 199 ? 199 : num;
cartInfo = new CartInfo();
cartInfo.setUserId(username);
cartInfo.setSkuId(skuId);
BigDecimal price = productFeign.getPrice(skuId);
cartInfo.setCartPrice(price);
cartInfo.setSkuNum(num);
cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
cartInfo.setSkuName(skuInfo.getSkuName());
int insert = cartInfoMapper.insert(cartInfo);
if (insert <= 0) {
throw new GmallException("新增购物车失败,请重试", 201);
}
} else {
num = cartInfo.getSkuNum() + num;
if (num <= 0) {
int delete = cartInfoMapper.deleteById(cartInfo.getId());
if (delete < 0) {
throw new GmallException("新增购物车失败,请重试", 201);
}
} else {
num = num > 199 ? 199 : num;
cartInfo.setSkuNum(num);
int i = cartInfoMapper.updateById(cartInfo);
if (i < 0) {
throw new GmallException("新增购物车失败,请重试", 201);
}
}
}
}
@Override
public void mergeCart(List<CartInfo> cartInfoList) {
if (cartInfoList == null || cartInfoList.isEmpty())
return;
cartInfoList.stream().forEach(cartInfo -> {
this.addCart(cartInfo.getSkuId(), cartInfo.getSkuNum());
});
}
@Override
public Map<String, Object> getOrderConfirmInfo() {
List<CartInfo> cartInfoList =
cartInfoMapper.selectList(
new LambdaQueryWrapper<CartInfo>()
.eq(CartInfo::getUserId, ThreadLocalUtil.get())
.eq(CartInfo::getIsChecked, CartConst.CART_CHECK)
);
if (cartInfoList == null && cartInfoList.isEmpty()) {
return null;
}
AtomicInteger totalNum = new AtomicInteger(0);
AtomicDouble totalMoney = new AtomicDouble(0);
List<CartInfo> cartInfoListNew = cartInfoList.stream().map(cartInfo -> {
Long skuId = cartInfo.getSkuId();
BigDecimal price = productFeign.getPrice(skuId);
cartInfo.setSkuPrice(price);
totalNum.getAndAdd(cartInfo.getSkuNum());
totalMoney.getAndAdd(price.multiply(new BigDecimal(cartInfo.getSkuNum())).doubleValue());
return cartInfo;
}).collect(Collectors.toList());
Map<String, Object> result = new HashMap<>();
result.put("totalNum", totalNum);
result.put("totalMoney", totalMoney);
result.put("cartInfoList", cartInfoListNew);
return result;
}
@Override
public void clearCart() {
int delete =
cartInfoMapper.delete(
new LambdaQueryWrapper<CartInfo>()
.eq(CartInfo::getUserId, ThreadLocalUtil.get())
.eq(CartInfo::getIsChecked, CartConst.CART_CHECK));
if (delete < 0) {
throw new GmallException("清理购物车失败", 201);
}
}
}