fix(cache): 解决缓存中JSON null值导致的空指针问题

- 添加对历史缓存中JSON "null" 字符串的兼容处理
- 当缓存解析出null值时清理缓存并回源数据库
- 在CmsWebsiteServiceImpl中增加缓存清理逻辑
- 在ShopWebsiteServiceImpl中统一缓存异常处理机制
- 添加单元测试验证JSON null值场景的正确回退行为
This commit is contained in:
2026-02-06 00:49:00 +08:00
parent 2c076e2b0f
commit 60279fca4c
3 changed files with 78 additions and 2 deletions

View File

@@ -0,0 +1,66 @@
package com.gxwebsoft.cms.service.impl;
import com.gxwebsoft.cms.entity.CmsWebsite;
import com.gxwebsoft.cms.mapper.CmsWebsiteMapper;
import com.gxwebsoft.cms.service.CmsNavigationService;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.shop.vo.ShopVo;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class CmsWebsiteServiceImplCacheTest {
@Test
void getSiteInfo_cacheValueIsJsonNull_shouldFallbackToDb() throws Exception {
Integer tenantId = 1;
RedisUtil redisUtil = mock(RedisUtil.class);
CmsNavigationService cmsNavigationService = mock(CmsNavigationService.class);
CmsWebsiteMapper cmsWebsiteMapper = mock(CmsWebsiteMapper.class);
// 历史缓存可能存在字符串 "null"Jackson 解析后会得到 null需回源 DB。
when(redisUtil.get("SiteInfo:" + tenantId)).thenReturn("null");
when(cmsNavigationService.listRel(any())).thenReturn(Collections.emptyList());
CmsWebsite website = new CmsWebsite();
website.setTenantId(tenantId);
website.setTenantName("tenant");
website.setWebsiteName("site");
when(cmsWebsiteMapper.getByTenantId(tenantId)).thenReturn(website);
CmsWebsiteServiceImpl service = new CmsWebsiteServiceImpl();
setField(service, "redisUtil", redisUtil);
setField(service, "cmsNavigationService", cmsNavigationService);
setField(service, "baseMapper", cmsWebsiteMapper);
ShopVo vo = service.getSiteInfo(tenantId);
assertNotNull(vo);
verify(redisUtil).delete("SiteInfo:" + tenantId);
verify(cmsWebsiteMapper).getByTenantId(tenantId);
}
private static void setField(Object target, String fieldName, Object value) throws Exception {
Class<?> c = target.getClass();
while (c != null) {
try {
Field f = c.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(target, value);
return;
} catch (NoSuchFieldException ignored) {
c = c.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
}