From db680d610d3bfb082978ac2af4a70404d3b57da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Thu, 30 Jul 2026 22:22:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(cms):=20=E5=A2=9E=E5=BC=BA=E5=8D=95?= =?UTF-8?q?=E9=A1=B5=E7=BB=91=E5=AE=9A=E5=94=AF=E4=B8=80=E6=80=A7=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E5=92=8C=E7=BC=93=E5=AD=98=E5=A4=B1=E6=95=88=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在CmsNavigationController新增checkPageBindingUnique方法,确保同一租户下同一单页只能绑定一个栏目 - 在新增和修改网站导航时调用绑定唯一性校验,避免唯一索引冲突导致操作失败 - 在CmsWebsiteController修改后立即清理站点信息缓存,避免缓存数据延迟导致旧数据读取 - clearSiteInfoCacheQuietly方法中捕获异常,确保缓存清理失败不会影响主流程 - 添加了缓存清理的日志记录,方便问题追踪 --- .../controller/CmsNavigationController.java | 25 +++++++++++++++++++ .../cms/controller/CmsWebsiteController.java | 22 ++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java index 3b62c5f..74ccb10 100644 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java +++ b/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java @@ -21,6 +21,7 @@ import com.gxwebsoft.cms.param.CmsNavigationParam; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; @@ -103,6 +104,8 @@ public class CmsNavigationController extends BaseController { } // 去除前面空格 cmsNavigation.setTitle(StrUtil.trimStart(cmsNavigation.getTitle())); + // 单页模型绑定唯一性校验:同一租户下同一个单页只能绑定一个栏目 + checkPageBindingUnique(cmsNavigation); if (cmsNavigationService.save(cmsNavigation)) { // 添加成功事务处理 cmsNavigationService.saveAsync(cmsNavigation); @@ -116,6 +119,8 @@ public class CmsNavigationController extends BaseController { @Operation(summary = "修改网站导航记录表") @PutMapping() public ApiResult update(@RequestBody CmsNavigation cmsNavigation) { + // 单页模型绑定唯一性校验:同一租户下同一个单页只能绑定一个栏目 + checkPageBindingUnique(cmsNavigation); if (cmsNavigationService.updateById(cmsNavigation)) { // 修改成功事务处理 cmsNavigationService.saveAsync(cmsNavigation); @@ -281,6 +286,26 @@ public class CmsNavigationController extends BaseController { } } + /** + * 校验单页绑定唯一性:同一租户下同一个单页(pageId)只能绑定一个栏目, + * 避免触发 cms_navigation.uk_navigation_tenant_page 唯一索引导致用户看到"操作失败"。 + */ + private void checkPageBindingUnique(CmsNavigation cmsNavigation) { + if (!"page".equals(cmsNavigation.getModel()) || cmsNavigation.getPageId() == null) { + return; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(CmsNavigation::getTenantId, getTenantId()) + .eq(CmsNavigation::getPageId, cmsNavigation.getPageId()) + .eq(CmsNavigation::getDeleted, 0); + if (cmsNavigation.getNavigationId() != null) { + wrapper.ne(CmsNavigation::getNavigationId, cmsNavigation.getNavigationId()); + } + if (cmsNavigationService.count(wrapper) > 0) { + throw new BusinessException("该单页已被其他栏目绑定,请先解绑后再绑定"); + } + } + /** * 递归创建子级导航 */ diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsWebsiteController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsWebsiteController.java index ddf42de..fbd0f63 100644 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsWebsiteController.java +++ b/src/main/java/com/gxwebsoft/cms/controller/CmsWebsiteController.java @@ -134,6 +134,9 @@ public class CmsWebsiteController extends BaseController { cmsWebsite.setWebsiteCode(null); } if (cmsWebsiteService.updateById(cmsWebsite)) { + // 站点信息(含 domain / templateId 等)有 1 天 Redis 缓存,改完必须立刻失效, + // 否则公开站与后台链接拼接最长 1 天读到旧值(与 CmsNavigationController 写操作保持一致)。 + clearSiteInfoCacheQuietly(); return success("修改成功"); } return fail("修改失败"); @@ -144,11 +147,30 @@ public class CmsWebsiteController extends BaseController { @PutMapping("/updateAll") public ApiResult updateAll(@RequestBody CmsWebsite cmsWebsite) { if (cmsWebsiteService.updateByIdAll(cmsWebsite)) { + clearSiteInfoCacheQuietly(); return success("修改成功"); } return fail("修改失败"); } + /** + * 清除当前租户的站点信息缓存。 + * 缓存失效属于写操作的附带动作,异常不应影响主流程(更新本身已成功)。 + */ + private void clearSiteInfoCacheQuietly() { + try { + Integer tenantId = getTenantId(); + if (ObjectUtil.isEmpty(tenantId)) { + return; + } + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(tenantId.toString())); + redisUtil.delete(MP_INFO_KEY_PREFIX.concat(tenantId.toString())); + log.info("已清除站点信息缓存,租户ID: {}", tenantId); + } catch (Exception e) { + log.warn("清除站点信息缓存失败: {}", e.getMessage()); + } + } + @PreAuthorize("hasAuthority('cms:website:remove')") @Operation(summary = "删除网站信息记录表") @DeleteMapping("/{id}")