Merge pull request #797 from baiyu-jujuc/fix/redis-image-preview-npe

fix: avoid NPE when previewing images with redis cache
This commit is contained in:
kl
2026-10-08 13:02:47 +08:00
committed by GitHub
2 changed files with 70 additions and 0 deletions

View File

@@ -1,12 +1,14 @@
package cn.keking.service.cache.impl;
import cn.keking.service.cache.CacheService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -68,6 +70,9 @@ public class CacheServiceRedisImpl implements CacheService {
@Override
public List<String> getImgCache(String key) {
if (StringUtils.isEmpty(key)) {
return new ArrayList<>();
}
RMapCache<String, List<String>> convertedList = redissonClient.getMapCache(FILE_PREVIEW_IMGS_KEY);
return convertedList.get(key);
}

View File

@@ -0,0 +1,65 @@
package cn.keking.service.cache.impl;
import cn.keking.service.cache.CacheService;
import org.junit.jupiter.api.Test;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
/**
* CacheServiceRedisImpl 回归测试。
*
* 背景:cache.type=redis 时预览单张图片,compressFileKey 为 null,
* 修复前会把 null 直接传给 Redisson,抛出 NullPointerException: map key can't be null。
*/
class CacheServiceRedisImplTests {
@Test
void shouldReturnEmptyListWhenKeyIsNull() {
RedissonClient redissonClient = mock(RedissonClient.class);
CacheServiceRedisImpl cacheService = new CacheServiceRedisImpl(redissonClient);
List<String> result = cacheService.getImgCache(null);
assertNotNull(result);
assertTrue(result.isEmpty());
// 判空后不应再访问 Redis —— 修复前这里会调用 getMapCache 并抛出 NPE
verifyNoInteractions(redissonClient);
}
@Test
void shouldReturnEmptyListWhenKeyIsEmpty() {
RedissonClient redissonClient = mock(RedissonClient.class);
CacheServiceRedisImpl cacheService = new CacheServiceRedisImpl(redissonClient);
List<String> result = cacheService.getImgCache("");
assertNotNull(result);
assertTrue(result.isEmpty());
verifyNoInteractions(redissonClient);
}
@Test
void shouldReadFromRedisWhenKeyIsPresent() {
RedissonClient redissonClient = mock(RedissonClient.class);
@SuppressWarnings("unchecked")
RMapCache<String, List<String>> mapCache = mock(RMapCache.class);
when(redissonClient.<String, List<String>>getMapCache(CacheService.FILE_PREVIEW_IMGS_KEY))
.thenReturn(mapCache);
when(mapCache.get("zip-key")).thenReturn(List.of("a.png", "b.png"));
CacheServiceRedisImpl cacheService = new CacheServiceRedisImpl(redissonClient);
List<String> result = cacheService.getImgCache("zip-key");
assertEquals(List.of("a.png", "b.png"), result);
}
}