Browse Source

promotion:code review 秒杀的代码

YunaiV 2 years ago
parent
commit
0b9ddddd18

+ 2 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityCreateReqVO.java

@@ -12,6 +12,7 @@ import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.util.List;
 
+// TODO halfninety:检查下所有的 VO,需要保证 example 都写了哈。
 @ApiModel("管理后台 - 秒杀活动创建 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -25,6 +26,7 @@ public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO {
     @NotNull(message = "排序不能为空")
     private Integer sort;
 
+    // TODO halfninety:直接使用数组接口。timeIds,
     @ApiModelProperty(value = "秒杀时段id", required = true)
     @NotBlank(message = "参与场次不能为空")
     private String timeId;

+ 3 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/SeckillTimeController.java

@@ -20,6 +20,7 @@ import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
+// TODO @halfninety:controller 可以都放在 seckill 包下;vo 下分成 actvity 和 time
 @Api(tags = "管理后台 - 秒杀时段")
 @RestController
 @RequestMapping("/promotion/seckill-time")
@@ -65,11 +66,13 @@ public class SeckillTimeController {
     @GetMapping("/list")
     @ApiOperation("获得所有秒杀时段列表")
 //    @PreAuthorize("@ss.hasPermission('promotion:seckill-time:query')")
+    // TODO @halfninety:权限为啥注释掉呀?
     public CommonResult<List<SeckillTimeRespVO>> getSeckillTimeList() {
         List<SeckillTimeDO> list = seckillTimeService.getSeckillTimeList();
         return success(SeckillTimeConvert.INSTANCE.convertList(list));
     }
 
+    // TODO @halfninety:不用的,可以删除掉
 //    @GetMapping("/page")
 //    @ApiOperation("获得秒杀时段分页")
 //    @PreAuthorize("@ss.hasPermission('promotion:seckill-time:query')")

+ 3 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java

@@ -57,8 +57,9 @@ public class SeckillActivityDO extends BaseDO {
      */
     private Integer sort;
     /**
-     * 秒杀时段id
+     * 秒杀时段 id
      */
+    // TODO @halfninety 可以使用 List 存储;看下别的模块怎么做的哈
     private String timeId;
     /**
      * 付款订单数
@@ -68,6 +69,7 @@ public class SeckillActivityDO extends BaseDO {
      * 付款人数
      */
     private Integer userCount;
+    // TODO @halfninety 使用 Long 哈。单位是分
     /**
      * 订单实付金额,单位:分
      */

+ 12 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckilltime/SeckillTimeMapper.java

@@ -1,8 +1,5 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime;
 
-import java.time.LocalTime;
-import java.util.*;
-
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
@@ -10,6 +7,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.time.LocalTime;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * 秒杀时段 Mapper
  *
@@ -17,16 +18,22 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface SeckillTimeMapper extends BaseMapperX<SeckillTimeDO> {
+
+    // @TODO halfninety:){ 之间要有空格哈
     default List<SeckillTimeDO> selectListWithTime(LocalTime time){
+        // TODO @halfninety:mapper 层,不做空判断,业务上面自己的保证
         if (time == null) {
             return Collections.emptyList();
         }
+        // TODO @halfninety:在 BaseMapperX 上,可以封装一个 2 个字段的检索哈
         return selectList(new LambdaQueryWrapper<SeckillTimeDO>()
                 .le(SeckillTimeDO::getStartTime,time)
                 .ge(SeckillTimeDO::getEndTime,time));
     }
-    
+
+    // TODO @halfninety:selectListByXXX,使用 By 作为查询条件。
     default List<SeckillTimeDO> selectListWithTime(LocalTime startTime, LocalTime endTime){
+        // TODO @halfninety:mapper 层,不做空判断,业务上面自己的保证
         if (startTime == null && endTime == null) {
             return Collections.emptyList();
         }
@@ -35,6 +42,7 @@ public interface SeckillTimeMapper extends BaseMapperX<SeckillTimeDO> {
                 .le(SeckillTimeDO::getEndTime,endTime));
     }
 
+    // TODO @halfninety:updateActivityCount + 和 -,可以执使用一个方法实现哈。多传递一个参数
     default void sekillActivityCountAdd(List<Long> ids){
         if (CollUtil.isEmpty(ids)){
             return;

+ 31 - 18
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java

@@ -31,7 +31,7 @@ import static java.util.Arrays.asList;
 /**
  * 秒杀活动 Service 实现类
  *
- * @author 芋道源码
+ * @author 芋道源码 // TODO @halfninety:作者改成你自己哈
  */
 @Service
 @Validated
@@ -39,7 +39,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
 
     @Resource
     private SeckillActivityMapper seckillActivityMapper;
-
     @Resource
     private SeckillProductMapper seckillProductMapper;
 
@@ -48,32 +47,40 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
 
     @Override
     public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
+        // TODO @halfninety:多余的变量,需要删除
         List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
         // 校验商品是否冲突
         validateSeckillActivityProductConflicts(null, createReqVO.getProducts());
-        // 更新秒杀时段的秒杀活动数量
-        seckillTimeService.sekillActivityCountAdd(StrUtils.splitToLong(createReqVO.getTimeId(),","));
+
+        // TODO halfninety:要校验下,秒杀时间段存在
         // 插入秒杀活动
         SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
                 .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
         seckillActivityMapper.insert(seckillActivity);
         // 插入商品
+        // TODO @halfninety:是不是写成一个 convertList,通过 default 来处理下;这样可读性更好哈
         List<SeckillProductDO> productDOS = CollectionUtils.convertList(createReqVO.getProducts(),
                 product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(seckillActivity.getId()));
         seckillProductMapper.insertBatch(productDOS);
+
+        // TODO halfninety:最后在更新秒杀时间段的商品数量哈。【我已经改了】一般先做核心的逻辑,在做附件的逻辑。
+        // 更新秒杀时段的秒杀活动数量
+        seckillTimeService.sekillActivityCountAdd(StrUtils.splitToLong(createReqVO.getTimeId(),","));
         return seckillActivity.getId();
     }
 
     @Override
     public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
         // 校验存在
-        SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(updateReqVO.getId());
+        SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
         if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
             throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
         }
         // 校验商品是否冲突
         validateSeckillActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
+
         // 更新秒杀时段的秒杀活动数量
+        // TODO @halfninety:可以直接传递 seckillActivity 进去,不用重复查询;
         updateSeckillTimeActivityCount(updateReqVO.getId(), updateReqVO.getTimeId());
         // 更新活动
         SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
@@ -83,6 +90,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         updateSeckillProduct(updateReqVO);
     }
 
+    // TODO @halfninety:注释写全哈;
     /**
      * 更新秒杀时段的秒杀活动数量
      *
@@ -91,16 +99,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
      */
     private void updateSeckillTimeActivityCount(Long id, String timeId) {
         List<Long> updateTimeIds = StrUtils.splitToLong(timeId, ",");
-        // 查出自己的timeIds
+        // 查出自己的 timeIds
         SeckillActivityDO seckillActivityDO = seckillActivityMapper.selectById(id);
         List<Long> existsTimeIds = StrUtils.splitToLong(seckillActivityDO.getTimeId(), ",");
-        //需要减少的时间段
+        // 需要减少的时间段
+        // TODO @halfninety:可以使用 CollUtil.filterNew()
         List<Long> reduceIds = existsTimeIds.stream()
                 .filter(existsTimeId -> !updateTimeIds.contains(existsTimeId))
                 .collect(Collectors.toList());
-        //需要添加的时间段
+        // 需要添加的时间段
+        // TODO @halfninety:IDEA 一般会有告警提示,下面可以 lambada 表达式优化下;通过 command + 回车
         updateTimeIds.removeIf(updateTimeId -> existsTimeIds.contains(updateTimeId));
-        //更新减少时间段和增加时间段
+        // 更新减少时间段和增加时间段
+        // TODO @halfninety:判断非空才操作
         seckillTimeService.sekillActivityCountAdd(updateTimeIds);
         seckillTimeService.sekillActivityCountReduce(reduceIds);
     }
@@ -111,17 +122,20 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {
         List<SeckillProductDO> seckillProductDOS = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
         List<SeckillActivityBaseVO.Product> products = updateReqVO.getProducts();
-        //对后台查出的数据和前台查出的数据进行遍历,
-        //1.对前台数据进行遍历:如果不存在于后台的sku中需要新增
-        //2.对后台数据进行遍历:如果不存在于前台的sku中需要删除
-        //计算需要删除的数据
+        // TODO halfninety:下面这段,其实可以放到注释哈
+        // 对后台查出的数据和前台查出的数据进行遍历,
+        // 1. 对前台数据进行遍历:如果不存在于后台的 sku 中需要新增
+        // 2. 对后台数据进行遍历:如果不存在于前台的 sku 中需要删除
+
+        // 计算需要删除的数据
         List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOS, SeckillProductDO::getId,
                 seckillProductDO -> products.stream()
                         .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product)));
         if (CollUtil.isNotEmpty(deleteIds)) {
             seckillProductMapper.deleteBatchIds(deleteIds);
         }
-        //计算需要新增的数据
+
+        // 计算需要新增的数据
         List<SeckillProductDO> newSeckillProductDOs = CollectionUtils.convertList(products,
                 product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId()));
         newSeckillProductDOs.removeIf(product -> seckillProductDOS.stream()
@@ -148,17 +162,16 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         }
         List<SeckillActivityDO> seckillActivityDOS = seckillActivityMapper
                 .selectBatchIds(CollectionUtils.convertSet(seckillProductDOS, SeckillProductDO::getActivityId));
-        if (id != null) {// 排除自己这个活动
+        if (id != null) { // 排除自己这个活动
             seckillActivityDOS.removeIf(item -> id.equals(item.getId()));
         }
-        // 排除不满足status的活动
+        // 排除不满足 status 的活动
         List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
         seckillActivityDOS.removeIf(item -> !statuses.contains(item.getStatus()));
-        //如果非空,则说明冲突
+        // 如果非空,则说明冲突
         if (CollUtil.isNotEmpty(seckillActivityDOS)) {
             throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
         }
-
     }
 
     @Override

+ 10 - 13
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckilltime/SeckillTimeServiceImpl.java

@@ -3,33 +3,30 @@ package cn.iocoder.yudao.module.promotion.service.seckill.seckilltime;
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.convert.seckill.seckilltime.SeckillTimeConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime.SeckillTimeMapper;
 import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
 import org.springframework.validation.annotation.Validated;
 
+import javax.annotation.Resource;
 import java.time.LocalTime;
-import java.util.*;
-
-import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
-
-import cn.iocoder.yudao.module.promotion.convert.seckill.seckilltime.SeckillTimeConvert;
-import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime.SeckillTimeMapper;
+import java.util.List;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_TIME_CONFLICTS;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_TIME_NOT_EXISTS;
 
 /**
  * 秒杀时段 Service 实现类
  *
- * @author 芋道源码
+ * @author 芋道源码     // TODO @halfninety:作者改成你自己哈
  */
 @Service
 @Validated
 public class SeckillTimeServiceImpl implements SeckillTimeService {
 
-
     @Resource
     private SeckillTimeMapper seckillTimeMapper;
 
@@ -93,7 +90,6 @@ public class SeckillTimeServiceImpl implements SeckillTimeService {
         }
     }
 
-
     @Override
     public SeckillTimeDO getSeckillTime(Long id) {
         return seckillTimeMapper.selectById(id);
@@ -104,6 +100,7 @@ public class SeckillTimeServiceImpl implements SeckillTimeService {
         return seckillTimeMapper.selectList();
     }
 
+    // TODO @halfninety:updateActivityCount + 和 -,可以执使用一个方法实现哈。多传递一个参数
     @Override
     public void sekillActivityCountAdd(List<Long> ids) {
         seckillTimeMapper.sekillActivityCountAdd(ids);

+ 1 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/seckillactivity/SeckillActivityMapper.xml

@@ -8,5 +8,6 @@
         代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
         文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
      -->
+    <!-- TODO halfninety:不用的话,可以删除掉哈。 -->
 
 </mapper>

+ 1 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/seckilltime/SeckillTimeMapper.xml

@@ -8,5 +8,6 @@
         代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
         文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
      -->
+    <!-- TODO halfninety:不用的话,可以删除掉哈。 -->
 
 </mapper>

+ 8 - 8
yudao-server/src/main/resources/application-local.yaml

@@ -30,7 +30,7 @@ spring:
             multi-statement-allow: true
     dynamic: # 多数据源配置
       druid: # Druid 【连接池】相关的全局配置
-        initial-size: 1 # 初始连接数
+        initial-size: 5 # 初始连接数
         min-idle: 10 # 最小连接池数量
         max-active: 20 # 最大连接池数量
         max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
@@ -45,40 +45,40 @@ spring:
       datasource:
         master:
           name: ruoyi-vue-pro
-          url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
+          url: jdbc:mysql://139.9.196.247:3307/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
           #          url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
           #          url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例
           #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
           #          url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例
           username: root
-          password: 123456
+          password: ${RUOYI_VUE_PRO}
         #          username: sa
         #          password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
         slave: # 模拟从库,可根据自己需要修改
           name: ruoyi-vue-pro
-          url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
+          url: jdbc:mysql://139.9.196.247:3307/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
           #          url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
           #          url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例
           #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
           #          url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.slave.name} # SQLServer 连接的示例
           username: root
-          password: 123456
+          password: ${RUOYI_VUE_PRO}
   #          username: sa
   #          password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
 
   # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
   redis:
-    host: 127.0.0.1 # 地址
+    host: 139.9.196.247 # 地址
     port: 6379 # 端口
     database: 0 # 数据库索引
-#    password: 123456 # 密码,建议生产环境开启
+    password: 123456 # 密码,建议生产环境开启
 
 --- #################### 定时任务相关配置 ####################
 
 # Quartz 配置项,对应 QuartzProperties 配置类
 spring:
   quartz:
-    auto-startup: true # 本地开发环境,尽量不要开启 Job
+    auto-startup: false # 本地开发环境,尽量不要开启 Job
     scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName
     job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。
     wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true