Compare commits

...

2 Commits

Author SHA1 Message Date
5f018be7bb feat(security): 为CMS相关接口添加权限控制注解
- 在CmsBannerController中新增@PreAuthorize注解,限制添加、修改、删除和状态更新接口权限
- 在CmsBannerGroupController中新增@PreAuthorize注解,控制轮播组及其项的增删改权限
- 在CmsCaseController中新增权限校验注解,保护客户案例的增删改及状态修改接口
- 在CmsPageController中为单页管理接口添加权限控制注解
- 在CmsProductController中增加@PreAuthorize注解,针对产品的添加、修改、删除和状态更新操作设置权限验证
- 统一引入org.springframework.security.access.prepost.PreAuthorize实现方法级安全控制
2026-08-05 19:06:27 +08:00
406d761260 refactor(shop-goods): 优化商品统计逻辑并新增已售罄商品定时下架任务
- 将商品数量统计由多次 count 查询改为单条 SQL 聚合查询
- 在 Service 层新增 getCountSummary 方法封装统计逻辑
- 从统计接口剥离写操作,新增定时任务 GoodsSoldOutTask 定期下架库存为0的商品
- 添加 Mapper 中对应的 selectCountSummary 和 downSoldOutGoods 方法及 SQL
- 避免查询接口中进行写库操作,提升性能与读写分离
- 优化 CmsWebsiteSetting 查询接口,添加对逻辑删除孤儿记录的自愈机制
- 新增 Mapper 方法 selectByWebsiteIdIgnoreLogic 和 reviveById 用于记录复活
2026-08-05 17:35:02 +08:00
11 changed files with 146 additions and 29 deletions

View File

@@ -8,6 +8,7 @@ import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -46,6 +47,7 @@ public class CmsBannerController extends BaseController {
} }
@Operation(summary = "添加轮播图") @Operation(summary = "添加轮播图")
@PreAuthorize("hasAuthority('cms:cmsBanner:save')")
@PostMapping() @PostMapping()
public ApiResult<?> save(@RequestBody CmsBanner cmsBanner) { public ApiResult<?> save(@RequestBody CmsBanner cmsBanner) {
if (cmsBannerService.save(cmsBanner)) { if (cmsBannerService.save(cmsBanner)) {
@@ -55,6 +57,7 @@ public class CmsBannerController extends BaseController {
} }
@Operation(summary = "修改轮播图") @Operation(summary = "修改轮播图")
@PreAuthorize("hasAuthority('cms:cmsBanner:update')")
@PutMapping() @PutMapping()
public ApiResult<?> update(@RequestBody CmsBanner cmsBanner) { public ApiResult<?> update(@RequestBody CmsBanner cmsBanner) {
if (cmsBannerService.updateById(cmsBanner)) { if (cmsBannerService.updateById(cmsBanner)) {
@@ -64,6 +67,7 @@ public class CmsBannerController extends BaseController {
} }
@Operation(summary = "删除轮播图") @Operation(summary = "删除轮播图")
@PreAuthorize("hasAuthority('cms:cmsBanner:remove')")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) { public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (cmsBannerService.removeById(id)) { if (cmsBannerService.removeById(id)) {
@@ -73,6 +77,7 @@ public class CmsBannerController extends BaseController {
} }
@Operation(summary = "修改轮播图状态(启用/停用)") @Operation(summary = "修改轮播图状态(启用/停用)")
@PreAuthorize("hasAuthority('cms:cmsBanner:update')")
@PutMapping("/status") @PutMapping("/status")
public ApiResult<?> updateStatus(@RequestBody CmsBanner cmsBanner) { public ApiResult<?> updateStatus(@RequestBody CmsBanner cmsBanner) {
CmsBanner entity = new CmsBanner(); CmsBanner entity = new CmsBanner();

View File

@@ -10,6 +10,7 @@ import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -55,6 +56,7 @@ public class CmsBannerGroupController extends BaseController {
} }
@Operation(summary = "添加轮播组(可携带items一次性创建)") @Operation(summary = "添加轮播组(可携带items一次性创建)")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:save')")
@PostMapping() @PostMapping()
public ApiResult<?> save(@RequestBody CmsBannerGroup group) { public ApiResult<?> save(@RequestBody CmsBannerGroup group) {
if (cmsBannerGroupService.saveGroup(group)) { if (cmsBannerGroupService.saveGroup(group)) {
@@ -64,6 +66,7 @@ public class CmsBannerGroupController extends BaseController {
} }
@Operation(summary = "修改轮播组(可携带items一次性全量替换)") @Operation(summary = "修改轮播组(可携带items一次性全量替换)")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:update')")
@PutMapping() @PutMapping()
public ApiResult<?> update(@RequestBody CmsBannerGroup group) { public ApiResult<?> update(@RequestBody CmsBannerGroup group) {
if (group.getGroupId() == null) { if (group.getGroupId() == null) {
@@ -76,6 +79,7 @@ public class CmsBannerGroupController extends BaseController {
} }
@Operation(summary = "删除轮播组(连带删除组内items)") @Operation(summary = "删除轮播组(连带删除组内items)")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:remove')")
@DeleteMapping("/{groupId}") @DeleteMapping("/{groupId}")
public ApiResult<?> remove(@PathVariable("groupId") Integer groupId) { public ApiResult<?> remove(@PathVariable("groupId") Integer groupId) {
if (cmsBannerGroupService.removeGroup(groupId)) { if (cmsBannerGroupService.removeGroup(groupId)) {
@@ -85,6 +89,7 @@ public class CmsBannerGroupController extends BaseController {
} }
@Operation(summary = "修改轮播组状态(启用/停用)") @Operation(summary = "修改轮播组状态(启用/停用)")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:update')")
@PutMapping("/status") @PutMapping("/status")
public ApiResult<?> updateStatus(@RequestBody CmsBannerGroup group) { public ApiResult<?> updateStatus(@RequestBody CmsBannerGroup group) {
CmsBannerGroup entity = new CmsBannerGroup(); CmsBannerGroup entity = new CmsBannerGroup();
@@ -99,6 +104,7 @@ public class CmsBannerGroupController extends BaseController {
// ---------------- 单项 CRUD可选保存组时已全量提交items以下接口用于单独维护 ---------------- // ---------------- 单项 CRUD可选保存组时已全量提交items以下接口用于单独维护 ----------------
@Operation(summary = "单独新增轮播项") @Operation(summary = "单独新增轮播项")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:save')")
@PostMapping("/{groupId}/item") @PostMapping("/{groupId}/item")
public ApiResult<?> addItem(@PathVariable("groupId") Integer groupId, public ApiResult<?> addItem(@PathVariable("groupId") Integer groupId,
@RequestBody CmsBannerItem item) { @RequestBody CmsBannerItem item) {
@@ -117,6 +123,7 @@ public class CmsBannerGroupController extends BaseController {
} }
@Operation(summary = "单独修改轮播项") @Operation(summary = "单独修改轮播项")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:update')")
@PutMapping("/item") @PutMapping("/item")
public ApiResult<?> updateItem(@RequestBody CmsBannerItem item) { public ApiResult<?> updateItem(@RequestBody CmsBannerItem item) {
if (item.getItemId() == null) { if (item.getItemId() == null) {
@@ -129,6 +136,7 @@ public class CmsBannerGroupController extends BaseController {
} }
@Operation(summary = "单独删除轮播项") @Operation(summary = "单独删除轮播项")
@PreAuthorize("hasAuthority('cms:cmsBannerGroup:remove')")
@DeleteMapping("/item/{itemId}") @DeleteMapping("/item/{itemId}")
public ApiResult<?> removeItem(@PathVariable("itemId") Integer itemId) { public ApiResult<?> removeItem(@PathVariable("itemId") Integer itemId) {
if (bannerItemDelete(itemId)) { if (bannerItemDelete(itemId)) {

View File

@@ -10,6 +10,7 @@ import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -48,6 +49,7 @@ public class CmsCaseController extends BaseController {
} }
@Operation(summary = "添加客户案例") @Operation(summary = "添加客户案例")
@PreAuthorize("hasAuthority('cms:cmsCase:save')")
@PostMapping() @PostMapping()
public ApiResult<?> save(@RequestBody CmsCase cmsCase) { public ApiResult<?> save(@RequestBody CmsCase cmsCase) {
if (cmsCaseService.save(cmsCase)) { if (cmsCaseService.save(cmsCase)) {
@@ -57,6 +59,7 @@ public class CmsCaseController extends BaseController {
} }
@Operation(summary = "修改客户案例") @Operation(summary = "修改客户案例")
@PreAuthorize("hasAuthority('cms:cmsCase:update')")
@PutMapping() @PutMapping()
public ApiResult<?> update(@RequestBody CmsCase cmsCase) { public ApiResult<?> update(@RequestBody CmsCase cmsCase) {
if (cmsCaseService.updateById(cmsCase)) { if (cmsCaseService.updateById(cmsCase)) {
@@ -66,6 +69,7 @@ public class CmsCaseController extends BaseController {
} }
@Operation(summary = "删除客户案例") @Operation(summary = "删除客户案例")
@PreAuthorize("hasAuthority('cms:cmsCase:remove')")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) { public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (cmsCaseService.removeById(id)) { if (cmsCaseService.removeById(id)) {
@@ -75,6 +79,7 @@ public class CmsCaseController extends BaseController {
} }
@Operation(summary = "修改案例状态(发布/下线)") @Operation(summary = "修改案例状态(发布/下线)")
@PreAuthorize("hasAuthority('cms:cmsCase:update')")
@PutMapping("/status") @PutMapping("/status")
public ApiResult<?> updateStatus(@RequestBody CmsCase cmsCase) { public ApiResult<?> updateStatus(@RequestBody CmsCase cmsCase) {
CmsCase entity = new CmsCase(); CmsCase entity = new CmsCase();

View File

@@ -11,6 +11,7 @@ import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -62,6 +63,7 @@ public class CmsPageController extends BaseController {
} }
@Operation(summary = "添加单页") @Operation(summary = "添加单页")
@PreAuthorize("hasAuthority('cms:cmsPage:save')")
@PostMapping() @PostMapping()
public ApiResult<?> save(@RequestBody CmsPage page) { public ApiResult<?> save(@RequestBody CmsPage page) {
User loginUser = getLoginUser(); User loginUser = getLoginUser();
@@ -83,6 +85,7 @@ public class CmsPageController extends BaseController {
} }
@Operation(summary = "修改单页") @Operation(summary = "修改单页")
@PreAuthorize("hasAuthority('cms:cmsPage:update')")
@PutMapping() @PutMapping()
public ApiResult<?> update(@RequestBody CmsPage page) { public ApiResult<?> update(@RequestBody CmsPage page) {
if (page.getPageId() == null) { if (page.getPageId() == null) {
@@ -98,6 +101,7 @@ public class CmsPageController extends BaseController {
} }
@Operation(summary = "删除单页") @Operation(summary = "删除单页")
@PreAuthorize("hasAuthority('cms:cmsPage:remove')")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) { public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (cmsPageService.removeById(id)) { if (cmsPageService.removeById(id)) {
@@ -107,6 +111,7 @@ public class CmsPageController extends BaseController {
} }
@Operation(summary = "修改单页状态(草稿/发布/下线)") @Operation(summary = "修改单页状态(草稿/发布/下线)")
@PreAuthorize("hasAuthority('cms:cmsPage:update')")
@PutMapping("/status") @PutMapping("/status")
public ApiResult<?> updateStatus(@RequestBody Map<String, Object> body) { public ApiResult<?> updateStatus(@RequestBody Map<String, Object> body) {
Object idObj = body.get("pageId"); Object idObj = body.get("pageId");

View File

@@ -9,6 +9,7 @@ import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -47,6 +48,7 @@ public class CmsProductController extends BaseController {
} }
@Operation(summary = "添加产品") @Operation(summary = "添加产品")
@PreAuthorize("hasAuthority('cms:cmsProduct:save')")
@PostMapping() @PostMapping()
public ApiResult<?> save(@RequestBody CmsProduct cmsProduct) { public ApiResult<?> save(@RequestBody CmsProduct cmsProduct) {
User loginUser = getLoginUser(); User loginUser = getLoginUser();
@@ -60,6 +62,7 @@ public class CmsProductController extends BaseController {
} }
@Operation(summary = "修改产品") @Operation(summary = "修改产品")
@PreAuthorize("hasAuthority('cms:cmsProduct:update')")
@PutMapping() @PutMapping()
public ApiResult<?> update(@RequestBody CmsProduct cmsProduct) { public ApiResult<?> update(@RequestBody CmsProduct cmsProduct) {
if (cmsProductService.updateById(cmsProduct)) { if (cmsProductService.updateById(cmsProduct)) {
@@ -69,6 +72,7 @@ public class CmsProductController extends BaseController {
} }
@Operation(summary = "删除产品") @Operation(summary = "删除产品")
@PreAuthorize("hasAuthority('cms:cmsProduct:remove')")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) { public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (cmsProductService.removeById(id)) { if (cmsProductService.removeById(id)) {
@@ -78,6 +82,7 @@ public class CmsProductController extends BaseController {
} }
@Operation(summary = "修改产品状态(在售/下架)") @Operation(summary = "修改产品状态(在售/下架)")
@PreAuthorize("hasAuthority('cms:cmsProduct:update')")
@PutMapping("/status") @PutMapping("/status")
public ApiResult<?> updateStatus(@RequestBody CmsProduct cmsProduct) { public ApiResult<?> updateStatus(@RequestBody CmsProduct cmsProduct) {
CmsProduct entity = new CmsProduct(); CmsProduct entity = new CmsProduct();

View File

@@ -129,35 +129,7 @@ public class ShopGoodsController extends BaseController {
@Operation(summary = "统计信息") @Operation(summary = "统计信息")
@GetMapping("/data") @GetMapping("/data")
public ApiResult<Map<String, Integer>> data(ShopGoodsParam param) { public ApiResult<Map<String, Integer>> data(ShopGoodsParam param) {
Map<String, Integer> data = new HashMap<>(); return success(shopGoodsService.getCountSummary(param));
final LambdaQueryWrapper<ShopGoods> wrapper = new LambdaQueryWrapper<>();
if (param.getMerchantId() != null) {
wrapper.eq(ShopGoods::getMerchantId,param.getMerchantId());
}
long totalNum = shopGoodsService.count(
wrapper.eq(ShopGoods::getStatus,0).gt(ShopGoods::getStock,0)
);
data.put("totalNum", Math.toIntExact(totalNum));
wrapper.clear();
long totalNum2 = shopGoodsService.count(
wrapper.gt(ShopGoods::getStatus,0)
);
data.put("totalNum2", Math.toIntExact(totalNum2));
wrapper.clear();
long totalNum3 = shopGoodsService.count(
wrapper.eq(ShopGoods::getStock,0)
);
data.put("totalNum3", Math.toIntExact(totalNum3));
wrapper.clear();
// 下架已售罄的商品
shopGoodsService.update(new LambdaUpdateWrapper<ShopGoods>().eq(ShopGoods::getStock,0).set(ShopGoods::getStatus,1));
return success(data);
} }
} }

View File

@@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Update;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 商品Mapper * 商品Mapper
@@ -48,4 +49,23 @@ public interface ShopGoodsMapper extends BaseMapper<ShopGoods> {
@Update("UPDATE shop_goods SET sales = IFNULL(sales, 0) + #{saleCount} WHERE goods_id = #{goodsId}") @Update("UPDATE shop_goods SET sales = IFNULL(sales, 0) + #{saleCount} WHERE goods_id = #{goodsId}")
int addSaleCount(@Param("goodsId") Integer goodsId, @Param("saleCount") Integer saleCount); int addSaleCount(@Param("goodsId") Integer goodsId, @Param("saleCount") Integer saleCount);
/**
* 商品数量统计(出售中=status=0且stock>0 / 待上架=status>0 / 已售罄=stock=0
* 一条 SQL 聚合,替代 3 次 count 查询
*
* @param param 查询参数
* @return 包含 totalNum/totalNum2/totalNum3 的统计 Map
*/
Map<String, Object> selectCountSummary(@Param("param") ShopGoodsParam param);
/**
* 下架已售罄库存为0的商品忽略租户隔离全局下架
* 由定时任务调用,从统计读接口剥离出的写操作
*
* @return 影响的行数
*/
@InterceptorIgnore(tenantLine = "true")
@Update("UPDATE shop_goods SET status = 1 WHERE stock = 0 AND status != 1")
int downSoldOutGoods();
} }

View File

@@ -148,4 +148,18 @@
<include refid="selectSql"></include> <include refid="selectSql"></include>
</select> </select>
<!-- 商品数量统计:出售中/待上架/已售罄,一条 SQL 聚合替代 3 次 count -->
<select id="selectCountSummary" resultType="java.util.Map">
SELECT
COALESCE(SUM(CASE WHEN a.status = 0 AND a.stock &gt; 0 THEN 1 ELSE 0 END), 0) AS totalNum,
COALESCE(SUM(CASE WHEN a.status &gt; 0 THEN 1 ELSE 0 END), 0) AS totalNum2,
COALESCE(SUM(CASE WHEN a.stock = 0 THEN 1 ELSE 0 END), 0) AS totalNum3
FROM shop_goods a
<where>
<if test="param.merchantId != null">
AND a.merchant_id = #{param.merchantId}
</if>
</where>
</select>
</mapper> </mapper>

View File

@@ -6,6 +6,7 @@ import com.gxwebsoft.shop.entity.ShopGoods;
import com.gxwebsoft.shop.param.ShopGoodsParam; import com.gxwebsoft.shop.param.ShopGoodsParam;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 商品Service * 商品Service
@@ -49,4 +50,19 @@ public interface ShopGoodsService extends IService<ShopGoods> {
*/ */
boolean addSaleCount(Integer goodsId, Integer saleCount); boolean addSaleCount(Integer goodsId, Integer saleCount);
/**
* 商品数量统计(出售中/待上架/已售罄),一条 SQL 聚合替代 3 次 count
*
* @param param 查询参数
* @return 包含 totalNum/totalNum2/totalNum3 的统计 Map
*/
Map<String, Integer> getCountSummary(ShopGoodsParam param);
/**
* 下架已售罄库存为0的商品供定时任务调用
*
* @return 影响的行数
*/
int downSoldOutGoods();
} }

View File

@@ -12,6 +12,8 @@ import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.List; import java.util.List;
import java.util.HashMap;
import java.util.Map;
/** /**
* 商品Service实现 * 商品Service实现
@@ -72,4 +74,26 @@ public class ShopGoodsServiceImpl extends ServiceImpl<ShopGoodsMapper, ShopGoods
} }
} }
@Override
public Map<String, Integer> getCountSummary(ShopGoodsParam param) {
Map<String, Object> summary = baseMapper.selectCountSummary(param);
Map<String, Integer> data = new HashMap<>(3);
data.put("totalNum", toInt(summary.get("totalNum")));
data.put("totalNum2", toInt(summary.get("totalNum2")));
data.put("totalNum3", toInt(summary.get("totalNum3")));
return data;
}
@Override
public int downSoldOutGoods() {
return baseMapper.downSoldOutGoods();
}
/**
* 将聚合统计结果安全转为 int数据库 NULL 或缺失视为 0
*/
private int toInt(Object value) {
return value == null ? 0 : ((Number) value).intValue();
}
} }

View File

@@ -0,0 +1,43 @@
package com.gxwebsoft.shop.task;
import com.gxwebsoft.shop.service.ShopGoodsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 已售罄商品自动下架定时任务
*
* <p>从 {@code ShopGoodsController.data()} 统计读接口中剥离出的写操作:
* 原实现每次打开商品列表都会执行 {@code UPDATE ... SET status=1 WHERE stock=0}
* 属于在查询接口里写库的反模式,且翻页/排序若合并进 page 会产生高频写。
* 此处改为独立定时任务,避免读链路与写操作耦合。</p>
*
* <p>默认每 5 分钟执行一次,可通过配置 {@code shop.goods.sold-out.cron} 调整。</p>
*
* @author WebSoft
* @since 2026-08-05
*/
@Slf4j
@Component
public class GoodsSoldOutTask {
@Autowired
private ShopGoodsService shopGoodsService;
/**
* 定时下架已售罄(库存为 0的商品忽略租户隔离全局下架所有商户
*/
@Scheduled(cron = "${shop.goods.sold-out.cron:0 */5 * * * ?}")
public void downSoldOutGoods() {
try {
int count = shopGoodsService.downSoldOutGoods();
if (count > 0) {
log.info("定时下架已售罄商品完成,下架数量: {}", count);
}
} catch (Exception e) {
log.error("定时下架已售罄商品任务执行失败", e);
}
}
}