ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constants/NotificationTypeConstant.java
New file @@ -0,0 +1,11 @@ package com.ruoyi.system.api.constants; /** * @author mitao * @date 2024/5/27 */ public interface NotificationTypeConstant { String SECKILL = "seckill"; String GROUP_PURCHASE = "group_purchase"; } ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/inner/GoodsGroupPurchaseController.java
@@ -1,6 +1,7 @@ package com.ruoyi.goods.controller.inner; import com.fasterxml.jackson.core.JsonProcessingException; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.security.annotation.InnerAuth; import com.ruoyi.goods.service.IGoodsGroupPurchaseService; @@ -35,7 +36,12 @@ @InnerAuth @GetMapping("/start/{groupPurchaseId}") R<?> startGroupPurchase(@PathVariable("groupPurchaseId") Long groupPurchaseId) { try { goodsGroupPurchaseService.startGroupPurchase(groupPurchaseId); } catch (JsonProcessingException e) { log.error("团购商品开始团购失败", e); return R.fail("团购商品开始团购失败"); } return R.ok(); } @@ -47,7 +53,12 @@ @InnerAuth @GetMapping("/end/{groupPurchaseId}") R<?> endGroupPurchase(@PathVariable("groupPurchaseId") Long groupPurchaseId) { try { goodsGroupPurchaseService.endGroupPurchase(groupPurchaseId); } catch (JsonProcessingException e) { log.error("团购商品开始团购失败", e); return R.fail("团购商品结束团购失败"); } return R.ok(); } } ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/IGoodsGroupPurchaseService.java
@@ -1,6 +1,7 @@ package com.ruoyi.goods.service; import com.baomidou.mybatisplus.extension.service.IService; import com.fasterxml.jackson.core.JsonProcessingException; import com.ruoyi.common.core.utils.page.PageDTO; import com.ruoyi.goods.controller.management.dto.GoodsGroupPurchaseDTO; import com.ruoyi.goods.controller.management.dto.GoodsGroupPurchaseQuery; @@ -53,14 +54,14 @@ * * @param groupPurchaseId 团购商品id */ void startGroupPurchase(Long groupPurchaseId); void startGroupPurchase(Long groupPurchaseId) throws JsonProcessingException; /** * 团购商品结束团购 * * @param groupPurchaseId 团购商品id */ void endGroupPurchase(Long groupPurchaseId); void endGroupPurchase(Long groupPurchaseId) throws JsonProcessingException; /** * 立即结束团购 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/IGoodsSeckillService.java
@@ -1,6 +1,7 @@ package com.ruoyi.goods.service; import com.baomidou.mybatisplus.extension.service.IService; import com.fasterxml.jackson.core.JsonProcessingException; import com.ruoyi.common.core.utils.page.PageDTO; import com.ruoyi.goods.controller.management.dto.GoodsSeckillDTO; import com.ruoyi.goods.controller.management.dto.GoodsSeckillQuery; @@ -61,12 +62,12 @@ * * @param seckillId 秒杀id */ void startSeckill(Long seckillId); void startSeckill(Long seckillId) throws JsonProcessingException; /** * 结束秒杀 * * @param seckillId 秒杀id */ void endSeckill(Long seckillId); void endSeckill(Long seckillId) throws JsonProcessingException; } ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/GoodsGroupPurchaseServiceImpl.java
@@ -2,6 +2,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.core.enums.GroupStatusEnum; import com.ruoyi.common.core.enums.ListingStatusEnum; import com.ruoyi.common.core.enums.PaymentMethodEnum; @@ -18,15 +20,19 @@ import com.ruoyi.goods.service.IGoodsGroupPurchaseService; import com.ruoyi.goods.service.IGoodsSkuService; import com.ruoyi.goods.service.async.AsyncMethodService; import com.ruoyi.system.api.WebSocketUsers; import com.ruoyi.system.api.constants.NotificationTypeConstant; import com.ruoyi.system.api.domain.GoodsSku; import com.ruoyi.system.api.domain.Order; import com.ruoyi.system.api.domain.dto.ListStatusDTO; import com.ruoyi.system.api.feignClient.OrderClient; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import util.WebSocketUsers; /** * <p> @@ -44,6 +50,8 @@ private final OrderClient orderClient; private final IGoodsSkuService goodsSkuService; private final AsyncMethodService asyncMethodService; // 创建一个静态共享的ObjectMapper实例以重用 private static final ObjectMapper objectMapper = new ObjectMapper(); /** * 获取团购商品列表的分页数据 * @@ -148,15 +156,19 @@ * @param groupPurchaseId 团购商品id */ @Override public void startGroupPurchase(Long groupPurchaseId) { public void startGroupPurchase(Long groupPurchaseId) throws JsonProcessingException { log.info(">>>>>>>>>>>>>>>>>>>>{}团购商品开始团购<<<<<<<<<<<<<<<<<<<<", groupPurchaseId); GoodsGroupPurchase groupPurchase = this.getById(groupPurchaseId); if (StringUtils.isNotNull(groupPurchase)) { this.lambdaUpdate().set(GoodsGroupPurchase::getStartStatus, StartStatusEnum.STARTED) .eq(GoodsGroupPurchase::getId, groupPurchaseId).update(); //TODO 通知小程序 WebSocketUsers.sendMessageToUsersByText( "团购商品" + groupPurchase.getGoodsSkuName() + "开始团购"); Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.GROUP_PURCHASE); map.put("notification_time", LocalDateTime.now()); map.put("message_type", "start"); String msg = objectMapper.writeValueAsString(map); WebSocketUsers.sendMessageToUsersByText(msg); log.info("===================>发送websocket通知,消息体{}", msg); } } @@ -166,15 +178,19 @@ * @param groupPurchaseId 团购商品id */ @Override public void endGroupPurchase(Long groupPurchaseId) { public void endGroupPurchase(Long groupPurchaseId) throws JsonProcessingException { log.info(">>>>>>>>>>>>>>>>>>>>{}团购商品结束团购<<<<<<<<<<<<<<<<<<<<", groupPurchaseId); GoodsGroupPurchase groupPurchase = this.getById(groupPurchaseId); if (StringUtils.isNotNull(groupPurchase)) { this.lambdaUpdate().set(GoodsGroupPurchase::getStartStatus, StartStatusEnum.ENDED) .eq(GoodsGroupPurchase::getId, groupPurchaseId).update(); //TODO 通知小程序 WebSocketUsers.sendMessageToUsersByText( "团购商品" + groupPurchase.getGoodsSkuName() + "结束团购"); Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.GROUP_PURCHASE); map.put("notification_time", LocalDateTime.now()); map.put("message_type", "end"); String msg = objectMapper.writeValueAsString(map); WebSocketUsers.sendMessageToUsersByText(msg); log.info("===================>发送websocket通知,消息体{}", msg); } } ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/GoodsSeckillServiceImpl.java
@@ -2,6 +2,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.enums.StartStatusEnum; import com.ruoyi.common.core.exception.ServiceException; @@ -17,18 +19,22 @@ import com.ruoyi.goods.service.IGoodsSeckillService; import com.ruoyi.goods.service.IGoodsSkuService; import com.ruoyi.goods.service.async.AsyncMethodService; import com.ruoyi.system.api.WebSocketUsers; import com.ruoyi.system.api.constants.NotificationTypeConstant; import com.ruoyi.system.api.domain.GoodsSeckill; import com.ruoyi.system.api.domain.GoodsSku; import com.ruoyi.system.api.domain.dto.ListStatusDTO; import com.ruoyi.system.api.feignClient.OrderClient; import com.ruoyi.system.api.feignClient.SysUserClient; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import util.WebSocketUsers; /** * <p> @@ -48,6 +54,8 @@ private final RedisService redisService; private final SysUserClient sysUserClient; private final AsyncMethodService asyncMethodService; // 创建一个静态共享的ObjectMapper实例以重用 private static final ObjectMapper objectMapper = new ObjectMapper(); @Override @Transactional(rollbackFor = Exception.class) public void addGoodsSeckill(GoodsSeckillDTO dto) { @@ -147,7 +155,7 @@ * @param seckillId 秒杀id */ @Override public void startSeckill(Long seckillId) { public void startSeckill(Long seckillId) throws JsonProcessingException { log.info(">>>>>>>>>>>>>>>>>>>>{}秒杀开始<<<<<<<<<<<<<<<<<<<<", seckillId); GoodsSeckill goodsSeckill = this.getById(seckillId); //秒杀商品不能为空且状态为未开始 @@ -162,7 +170,13 @@ goodsSeckill.getSeckillStock()); } //推送秒杀开始消息 WebSocketUsers.sendMessageToUsersByText("秒杀活动已开始"); Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.SECKILL); map.put("notification_time", LocalDateTime.now()); map.put("message_type", "start"); String msg = objectMapper.writeValueAsString(map); WebSocketUsers.sendMessageToUsersByText(msg); log.info("===================>发送websocket通知,消息体{}", msg); } /** @@ -171,7 +185,7 @@ * @param seckillId 秒杀id */ @Override public void endSeckill(Long seckillId) { public void endSeckill(Long seckillId) throws JsonProcessingException { log.info(">>>>>>>>>>>>>>>>>>>>{}秒杀结束<<<<<<<<<<<<<<<<<<<<", seckillId); GoodsSeckill goodsSeckill = this.getById(seckillId); if (StringUtils.isNotNull(goodsSeckill) @@ -182,7 +196,12 @@ // 将秒杀商品从缓存中移除 redisService.deleteObject(CacheConstants.SECKILL_GOODS + goodsSeckill.getId()); } //TODO websocket 推送秒杀结束消息 WebSocketUsers.sendMessageToUsersByText("秒杀活动已结束"); Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.SECKILL); map.put("notification_time", LocalDateTime.now()); map.put("message_type", "end"); String msg = objectMapper.writeValueAsString(map); WebSocketUsers.sendMessageToUsersByText(msg); log.info("===================>发送websocket通知,消息体{}", msg); } }