diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java index 1f9ea52c8..1c7244642 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java @@ -16,6 +16,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import java.text.ParseException; import java.util.List; /** @@ -38,7 +39,7 @@ public class AdvertRoundController extends XktBaseController { @ApiOperation(value = "档口购买推广营销", httpMethod = "POST", response = R.class) @Log(title = "档口购买推广营销", businessType = BusinessType.INSERT) @PostMapping - public R create(@Validated @RequestBody AdRoundStoreCreateVO createVO) { + public R create(@Validated @RequestBody AdRoundStoreCreateVO createVO) throws ParseException { return R.ok(advertRoundService.create(BeanUtil.toBean(createVO, AdRoundStoreCreateDTO.class))); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundPopularResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundPopularResVO.java index 5bdb2e06a..328a42e54 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundPopularResVO.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundPopularResVO.java @@ -1,13 +1,11 @@ package com.ruoyi.web.controller.xkt.vo.advertRound; -import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.experimental.Accessors; import java.math.BigDecimal; -import java.util.Date; /** * @author liujiang @@ -28,11 +26,9 @@ public class AdRoundPopularResVO { @ApiModelProperty(value = "推广展示类型") private Integer showType; @ApiModelProperty(value = "投放开始时间") - @JsonFormat(pattern = "MM月dd日", timezone = "GMT+8") - private Date startTime; + private String startTime; @ApiModelProperty(value = "投放结束时间") - @JsonFormat(pattern = "MM月dd日", timezone = "GMT+8") - private Date endTime; + private String endTime; @ApiModelProperty(value = "起拍价格") private BigDecimal startPrice; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java index 1af61eb33..440f5782e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java @@ -46,4 +46,15 @@ public class CacheConstants * 用户STS */ public static final String USER_STS_KEY = "user_sts:"; + + /** + * 档口 + */ + public static final String STORE_KEY = "store:"; + + /** + * 推广购买截止时间 + */ + public static final String ADVERT_DEADLINE_KEY = "advert_deadline:"; + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 8ee2da6a1..6e838372b 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -224,14 +224,9 @@ public class Constants */ public static final Long TOPMOST_PRODUCT_CATEGORY_ID = 1L; - /** - * redis store前缀 - */ - public static final String STORE_REDIS_PREFIX = "store_"; - /** * 最受欢迎的8个推广位 */ - public static final String ADVERT_POPULAR = "popular"; + public static final String ADVERT_POPULAR = "ADVERT_POPULAR"; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java index 6f405c3be..59faffc86 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java @@ -22,6 +22,8 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils public static String YYYY_MM = "yyyy-MM"; + public static String MM_DD = "MM月dd日"; + public static String YYYY_MM_DD = "yyyy-MM-dd"; public static String YYYYMMDD = "yyyyMMdd"; @@ -75,6 +77,11 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils return parseDateToStr(YYYY_MM_DD, date); } + public static final String timeMMDD(final Date date) + { + return parseDateToStr(MM_DD, date); + } + public static final String parseDateToStr(final String format, final Date date) { return new SimpleDateFormat(format).format(date); diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java index b211b8eb0..5cd0c762b 100644 --- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import co.elastic.clients.elasticsearch.core.BulkResponse; import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.domain.entity.SysProductCategory; @@ -298,7 +299,7 @@ public class XktTask { } /** - * 每晚定时任务更新推广的播放轮次,这个要次日凌晨更新 + * 定时任务更新推广的播放轮次,这个要次日凌晨更新 凌晨12:01:00分更新 */ @Transactional public void dailyAdvertRound() throws ParseException { @@ -438,7 +439,7 @@ public class XktTask { * 比如:5.1 - 5.3 * a. 现在是4.30 则截止时间是 4.30 22:00 * b. 现在是5.2,则截止时间是 5.2 22:00:00 。 - * c. 现在是5.3,则第一轮还有请求,肯定是人为的不用管。请求第三轮 或者 第四轮 不报错。只处理第二轮请求 + * c. 现在是5.3,则第一轮还有请求,肯定是人为的不用管。每一轮都要放到redis中 * * @throws ParseException */ @@ -457,7 +458,7 @@ public class XktTask { return; } storeList.forEach(store -> { - redisCache.setCacheObject(Constants.STORE_REDIS_PREFIX + store.getId(), store.getId(), 1, TimeUnit.DAYS); + redisCache.setCacheObject(CacheConstants.STORE_KEY + store.getId(), store.getId(), 1, TimeUnit.DAYS); }); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundPopularResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundPopularResDTO.java index 0a68e0d86..7f1611578 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundPopularResDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundPopularResDTO.java @@ -1,5 +1,6 @@ package com.ruoyi.xkt.dto.advertRound; +import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -27,9 +28,9 @@ public class AdRoundPopularResDTO { @ApiModelProperty(value = "推广展示类型") private Integer showType; @ApiModelProperty(value = "投放开始时间") - private Date startTime; + private String startTime; @ApiModelProperty(value = "投放结束时间") - private Date endTime; + private String endTime; @ApiModelProperty(value = "起拍价格") private BigDecimal startPrice; diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java index 356b57627..b6b762bbb 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java @@ -30,7 +30,7 @@ public interface IAdvertRoundService { * @param createDTO 购买入参 * @return Integer */ - Integer create(AdRoundStoreCreateDTO createDTO); + Integer create(AdRoundStoreCreateDTO createDTO) throws ParseException; /** * 初始化每天购买广告的截止时间 diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java index e7e31718d..f9f9dba97 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.page.Page; @@ -40,6 +41,7 @@ import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; +import static com.ruoyi.common.constant.CacheConstants.ADVERT_DEADLINE_KEY; import static com.ruoyi.common.constant.Constants.ADVERT_POPULAR; /** @@ -329,12 +331,12 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { */ @Override @Transactional - public Integer create(AdRoundStoreCreateDTO createDTO) { + public Integer create(AdRoundStoreCreateDTO createDTO) throws ParseException { // 截止时间都是当天 22:00:00,并且只会处理马上播放的这一轮。比如 5.1-5.3,当前为4.30,处理这一轮;当前为5.2,处理这一轮;当前为5.3(最后一天),处理下一轮。 if (DateUtils.getTime().compareTo(this.getDeadline(createDTO.getSymbol())) > 0) { throw new ServiceException("竞价失败,已经有档口出价更高了噢!", HttpStatus.ERROR); } - if (ObjectUtils.isEmpty(redisCache.getCacheObject(Constants.STORE_REDIS_PREFIX + createDTO.getStoreId()))) { + if (ObjectUtils.isEmpty(redisCache.getCacheObject(CacheConstants.STORE_KEY + createDTO.getStoreId()))) { throw new ServiceException("档口不存在!", HttpStatus.ERROR); } // 如果是位置枚举的推广位,则需要传position @@ -468,7 +470,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { // 判断当前时间距离开播是否小于72h,若是:则不可取消 Date threeDaysAfter = DateUtils.toDate(LocalDateTime.now().plusDays(3)); if (threeDaysAfter.after(advertRound.getStartTime())) { - throw new ServiceException("距推广开播小于72小时,不可退订!"); + throw new ServiceException("距推广开播小于72小时,不可退订噢!"); } // 将费用退回到档口余额中 assetService.refundAdvertFee(advertRound.getStoreId(), advertRound.getPayPrice()); @@ -503,8 +505,8 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { .groupingBy(AdvertRound::getAdvertId, Collectors.minBy(Comparator.comparing(AdvertRound::getRoundId)))); // 将minRoundIdMap中的值转换为List List list = minRoundIdMap.values().stream().map(Optional::get).map(x -> new AdRoundPopularResDTO().setAdvertId(x.getAdvertId()) - .setTypeId(x.getTypeId()).setTypeName(AdType.of(x.getTypeId()).getLabel()).setShowType(x.getShowType()).setStartTime(x.getStartTime()) - .setEndTime(x.getEndTime()).setStartPrice(x.getStartPrice())) + .setTypeId(x.getTypeId()).setTypeName(AdType.of(x.getTypeId()).getLabel()).setShowType(x.getShowType()) + .setStartTime(DateUtils.timeMMDD(x.getStartTime())).setEndTime(DateUtils.timeMMDD(x.getEndTime())).setStartPrice(x.getStartPrice())) .collect(Collectors.toList()); // 存到redis中 redisCache.setCacheObject(ADVERT_POPULAR, list, 1, TimeUnit.DAYS); @@ -581,37 +583,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { } /** - * 获取已抢购推广位列表 - * - * @param storeId 档口ID - * @param advertRoundList 播放轮次列表 - * @param recordList 未购买的播放轮次列表 - * @return List - */ - private List getStoreBoughtList(Long storeId, List advertRoundList, List recordList) { - // 每一轮最高的出价map - Map maxBidMap = advertRoundList.stream().filter(x -> ObjectUtils.isNotEmpty(x.getPayPrice())).collect(Collectors - .groupingBy(AdvertRound::getRoundId, Collectors - .mapping(AdvertRound::getPayPrice, Collectors.reducing(BigDecimal.ZERO, BigDecimal::max)))); - // 先处理 已抢购广告位列表,此处不用管 播放的轮次 统一展示前4轮的结果 - List boughtRoundList = advertRoundList.stream().filter(x -> Objects.equals(x.getStoreId(), storeId)) - .map(x -> BeanUtil.toBean(x, AdRoundStoreResDTO.ADRSRoundRecordDTO.class).setTypeName(Objects.requireNonNull(AdType.of(x.getTypeId())).getLabel()) - .setBiddingStatusName(Objects.requireNonNull(AdBiddingStatus.of(x.getBiddingStatus())).getLabel())) - .collect(Collectors.toList()); - // 查询其它轮次是否有购买记录 - if (CollectionUtils.isEmpty(recordList)) { - return boughtRoundList; - } - boughtRoundList.addAll(recordList.stream().sorted(Comparator.comparing(AdvertRoundRecord::getBiddingStatus)) - .map(x -> BeanUtil.toBean(x, AdRoundStoreResDTO.ADRSRoundRecordDTO.class).setTypeName(Objects.requireNonNull(AdType.of(x.getTypeId())).getLabel()) - .setBiddingStatusName(Objects.requireNonNull(AdBiddingStatus.of(x.getBiddingStatus())).getLabel() + ",最新出价:" + maxBidMap.get(x.getRoundId()))) - .collect(Collectors.toList())); - return boughtRoundList; - } - - - /** - * 通过定时任务往redis中放当前推广位 当前播放轮 或 即将播放轮 的截止时间; + * 通过定时任务往redis中放当前推广位 当前播放轮 或 即将播放轮 的截止时间;每晚12:05:00执行 * 比如:5.1 - 5.3 * a. 现在是4.30 则截止时间是 4.30 22:00 * b. 现在是5.2,则截止时间是 5.2 22:00:00 。 @@ -645,7 +617,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { AdvertRound firstRound = roundList.stream().filter(x -> Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue())) .max(Comparator.comparing(AdvertRound::getEndTime)) .orElseThrow(() -> new ServiceException("获取推广结束时间失败,请联系客服!", HttpStatus.ERROR)); - redisCache.setCacheObject(firstRound.getSymbol(), filterTime, 1, TimeUnit.DAYS); + redisCache.setCacheObject(ADVERT_DEADLINE_KEY + firstRound.getSymbol(), filterTime, 1, TimeUnit.DAYS); // 第二轮之后的轮次过期时间都为开始时间前一天 Map roundSymbolMap = roundList.stream().filter(x -> !Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue())) .collect(Collectors.toMap(AdvertRound::getSymbol, AdvertRound::getStartTime, (s1, s2) -> s2)); @@ -653,7 +625,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { roundSymbolMap.forEach((symbol, startTime) -> { // 推广开始时间的前一天的 22:00:00 LocalDateTime futureTimeFilter = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusDays(1).withHour(22).withMinute(0).withSecond(0); - redisCache.setCacheObject(symbol, futureTimeFilter, 1, TimeUnit.DAYS); + redisCache.setCacheObject(ADVERT_DEADLINE_KEY + symbol, futureTimeFilter, 1, TimeUnit.DAYS); }); } } @@ -666,7 +638,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { roundSymbolMap.forEach((symbol, startTime) -> { // 推广开始时间的前一天的 22:00:00 LocalDateTime futureTimeFilter = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusDays(1).withHour(22).withMinute(0).withSecond(0); - redisCache.setCacheObject(symbol, futureTimeFilter, 1, TimeUnit.DAYS); + redisCache.setCacheObject(ADVERT_DEADLINE_KEY + symbol, futureTimeFilter, 1, TimeUnit.DAYS); }); } List otherRoundList = roundList.stream().filter(x -> !Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue()) @@ -676,7 +648,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { otherRoundSymbolMap.forEach((symbol, startTime) -> { // 推广开始时间的前一天的 22:00:00 LocalDateTime futureTimeFilter = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusDays(1).withHour(22).withMinute(0).withSecond(0); - redisCache.setCacheObject(symbol, futureTimeFilter, 1, TimeUnit.DAYS); + redisCache.setCacheObject(ADVERT_DEADLINE_KEY + symbol, futureTimeFilter, 1, TimeUnit.DAYS); }); } } @@ -685,11 +657,11 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { if (now.equals(firstRoundEndTime)) { // 将位置枚举的每一个symbol都存放到redis中 roundList.stream().filter(x -> !Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue())) - .forEach(x -> redisCache.setCacheObject(x.getSymbol(), filterTime, 1, TimeUnit.DAYS)); + .forEach(x -> redisCache.setCacheObject(ADVERT_DEADLINE_KEY + x.getSymbol(), filterTime, 1, TimeUnit.DAYS)); } else { // 将位置枚举的每一个symbol都存放到redis中 roundList.stream().filter(x -> Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue())) - .forEach(x -> redisCache.setCacheObject(x.getSymbol(), filterTime, 1, TimeUnit.DAYS)); + .forEach(x -> redisCache.setCacheObject(ADVERT_DEADLINE_KEY + x.getSymbol(), filterTime, 1, TimeUnit.DAYS)); } } }); @@ -697,14 +669,23 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { /** - * 获取当前推广轮次的过期时间 + * 获取当前推广轮次的过期时间 每一个轮次都有过期时间, * * @param symbol 符号 * @return */ - private String getDeadline(String symbol) { - final String deadline = redisCache.getCacheObject(symbol); - return StringUtils.isNotBlank(deadline) ? deadline : ""; + private String getDeadline(String symbol) throws ParseException { + String deadline = redisCache.getCacheObject(ADVERT_DEADLINE_KEY + symbol); + if (StringUtils.isNotBlank(deadline)) { + return deadline; + } + // 重新存到redis中 + this.saveAdvertDeadlineToRedis(); + deadline = redisCache.getCacheObject(ADVERT_DEADLINE_KEY + symbol); + if (StringUtils.isEmpty(deadline)) { + throw new ServiceException("获取推广轮次过期时间失败!请联系客服", HttpStatus.ERROR); + } + return deadline; } /** diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java index b1596477c..591f5bd6b 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.page.Page; @@ -75,7 +76,7 @@ public class StoreServiceImpl implements IStoreService { // 创建档口账户 assetService.createInternalAccountIfNotExists(store.getId()); // 放到redis中 - redisCache.setCacheObject(Constants.STORE_REDIS_PREFIX + store.getId(), store.getId()); + redisCache.setCacheObject(CacheConstants.STORE_KEY + store.getId(), store.getId()); return count; } diff --git a/xkt/src/main/resources/mapper/AdvertRoundMapper.xml b/xkt/src/main/resources/mapper/AdvertRoundMapper.xml index b3c35c78c..bfe3f58f5 100644 --- a/xkt/src/main/resources/mapper/AdvertRoundMapper.xml +++ b/xkt/src/main/resources/mapper/AdvertRoundMapper.xml @@ -60,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and ar.start_time >= #{startTime} and ar.end_time <= #{endTime} ORDER BY - ar.start_time DESC + ar.start_time @@ -95,7 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and ar.round_id = #{roundId} and ar.sys_intercept = #{sysIntercept} ORDER BY - ar.start_time DESC + ar.start_time