From cea88fc351f48ec00db3fc6b42dad32d9b1ce42d Mon Sep 17 00:00:00 2001 From: JIAN Date: Tue, 24 Sep 2024 22:54:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(market):=E6=96=B0=E5=A2=9E=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E6=B4=BB=E5=8A=A8=E4=BF=A1=E6=81=AF=E5=92=8C=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=BC=93=E5=AD=98=E7=9A=84=E6=B4=BB=E5=8A=A8=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumer/ActivityController.java | 44 ++++++++++++++++++ .../jzo2o/market/handler/XxlJobHandler.java | 45 +++++++++++++++++++ .../dto/response/SeizeCouponInfoResDTO.java | 14 +++--- .../market/service/IActivityService.java | 17 +++++-- .../service/impl/ActivityServiceImpl.java | 33 ++++++++++++++ 5 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 jzo2o-market/src/main/java/com/jzo2o/market/controller/consumer/ActivityController.java diff --git a/jzo2o-market/src/main/java/com/jzo2o/market/controller/consumer/ActivityController.java b/jzo2o-market/src/main/java/com/jzo2o/market/controller/consumer/ActivityController.java new file mode 100644 index 0000000..b1cb9fc --- /dev/null +++ b/jzo2o-market/src/main/java/com/jzo2o/market/controller/consumer/ActivityController.java @@ -0,0 +1,44 @@ +package com.jzo2o.market.controller.consumer; + +import com.jzo2o.common.expcetions.BadRequestException; +import com.jzo2o.market.enums.ActivityStatusEnum; +import com.jzo2o.market.model.dto.response.SeizeCouponInfoResDTO; +import com.jzo2o.market.service.IActivityService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户端 - 活动管理控制器 + * @author JIAN + */ +@Slf4j +@RestController("consumerActivityController") +@RequestMapping("/consumer/activity") +public class ActivityController { + @Resource + private IActivityService activityService; + + /** + * 用户端查询缓存中的活动信息 + * @param tabType 1 进行中 2 待生效 + */ + @GetMapping("/list") + public List listActivity(@RequestParam Integer tabType) { + ActivityStatusEnum activityStatusEnum; + if (tabType == 1) { + activityStatusEnum = ActivityStatusEnum.DISTRIBUTING; + } else if (tabType == 2) { + activityStatusEnum = ActivityStatusEnum.NO_DISTRIBUTE; + } else { + throw new BadRequestException("请求的状态出错"); + } + + return activityService.getCachedActivity(activityStatusEnum); + } +} \ No newline at end of file diff --git a/jzo2o-market/src/main/java/com/jzo2o/market/handler/XxlJobHandler.java b/jzo2o-market/src/main/java/com/jzo2o/market/handler/XxlJobHandler.java index d0a3164..d7dbd5f 100644 --- a/jzo2o-market/src/main/java/com/jzo2o/market/handler/XxlJobHandler.java +++ b/jzo2o-market/src/main/java/com/jzo2o/market/handler/XxlJobHandler.java @@ -1,19 +1,27 @@ package com.jzo2o.market.handler; import com.jzo2o.common.expcetions.DBException; +import com.jzo2o.common.utils.BeanUtils; import com.jzo2o.common.utils.CollUtils; +import com.jzo2o.common.utils.JsonUtils; +import com.jzo2o.market.constants.RedisConstants; import com.jzo2o.market.enums.ActivityStatusEnum; import com.jzo2o.market.enums.CouponStatusEnum; import com.jzo2o.market.model.domain.Activity; import com.jzo2o.market.model.domain.Coupon; +import com.jzo2o.market.model.dto.response.SeizeCouponInfoResDTO; import com.jzo2o.market.service.IActivityService; import com.jzo2o.market.service.ICouponService; import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -21,6 +29,7 @@ import java.util.stream.Collectors; * XxlJob任务处理器 * @author JIAN */ +@Slf4j @Component @SuppressWarnings("unused") public class XxlJobHandler { @@ -28,6 +37,8 @@ public class XxlJobHandler { private IActivityService activityService; @Resource private ICouponService couponService; + @Resource + private RedisTemplate redisTemplate; /** * 自动修改活动状态(1分钟1次) @@ -37,6 +48,7 @@ public class XxlJobHandler { @XxlJob("updateActivityStatus") @Transactional public void updateActivityStatus() { + log.info("自动修改活动状态任务开始"); LocalDateTime nowTime = LocalDateTime.now(); List activityList = activityService.lambdaQuery() .eq(Activity::getStatus, ActivityStatusEnum.NO_DISTRIBUTE) @@ -76,6 +88,7 @@ public class XxlJobHandler { @XxlJob("processExpireCoupon") @Transactional public void processExpireCoupon() { + log.info("自动过期已领取优惠券任务开始"); List couponList = couponService.lambdaQuery() .eq(Coupon::getStatus, CouponStatusEnum.NO_USE) // 不处理还没到有效期的优惠卷 @@ -96,4 +109,36 @@ public class XxlJobHandler { throw new DBException("更新优惠卷状态失败"); } } + + /** + * 自动预热(缓存)1个月内的活动 + */ + @XxlJob("activityPreheat") + public void activityPreheat() { + log.info("自动预热1个月内的活动任务开始"); + LocalDateTime nowTime = LocalDateTime.now(); + + // 获取近一个月未开始/已开始的活动 + @SuppressWarnings("unchecked") + List activityList = activityService.lambdaQuery() + .le(Activity::getDistributeStartTime, nowTime.plusDays(30)) + .in(Activity::getStatus, Arrays.asList(ActivityStatusEnum.NO_DISTRIBUTE, ActivityStatusEnum.DISTRIBUTING)) + .orderByAsc(Activity::getDistributeStartTime) + .list(); + + if (CollUtils.isEmpty(activityList)) { + activityList = new ArrayList<>(); + } + + List couponInfoList = activityList.stream() + .map(activity -> BeanUtils + .toBean(activity, SeizeCouponInfoResDTO.class) + .setRemainNum(activity.getStockNum())) + .collect(Collectors.toList()); + String couponInfoListJsonStr = JsonUtils.toJsonStr(couponInfoList); + + redisTemplate + .opsForValue() + .set(RedisConstants.RedisKey.ACTIVITY_CACHE_LIST, couponInfoListJsonStr); + } } \ No newline at end of file diff --git a/jzo2o-market/src/main/java/com/jzo2o/market/model/dto/response/SeizeCouponInfoResDTO.java b/jzo2o-market/src/main/java/com/jzo2o/market/model/dto/response/SeizeCouponInfoResDTO.java index 5edde31..8f77064 100644 --- a/jzo2o-market/src/main/java/com/jzo2o/market/model/dto/response/SeizeCouponInfoResDTO.java +++ b/jzo2o-market/src/main/java/com/jzo2o/market/model/dto/response/SeizeCouponInfoResDTO.java @@ -1,8 +1,10 @@ package com.jzo2o.market.model.dto.response; +import com.jzo2o.market.enums.ActivityStatusEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import lombok.experimental.Accessors; import java.io.Serializable; import java.math.BigDecimal; @@ -10,6 +12,7 @@ import java.time.LocalDateTime; @Data @ApiModel("抢券列表信息") +@Accessors(chain = true) public class SeizeCouponInfoResDTO implements Serializable { @ApiModelProperty("活动id") private Long id; @@ -28,12 +31,9 @@ public class SeizeCouponInfoResDTO implements Serializable { @ApiModelProperty("发放结束时间") private LocalDateTime distributeEndTime; @ApiModelProperty("优惠券配置状态,1:待生效,2:进行中,3:已失效") - private Integer status; - @ApiModelProperty("优惠券剩余数量") - private Integer remainNum; - + private ActivityStatusEnum status; @ApiModelProperty("发放数量") private Integer totalNum; - @ApiModelProperty("库存数量") - private Integer stockNum; -} + @ApiModelProperty("优惠券剩余数量(库存数量)") + private Integer remainNum; +} \ No newline at end of file diff --git a/jzo2o-market/src/main/java/com/jzo2o/market/service/IActivityService.java b/jzo2o-market/src/main/java/com/jzo2o/market/service/IActivityService.java index 46085b7..09bc901 100644 --- a/jzo2o-market/src/main/java/com/jzo2o/market/service/IActivityService.java +++ b/jzo2o-market/src/main/java/com/jzo2o/market/service/IActivityService.java @@ -1,17 +1,20 @@ package com.jzo2o.market.service; -import com.jzo2o.common.model.PageResult; -import com.jzo2o.market.model.domain.Activity; import com.baomidou.mybatisplus.extension.service.IService; +import com.jzo2o.common.model.PageResult; +import com.jzo2o.market.enums.ActivityStatusEnum; +import com.jzo2o.market.model.domain.Activity; import com.jzo2o.market.model.dto.request.ActivityPageQueryDTO; import com.jzo2o.market.model.dto.request.ActivitySaveReqDTO; import com.jzo2o.market.model.dto.response.ActivityInfoResDTO; +import com.jzo2o.market.model.dto.response.SeizeCouponInfoResDTO; + +import java.util.List; /** *

- * 服务类 + * 服务类 *

- * * @author itcast * @since 2023-09-16 */ @@ -26,6 +29,12 @@ public interface IActivityService extends IService { */ ActivityInfoResDTO getDetailById(Long id); + /** + * 获取缓存的活动信息 + * @param status 筛选的活动状态 + */ + List getCachedActivity(ActivityStatusEnum status); + /** * 新增/插入活动信息 */ diff --git a/jzo2o-market/src/main/java/com/jzo2o/market/service/impl/ActivityServiceImpl.java b/jzo2o-market/src/main/java/com/jzo2o/market/service/impl/ActivityServiceImpl.java index 967ca00..46dd283 100644 --- a/jzo2o-market/src/main/java/com/jzo2o/market/service/impl/ActivityServiceImpl.java +++ b/jzo2o-market/src/main/java/com/jzo2o/market/service/impl/ActivityServiceImpl.java @@ -10,6 +10,9 @@ import com.jzo2o.common.expcetions.DBException; import com.jzo2o.common.expcetions.ForbiddenOperationException; import com.jzo2o.common.model.PageResult; import com.jzo2o.common.utils.BeanUtils; +import com.jzo2o.common.utils.CollUtils; +import com.jzo2o.common.utils.JsonUtils; +import com.jzo2o.market.constants.RedisConstants; import com.jzo2o.market.enums.ActivityStatusEnum; import com.jzo2o.market.enums.CouponStatusEnum; import com.jzo2o.market.enums.CouponTypeEnum; @@ -19,14 +22,19 @@ import com.jzo2o.market.model.domain.Coupon; import com.jzo2o.market.model.dto.request.ActivityPageQueryDTO; import com.jzo2o.market.model.dto.request.ActivitySaveReqDTO; import com.jzo2o.market.model.dto.response.ActivityInfoResDTO; +import com.jzo2o.market.model.dto.response.SeizeCouponInfoResDTO; import com.jzo2o.market.service.IActivityService; import com.jzo2o.market.service.ICouponService; import com.jzo2o.mysql.utils.PageUtils; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** *

@@ -39,6 +47,8 @@ import java.util.List; public class ActivityServiceImpl extends ServiceImpl implements IActivityService { @Resource private ICouponService couponService; + @Resource + private RedisTemplate redisTemplate; @Override @SuppressWarnings("unchecked") @@ -79,6 +89,29 @@ public class ActivityServiceImpl extends ServiceImpl i return activityInfoResDTO; } + @Override + public List getCachedActivity(ActivityStatusEnum status) { + List couponInfoList = JsonUtils.toList((String) redisTemplate.opsForValue() + .get(RedisConstants.RedisKey.ACTIVITY_CACHE_LIST), SeizeCouponInfoResDTO.class); + + if (CollUtils.isEmpty(couponInfoList)) { + return new ArrayList<>(); + } + + LocalDateTime nowTime = LocalDateTime.now(); + return couponInfoList.stream() + .peek(coupon -> { + // 防止缓存中的状态出错 + if (coupon.getDistributeEndTime().isBefore(nowTime)) { + coupon.setStatus(ActivityStatusEnum.LOSE_EFFICACY); + } else if (coupon.getDistributeStartTime().isBefore(nowTime)) { + coupon.setStatus(ActivityStatusEnum.DISTRIBUTING); + } + }) + .filter(coupon -> coupon.getStatus() == status) + .collect(Collectors.toList()); + } + @Override @Transactional public void saveOrUpdate(ActivitySaveReqDTO activitySaveReqDTO) {