fix(cms): 增强单页绑定唯一性校验和缓存失效处理
- 在CmsNavigationController新增checkPageBindingUnique方法,确保同一租户下同一单页只能绑定一个栏目 - 在新增和修改网站导航时调用绑定唯一性校验,避免唯一索引冲突导致操作失败 - 在CmsWebsiteController修改后立即清理站点信息缓存,避免缓存数据延迟导致旧数据读取 - clearSiteInfoCacheQuietly方法中捕获异常,确保缓存清理失败不会影响主流程 - 添加了缓存清理的日志记录,方便问题追踪
This commit is contained in:
@@ -21,6 +21,7 @@ import com.gxwebsoft.cms.param.CmsNavigationParam;
|
|||||||
import com.gxwebsoft.common.core.web.ApiResult;
|
import com.gxwebsoft.common.core.web.ApiResult;
|
||||||
import com.gxwebsoft.common.core.web.PageResult;
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
import com.gxwebsoft.common.core.web.BatchParam;
|
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.entity.User;
|
||||||
import com.gxwebsoft.common.system.service.UserService;
|
import com.gxwebsoft.common.system.service.UserService;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@@ -103,6 +104,8 @@ public class CmsNavigationController extends BaseController {
|
|||||||
}
|
}
|
||||||
// 去除前面空格
|
// 去除前面空格
|
||||||
cmsNavigation.setTitle(StrUtil.trimStart(cmsNavigation.getTitle()));
|
cmsNavigation.setTitle(StrUtil.trimStart(cmsNavigation.getTitle()));
|
||||||
|
// 单页模型绑定唯一性校验:同一租户下同一个单页只能绑定一个栏目
|
||||||
|
checkPageBindingUnique(cmsNavigation);
|
||||||
if (cmsNavigationService.save(cmsNavigation)) {
|
if (cmsNavigationService.save(cmsNavigation)) {
|
||||||
// 添加成功事务处理
|
// 添加成功事务处理
|
||||||
cmsNavigationService.saveAsync(cmsNavigation);
|
cmsNavigationService.saveAsync(cmsNavigation);
|
||||||
@@ -116,6 +119,8 @@ public class CmsNavigationController extends BaseController {
|
|||||||
@Operation(summary = "修改网站导航记录表")
|
@Operation(summary = "修改网站导航记录表")
|
||||||
@PutMapping()
|
@PutMapping()
|
||||||
public ApiResult<?> update(@RequestBody CmsNavigation cmsNavigation) {
|
public ApiResult<?> update(@RequestBody CmsNavigation cmsNavigation) {
|
||||||
|
// 单页模型绑定唯一性校验:同一租户下同一个单页只能绑定一个栏目
|
||||||
|
checkPageBindingUnique(cmsNavigation);
|
||||||
if (cmsNavigationService.updateById(cmsNavigation)) {
|
if (cmsNavigationService.updateById(cmsNavigation)) {
|
||||||
// 修改成功事务处理
|
// 修改成功事务处理
|
||||||
cmsNavigationService.saveAsync(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<CmsNavigation> 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("该单页已被其他栏目绑定,请先解绑后再绑定");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归创建子级导航
|
* 递归创建子级导航
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -134,6 +134,9 @@ public class CmsWebsiteController extends BaseController {
|
|||||||
cmsWebsite.setWebsiteCode(null);
|
cmsWebsite.setWebsiteCode(null);
|
||||||
}
|
}
|
||||||
if (cmsWebsiteService.updateById(cmsWebsite)) {
|
if (cmsWebsiteService.updateById(cmsWebsite)) {
|
||||||
|
// 站点信息(含 domain / templateId 等)有 1 天 Redis 缓存,改完必须立刻失效,
|
||||||
|
// 否则公开站与后台链接拼接最长 1 天读到旧值(与 CmsNavigationController 写操作保持一致)。
|
||||||
|
clearSiteInfoCacheQuietly();
|
||||||
return success("修改成功");
|
return success("修改成功");
|
||||||
}
|
}
|
||||||
return fail("修改失败");
|
return fail("修改失败");
|
||||||
@@ -144,11 +147,30 @@ public class CmsWebsiteController extends BaseController {
|
|||||||
@PutMapping("/updateAll")
|
@PutMapping("/updateAll")
|
||||||
public ApiResult<?> updateAll(@RequestBody CmsWebsite cmsWebsite) {
|
public ApiResult<?> updateAll(@RequestBody CmsWebsite cmsWebsite) {
|
||||||
if (cmsWebsiteService.updateByIdAll(cmsWebsite)) {
|
if (cmsWebsiteService.updateByIdAll(cmsWebsite)) {
|
||||||
|
clearSiteInfoCacheQuietly();
|
||||||
return success("修改成功");
|
return success("修改成功");
|
||||||
}
|
}
|
||||||
return fail("修改失败");
|
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')")
|
@PreAuthorize("hasAuthority('cms:website:remove')")
|
||||||
@Operation(summary = "删除网站信息记录表")
|
@Operation(summary = "删除网站信息记录表")
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
|
|||||||
Reference in New Issue
Block a user