diff --git a/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java b/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java index 8fa423dee..f91b29800 100644 --- a/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java +++ b/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java @@ -177,6 +177,24 @@ public class RedisConfig extends CachingConfigurerSupport { return template; } + @Bean("pressOrderRedisTemplate") + public RedisTemplate getPressOrderRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + + Jackson2JsonRedisSerializer j = new Jackson2JsonRedisSerializer(WxOrder.class); + + // value值的序列化 + template.setValueSerializer(j); + template.setHashKeySerializer(j); + + // key的序列化 + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + + template.setConnectionFactory(connectionFactory); + return template; + } + @Bean("stringValueOperations") public ValueOperations getStringValueOperations(RedisConnectionFactory connectionFactory) { diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java index cd6a448db..8914fac8f 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java @@ -2,15 +2,16 @@ package com.iformall.controller; import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; -import com.iformall.domain.po.WxCUser; -import com.iformall.domain.po.WxCoupon; import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxOrderPress; +import com.iformall.domain.vo.WxCouponCVo; import com.iformall.enums.EnumOrderPressStatus; import com.iformall.enums.EnumOrderStatus; import com.iformall.exception.MallinkException; import com.iformall.service.WxCouponService; import com.iformall.service.WxOrderPressService; import com.iformall.service.WxOrderService; +import com.iformall.utils.RedisLock; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -18,11 +19,16 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/api/press") @@ -39,6 +45,17 @@ public class WxPressOrderController extends BaseController { @Autowired WxOrderPressService wxOrderPressService; + @Autowired + @Qualifier("pressOrderRedisTemplate") + RedisTemplate orderRedisTemplate; + + @Autowired + @Qualifier("couponDetailRedisTemplate") + RedisTemplate couponCVoRedisTemplate; + + @Autowired + RedisLock redisLock; + // 砍价列表 - /api/wxCouponChannel/list // 我的砍价 - /api/order/pressOrderList // 砍价订单详情 - /api/order/pressOrderDetail @@ -49,6 +66,7 @@ public class WxPressOrderController extends BaseController { @ApiOperation(value = "参与砍价", notes = "{\"orderId\":\"String\"}") @PostMapping("pressOrderJoin") + @Transactional public ResultData pressOrderJoin(@RequestBody Map paramMap) { Date curDate = new Date(); String orderIdStr = paramMap.get("orderId"); @@ -56,19 +74,50 @@ public class WxPressOrderController extends BaseController { return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空"); } Long orderId = 0L; + WxOrder order = null; try { orderId = Long.valueOf(orderIdStr); } catch (NumberFormatException e) { logger.error("orderId convert error, " + orderIdStr + ", e:" + e.getMessage()); return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "orderId: " + orderIdStr + ", e:" + e.getMessage()); } - WxOrder order = wxOrderService.getById(orderId); + String key = "pressorder:" + orderId; + ValueOperations operations = orderRedisTemplate.opsForValue(); + // 缓存 + boolean hasKey = orderRedisTemplate.hasKey(key); + if (hasKey) { + // 从缓存获取砍价订单信息 + order = operations.get(key); + } else { + // 订单没有入缓存,需要从数据库中读取 + order = wxOrderService.getById(orderId); + if (order != null) { + // 订单优化,进缓存 + orderRedisTemplate.opsForValue().set(key, order, 3600, TimeUnit.SECONDS); + } + } if(order == null) { logger.error("订单不存在:" + orderId); return new ResultData(ErrorCode.ORDER_IS_NOT_FIND); } - WxCoupon coupon = wxCouponService.getById(order.getProductId()); - if(coupon == null) { + WxCouponCVo wxCouponCVo = null; + String cdKey = "cd:" + order.getProductId(); + + ValueOperations cdOperations = couponCVoRedisTemplate.opsForValue(); + // 缓存 + boolean cdHasKey = couponCVoRedisTemplate.hasKey(cdKey); + if (cdHasKey) { + // 从缓存获取券信息 + wxCouponCVo = cdOperations.get(cdKey); + } else { + // 券信息没有入缓存,需要从数据库中读取 + wxCouponCVo = wxCouponService.getVoById(order.getProductId()); + if (wxCouponCVo != null) { + // 券详情优化,进缓存 + couponCVoRedisTemplate.opsForValue().set(cdKey, wxCouponCVo, 3600, TimeUnit.SECONDS); + } + } + if(wxCouponCVo == null) { logger.error("券不存在:" + order.getProductId()); return new ResultData(ErrorCode.COUPON_IS_EMPTY); } @@ -93,21 +142,98 @@ public class WxPressOrderController extends BaseController { return new ResultData(ErrorCode.ORDER_HAD_CANCEL); } - if(order.getPressCurrentNum() + 1 > coupon.getPressLimitNum()) { + if(order.getPressCurrentNum() + 1 >= wxCouponCVo.getPressLimitNum()) { logger.error("砍价已结束:" + orderId); return new ResultData(ErrorCode.COUPON_PRESS_HAD_FINISHED); } + long time = System.currentTimeMillis() + RedisLock.TIMEOUT; + String timeStr = String.valueOf(time); + if (!redisLock.lock(orderIdStr, timeStr)) { + logger.error("此砍价订单被锁定, orderId: " + orderIdStr); + return new ResultData(ErrorCode.TOO_MANY_REQUEST); + } + + Long cUserId = getUserId(); + // 检查此人是否已参与砍价 + boolean hadJoin = wxOrderPressService.checkCUserHasJoin(order, cUserId); + if (hadJoin) { + redisLock.unlock(orderIdStr, timeStr); + logger.error("用户已参与砍价"); + return new ResultData(ErrorCode.COUPON_PRESS_IS_EXIST); + } + try { - wxOrderPressService.pressCouponJoin(order, coupon, getUserId()); + WxOrderPress orderPress = wxOrderPressService.pressCouponJoin(order, wxCouponCVo, cUserId); + if (orderPress != null) { + // 更新砍价信息 + Integer index = order.getPressCurrentNum() + 1; + if(index < wxCouponCVo.getPressLimitNum()) { + // 未完成 + order.setId(order.getId()); + order.setPressCurrentNum(index); + order.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); + order.setUpdateDate(new Date()); + orderRedisTemplate.opsForValue().set(key, order, 3600, TimeUnit.SECONDS); + updatePressOrderPressing(order, key, orderPress, index); + } else { + order.setPressCurrentNum(index); + order.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode()); + order.setUpdateDate(curDate); + orderRedisTemplate.opsForValue().set(key, order, 3600, TimeUnit.SECONDS); + updatePressOrder(order, wxCouponCVo, orderPress, index); + } + } } catch (MallinkException e) { + redisLock.unlock(orderIdStr, timeStr); logger.error(e.getMessage()); return new ResultData(e.getErrorCode(), e.getMessage()); } - + redisLock.unlock(orderIdStr, timeStr); return new ResultData(); } + private void updatePressOrderPressing(WxOrder order, String key, WxOrderPress orderPress, Integer index) { + + WxOrder orderUpdatePress = new WxOrder(); + orderUpdatePress.setId(order.getId()); + orderUpdatePress.setPressCurrentNum(index); + orderUpdatePress.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); + orderUpdatePress.setUpdateDate(new Date()); + // 保存订单 + wxOrderService.saveOrUpdate(orderUpdatePress); + } + + private void updatePressOrderPressing(WxOrder order, WxOrderPress orderPress, Integer index) { + WxOrder orderUpdatePress = new WxOrder(); + orderUpdatePress.setId(order.getId()); + orderUpdatePress.setPressCurrentNum(index); + orderUpdatePress.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); + orderUpdatePress.setUpdateDate(new Date()); + // 保存订单 + wxOrderService.saveOrUpdate(orderUpdatePress); + } + + private void updatePressOrder(WxOrder order, WxCouponCVo wxCouponCVo, WxOrderPress orderPress, Integer index) { + WxOrder orderUpdatePress = new WxOrder(); + orderUpdatePress.setId(order.getId()); + orderUpdatePress.setPressCurrentNum(index); + orderUpdatePress.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode()); + orderUpdatePress.setPayment(wxCouponCVo.getSalePrice()); + orderUpdatePress.setUpdateDate(new Date()); + // 保存订单 + wxOrderService.saveOrUpdate(orderUpdatePress); + // 发送砍价成功消息 + if(index.equals(wxCouponCVo.getPressLimitNum())) { + wxOrderPressService.sendPressComplateMsg(orderUpdatePress); + } + } + @ApiOperation(value = "砍价状态(1:我发起的砍价,2:未参与的砍价, 3:已参与的砍价)", notes = "") @GetMapping("getPressOrderStatus") @ApiImplicitParam(name = "orderId", value = "orderId", dataType = "String", paramType = "query", required = true) diff --git a/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java b/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java index ab0313ec0..5c4b2133e 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java @@ -47,7 +47,7 @@ public interface WxOrderPressService { * @param coupon * @param cUserId */ - void pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId); + WxOrderPress pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId); /** * 检查用户砍价状态 @@ -55,6 +55,10 @@ public interface WxOrderPressService { * @param cUserId */ int pressCouponStatus(WxOrder order, Long cUserId); + + boolean checkCUserHasJoin(WxOrder order, Long cUserId); + + void sendPressComplateMsg(WxOrder orderUpdatePress); diff --git a/mallinkService/src/main/java/com/iformall/service/WxOrderService.java b/mallinkService/src/main/java/com/iformall/service/WxOrderService.java index b11673021..28ecccc3c 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxOrderService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxOrderService.java @@ -114,6 +114,14 @@ public interface WxOrderService { * @return */ WxOrder getById(Long id); + + /** + * 根据Id获得实体 + * + * @param id + * @return + */ + WxOrder getPressOrderById(Long id); /** * 保存或更新实体 diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java index 42dc0e54c..2eb8afc17 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java @@ -24,11 +24,14 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import java.util.concurrent.TimeUnit; @Service public class WxOrderPressServiceImpl implements WxOrderPressService { @@ -52,7 +55,6 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { @Autowired MqBaseProducer mqBaseProducer; - @Override public PageInfo listAsPage(WxOrderPress record, Integer pageIndex, Integer pageSize) { return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderPressMapper.findList(record)); @@ -82,25 +84,12 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { @Override - public void pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId) { + public WxOrderPress pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId) { final IdWorker idWorker = IdWorker.get(); Date curDate = new Date(); - // 检查此人是否已参与砍价 - WxOrderPress orderPressQ = new WxOrderPress(); - orderPressQ.setTenantId(order.getTenantId()); - orderPressQ.setOrderId(order.getId()); - orderPressQ.setUserId(cUserId); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.setEntity(orderPressQ); - int count = wxOrderPressMapper.selectCount(queryWrapper); - if(count >= 1) { - logger.error("用户已参与砍价: " + cUserId); - throw new MallinkException(ErrorCode.COUPON_PRESS_IS_EXIST); - } // 添加 wx_order_press int total = coupon.getPrice() - coupon.getSalePrice(); - int left_total = order.getPressCurrentValue(); WxOrderPress orderPress = new WxOrderPress(); orderPress.setId(idWorker.nextId()); orderPress.setTenantId(order.getTenantId()); @@ -109,7 +98,7 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { orderPress.setUserId(cUserId); orderPress.setCreateDate(curDate); orderPress.setFirst(EnumOrderPressType.NORMAL.getCode()); - orderPress.setPressValue(PressUtils.stateLessPressValue(total, left_total, coupon.getPressLimitNum(), order.getPressCurrentNum())); + orderPress.setPressValue(PressUtils.stateLessPressValue(total, order.getPressCurrentValue(), coupon.getPressLimitNum(), order.getPressCurrentNum())); try { // 保存订单 @@ -118,30 +107,20 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { logger.error("保存砍价记录Error:" + e.getMessage()); throw new MallinkException(ErrorCode.DB_FAIL); } + return orderPress; + } - // 更新砍价信息 - Integer index = order.getPressCurrentNum() + 1; - WxOrder orderUpdatePress = new WxOrder(); - orderUpdatePress.setId(order.getId()); - orderUpdatePress.setPressCurrentNum(index); - orderUpdatePress.setPressCurrentValue(left_total - orderPress.getPressValue()); - if(index.equals(coupon.getPressLimitNum())) { - orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode()); - orderUpdatePress.setPayment(coupon.getSalePrice()); + @Override + public boolean checkCUserHasJoin(WxOrder order, Long cUserId) { + WxOrderPress orderPressQ = new WxOrderPress(); + orderPressQ.setTenantId(order.getTenantId()); + orderPressQ.setOrderId(order.getId()); + orderPressQ.setUserId(cUserId); + int count = wxOrderPressMapper.selectCount(new QueryWrapper<>(orderPressQ)); + if(count >= 1) { + return true; } else { - orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); - } - orderUpdatePress.setUpdateDate(new Date()); - try { - // 保存订单 - wxOrderMapper.updateById(orderUpdatePress); - } catch (RuntimeException e) { - logger.error("更新订单Error:" + e.getMessage()); - throw new MallinkException(ErrorCode.DB_FAIL); - } - // 发送砍价成功消息 - if(index.equals(coupon.getPressLimitNum())) { - sendPressComplateMsg(orderUpdatePress); + return false; } } @@ -167,7 +146,8 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { * * @param */ - private void sendPressComplateMsg(WxOrder orderUpdatePress) { + @Override + public void sendPressComplateMsg(WxOrder orderUpdatePress) { // 1. get order info WxOrder order = wxOrderMapper.selectById(orderUpdatePress.getId()); if (order == null) { diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java index ee01b9ef2..fec3ae16c 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java @@ -1427,6 +1427,12 @@ public class WxOrderServiceImpl implements WxOrderService { return wxOrderMapper.selectById(id); } + @Override + public WxOrder getPressOrderById(Long id) { + + return wxOrderMapper.selectById(id); + } + @Override public void saveOrUpdate(WxOrder record) { if (record.getId() == null) {