refactor(cache): 缓存操作接口化,支持 Redis/Caffeine 双实现切换
将系统所有缓存操作从 `RedisUtil` 迁移至 `CacheOperations` 接口, 通过 `gym.cache.type` 配置选择 Redis 或 Caffeine 实现。 变更内容: - 新增 CacheOperations 接口,定义 get/set/delete/hasKey/expire/deleteByPattern 等标准方法 - 新增 RedisCacheOperations 实现(基于 ReactiveRedisTemplate,默认实现) - 新增 CaffeineCacheOperations 实现(基于 Caffeine 本地缓存) - 新增 CacheProperties 配置类,支持 Caffeine 容量/过期等参数配置 - 新增 CacheAutoConfiguration 自动装配,通过 AutoConfiguration.imports 注册 - 全系统 17 个业务服务 + 18 个测试文件从 RedisUtil 迁移至 CacheOperations - manage-gateway 配置 caffeine 实现(无需 Redis),manage-app 配置 redis 实现 - 分布式锁等 Redis 独有特性保持直接使用 ReactiveRedisTemplate 测试:202 通过,0 失败,0 错误
This commit was merged in pull request #56.
This commit is contained in:
+7
-7
@@ -6,7 +6,7 @@ import cn.novalon.gym.manage.member.enums.MemberCardRecordStatus;
|
||||
import cn.novalon.gym.manage.member.repository.MemberCardRecordRepository;
|
||||
import cn.novalon.gym.manage.member.repository.MemberCardRepository;
|
||||
import cn.novalon.gym.manage.member.service.IMemberCardRecordService;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -29,30 +29,30 @@ import java.util.stream.Collectors;
|
||||
public class MemberCardRecordServiceImpl implements IMemberCardRecordService {
|
||||
private final MemberCardRecordRepository memberCardRecordRepository;
|
||||
private final MemberCardRepository memberCardRepository;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private static final String MEMBER_CARD_RECORD_CACHE_PREFIX = "member:card:record:";
|
||||
private static final long CACHE_EXPIRE_SECONDS = 300;
|
||||
|
||||
public MemberCardRecordServiceImpl(MemberCardRecordRepository memberCardRecordRepository,
|
||||
MemberCardRepository memberCardRepository,
|
||||
RedisUtil redisUtil) {
|
||||
CacheOperations cacheOperations) {
|
||||
this.memberCardRecordRepository = memberCardRecordRepository;
|
||||
this.memberCardRepository = memberCardRepository;
|
||||
this.redisUtil = redisUtil;
|
||||
this.cacheOperations = cacheOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MemberCardRecord> findById(Long recordId) {
|
||||
String cacheKey = MEMBER_CARD_RECORD_CACHE_PREFIX + recordId;
|
||||
return redisUtil.get(cacheKey)
|
||||
return cacheOperations.get(cacheKey)
|
||||
.filter(cached -> cached instanceof MemberCardRecord)
|
||||
.map(cached -> (MemberCardRecord) cached)
|
||||
.switchIfEmpty(Mono.defer(() ->
|
||||
memberCardRecordRepository.findById(recordId)
|
||||
.doOnSuccess(record -> {
|
||||
if (record != null) {
|
||||
redisUtil.setWithExpire(cacheKey, record, CACHE_EXPIRE_SECONDS);
|
||||
cacheOperations.setWithExpire(cacheKey, record, CACHE_EXPIRE_SECONDS);
|
||||
}
|
||||
})
|
||||
));
|
||||
@@ -255,7 +255,7 @@ public class MemberCardRecordServiceImpl implements IMemberCardRecordService {
|
||||
|
||||
private void clearRecordCache(Long recordId) {
|
||||
String cacheKey = MEMBER_CARD_RECORD_CACHE_PREFIX + recordId;
|
||||
redisUtil.delete(cacheKey);
|
||||
cacheOperations.delete(cacheKey);
|
||||
log.debug("清除会员卡记录缓存, recordId: {}", recordId);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,6 +1,6 @@
|
||||
package cn.novalon.gym.manage.member.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCard;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardRecord;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardTransaction;
|
||||
@@ -40,7 +40,7 @@ public class MemberCardServiceImpl implements IMemberCardService {
|
||||
private final DistributedLockService distributedLockService;
|
||||
private final ExpirationReminderService expirationReminderService;
|
||||
private final RefundSagaHandler refundSagaHandler;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private static final String MEMBER_CARD_CACHE_PREFIX = "member:card:";
|
||||
private static final long CACHE_EXPIRE_SECONDS = 300;
|
||||
@@ -53,7 +53,7 @@ public class MemberCardServiceImpl implements IMemberCardService {
|
||||
DistributedLockService distributedLockService,
|
||||
ExpirationReminderService expirationReminderService,
|
||||
RefundSagaHandler refundSagaHandler,
|
||||
RedisUtil redisUtil) {
|
||||
CacheOperations cacheOperations) {
|
||||
this.memberCardRepository = memberCardRepository;
|
||||
this.recordRepository = recordRepository;
|
||||
this.transactionService = transactionService;
|
||||
@@ -61,13 +61,13 @@ public class MemberCardServiceImpl implements IMemberCardService {
|
||||
this.distributedLockService = distributedLockService;
|
||||
this.expirationReminderService = expirationReminderService;
|
||||
this.refundSagaHandler = refundSagaHandler;
|
||||
this.redisUtil = redisUtil;
|
||||
this.cacheOperations = cacheOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MemberCard> findByMemberCardIdAndDeletedAtIsNull(Long memberCardId) {
|
||||
String cacheKey = MEMBER_CARD_CACHE_PREFIX + memberCardId;
|
||||
Object cached = redisUtil.get(cacheKey);
|
||||
Object cached = cacheOperations.get(cacheKey);
|
||||
if (cached != null && cached instanceof MemberCard) {
|
||||
log.debug("从缓存获取会员卡信息, memberCardId: {}", memberCardId);
|
||||
return Mono.just((MemberCard) cached);
|
||||
@@ -76,7 +76,7 @@ public class MemberCardServiceImpl implements IMemberCardService {
|
||||
return memberCardRepository.findByMemberCardIdAndDeletedAtIsNull(memberCardId)
|
||||
.doOnSuccess(card -> {
|
||||
if (card != null) {
|
||||
redisUtil.setWithExpire(cacheKey, card, CACHE_EXPIRE_SECONDS);
|
||||
cacheOperations.setWithExpire(cacheKey, card, CACHE_EXPIRE_SECONDS);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -439,7 +439,7 @@ public class MemberCardServiceImpl implements IMemberCardService {
|
||||
|
||||
private void clearCardCache(Long memberCardId) {
|
||||
String cacheKey = MEMBER_CARD_CACHE_PREFIX + memberCardId;
|
||||
redisUtil.delete(cacheKey);
|
||||
cacheOperations.delete(cacheKey);
|
||||
log.debug("清除会员卡缓存, memberCardId: {}", memberCardId);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -18,7 +18,7 @@ import cn.novalon.gym.manage.member.util.AesUtil;
|
||||
import cn.novalon.gym.manage.member.util.BeanConvertUtil;
|
||||
import cn.novalon.gym.manage.member.util.EsSyncUtils;
|
||||
import cn.novalon.gym.manage.member.util.WechatPhoneUtil;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.vo.MemberCardInfoVO;
|
||||
import cn.novalon.gym.manage.member.vo.MemberDetailVO;
|
||||
import cn.novalon.gym.manage.member.vo.MemberInfoVO;
|
||||
@@ -50,7 +50,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
private final IMemberRepository memberRepository;
|
||||
private final MemberESRepository memberESRepository;
|
||||
private final EsSyncUtils esSyncUtils;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private EsSyncUtils.EntitySyncer<Member, MemberES, String> memberSyncer;
|
||||
|
||||
@@ -68,7 +68,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
String cacheKey = MEMBER_INFO_CACHE_PREFIX + memberId;
|
||||
|
||||
// 先查缓存
|
||||
return redisUtil.get(cacheKey, MemberInfoVO.class)
|
||||
return cacheOperations.get(cacheKey, MemberInfoVO.class)
|
||||
.flatMap(cached -> {
|
||||
if (cached != null) {
|
||||
log.debug("从缓存获取会员信息, memberId: {}", memberId);
|
||||
@@ -91,7 +91,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
.map(this::buildMemberInfoResponse)
|
||||
.flatMap(vo -> {
|
||||
// 查询到数据后更新缓存
|
||||
return redisUtil.setWithExpire(cacheKey, vo, CACHE_EXPIRE_SECONDS)
|
||||
return cacheOperations.setWithExpire(cacheKey, vo, CACHE_EXPIRE_SECONDS)
|
||||
.then(Mono.just(vo));
|
||||
})
|
||||
.switchIfEmpty(Mono.error(() -> {
|
||||
@@ -269,7 +269,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
|
||||
String cacheKey = MEMBER_DETAIL_CACHE_PREFIX + memberId;
|
||||
|
||||
return redisUtil.get(cacheKey, MemberDetailVO.class)
|
||||
return cacheOperations.get(cacheKey, MemberDetailVO.class)
|
||||
.filter(cached -> cached != null)
|
||||
.switchIfEmpty(Mono.defer(() ->
|
||||
memberRepository.findById(memberId)
|
||||
@@ -312,7 +312,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
return memberDetailVO;
|
||||
}
|
||||
)
|
||||
.flatMap(vo -> redisUtil.setWithExpire(cacheKey, vo, CACHE_EXPIRE_SECONDS)
|
||||
.flatMap(vo -> cacheOperations.setWithExpire(cacheKey, vo, CACHE_EXPIRE_SECONDS)
|
||||
.then(Mono.just(vo)))
|
||||
));
|
||||
}
|
||||
@@ -383,8 +383,8 @@ public class MemberServiceImpl implements MemberService {
|
||||
private Mono<Long> clearMemberCache(Long memberId) {
|
||||
String infoCacheKey = MEMBER_INFO_CACHE_PREFIX + memberId;
|
||||
String detailCacheKey = MEMBER_DETAIL_CACHE_PREFIX + memberId;
|
||||
return redisUtil.delete(infoCacheKey)
|
||||
.then(redisUtil.delete(detailCacheKey))
|
||||
return cacheOperations.delete(infoCacheKey)
|
||||
.then(cacheOperations.delete(detailCacheKey))
|
||||
.doOnSuccess(result -> log.debug("清除会员缓存, memberId: {}", memberId));
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -5,7 +5,7 @@ import cn.novalon.gym.manage.member.entity.RefundApplication;
|
||||
import cn.novalon.gym.manage.member.enums.RefundStatus;
|
||||
import cn.novalon.gym.manage.member.repository.RefundApplicationRepository;
|
||||
import cn.novalon.gym.manage.member.service.IRefundApplicationService;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -23,14 +23,14 @@ import java.time.LocalDateTime;
|
||||
public class RefundApplicationServiceImpl implements IRefundApplicationService {
|
||||
|
||||
private final RefundApplicationRepository refundApplicationRepository;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private static final String REFUND_APPLICATION_CACHE_PREFIX = "member:refund:";
|
||||
private static final long CACHE_EXPIRE_SECONDS = 300;
|
||||
|
||||
public RefundApplicationServiceImpl(RefundApplicationRepository refundApplicationRepository, RedisUtil redisUtil) {
|
||||
public RefundApplicationServiceImpl(RefundApplicationRepository refundApplicationRepository, CacheOperations cacheOperations) {
|
||||
this.refundApplicationRepository = refundApplicationRepository;
|
||||
this.redisUtil = redisUtil;
|
||||
this.cacheOperations = cacheOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,7 +103,7 @@ public class RefundApplicationServiceImpl implements IRefundApplicationService {
|
||||
@Override
|
||||
public Mono<RefundApplication> findByRecordId(Long recordId) {
|
||||
String cacheKey = REFUND_APPLICATION_CACHE_PREFIX + recordId;
|
||||
Object cached = redisUtil.get(cacheKey);
|
||||
Object cached = cacheOperations.get(cacheKey);
|
||||
if (cached != null && cached instanceof RefundApplication) {
|
||||
log.debug("从缓存获取退款申请, recordId: {}", recordId);
|
||||
return Mono.just((RefundApplication) cached);
|
||||
@@ -112,14 +112,14 @@ public class RefundApplicationServiceImpl implements IRefundApplicationService {
|
||||
return refundApplicationRepository.findByRecordId(recordId)
|
||||
.doOnSuccess(application -> {
|
||||
if (application != null) {
|
||||
redisUtil.setWithExpire(cacheKey, application, CACHE_EXPIRE_SECONDS);
|
||||
cacheOperations.setWithExpire(cacheKey, application, CACHE_EXPIRE_SECONDS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void clearRefundCache(Long recordId) {
|
||||
String cacheKey = REFUND_APPLICATION_CACHE_PREFIX + recordId;
|
||||
redisUtil.delete(cacheKey);
|
||||
cacheOperations.delete(cacheKey);
|
||||
log.debug("清除退款申请缓存, recordId: {}", recordId);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ import cn.novalon.gym.manage.common.exception.ErrorCode;
|
||||
import cn.novalon.gym.manage.common.exception.SystemException;
|
||||
import cn.novalon.gym.manage.member.config.WechatProperties;
|
||||
import cn.novalon.gym.manage.member.service.WechatApiService;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -31,7 +31,7 @@ import java.util.Map;
|
||||
public class WechatApiServiceImpl implements WechatApiService {
|
||||
|
||||
private final WechatProperties wechatProperties;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private static final String ACCESS_TOKEN_CACHE_PREFIX = "wechat:access_token:";
|
||||
private static final long ACCESS_TOKEN_EXPIRE_SECONDS = 7000; // 比官方过期时间短100秒
|
||||
@@ -173,7 +173,7 @@ public class WechatApiServiceImpl implements WechatApiService {
|
||||
|
||||
String cacheKey = ACCESS_TOKEN_CACHE_PREFIX + appType;
|
||||
|
||||
return redisUtil.get(cacheKey, String.class)
|
||||
return cacheOperations.get(cacheKey, String.class)
|
||||
.flatMap(cachedToken -> {
|
||||
if (cachedToken != null) {
|
||||
log.debug("从缓存获取access_token, appType: {}", appType);
|
||||
@@ -203,7 +203,7 @@ public class WechatApiServiceImpl implements WechatApiService {
|
||||
String accessToken = (String) response.get("access_token");
|
||||
Integer expiresIn = (Integer) response.get("expires_in");
|
||||
log.info("获取access_token成功, expires_in: {}s", expiresIn);
|
||||
return redisUtil.setWithExpire(cacheKey, accessToken, ACCESS_TOKEN_EXPIRE_SECONDS)
|
||||
return cacheOperations.setWithExpire(cacheKey, accessToken, ACCESS_TOKEN_EXPIRE_SECONDS)
|
||||
.then(Mono.just(accessToken));
|
||||
} else {
|
||||
String errmsg = (String) response.get("errmsg");
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@ import cn.novalon.gym.manage.member.service.WechatAuthService;
|
||||
import cn.novalon.gym.manage.member.util.AesUtil;
|
||||
import cn.novalon.gym.manage.member.util.EsSyncUtils;
|
||||
import cn.novalon.gym.manage.member.util.MemberNoGenerator;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.util.WechatPhoneUtil;
|
||||
import cn.novalon.gym.manage.member.vo.WechatLoginVO;
|
||||
import cn.novalon.gym.manage.sys.security.JwtTokenProvider;
|
||||
@@ -46,7 +46,7 @@ public class WechatAuthServiceImpl implements WechatAuthService {
|
||||
private final MemberESRepository memberESRepository;
|
||||
private final EsSyncUtils esSyncUtils;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private EsSyncUtils.EntitySyncer<Member, MemberES, String> memberSyncer;
|
||||
|
||||
@@ -217,7 +217,7 @@ public class WechatAuthServiceImpl implements WechatAuthService {
|
||||
|
||||
private void clearMemberCache(Long memberId) {
|
||||
String cacheKey = MEMBER_INFO_CACHE_PREFIX + memberId;
|
||||
redisUtil.delete(cacheKey);
|
||||
cacheOperations.delete(cacheKey);
|
||||
log.debug("清除会员缓存, memberId: {}", memberId);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -8,7 +8,7 @@ import cn.novalon.gym.manage.member.es.repository.MemberESRepository;
|
||||
import cn.novalon.gym.manage.member.repository.IMemberRepository;
|
||||
import cn.novalon.gym.manage.member.service.WechatOfficialService;
|
||||
import cn.novalon.gym.manage.member.util.EsSyncUtils;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.vo.WechatUserInfoVO;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -43,7 +43,7 @@ public class WechatOfficialServiceImpl implements WechatOfficialService {
|
||||
private final ObjectMapper objectMapper = new ObjectMapper()
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
private final EsSyncUtils esSyncUtils;
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheOperations cacheOperations;
|
||||
|
||||
private EsSyncUtils.EntitySyncer<Member, MemberES, String> memberSyncer;
|
||||
|
||||
@@ -297,7 +297,7 @@ public class WechatOfficialServiceImpl implements WechatOfficialService {
|
||||
private Mono<String> getAccessToken() {
|
||||
String cacheKey = ACCESS_TOKEN_CACHE_PREFIX + "mp";
|
||||
|
||||
return redisUtil.get(cacheKey, String.class)
|
||||
return cacheOperations.get(cacheKey, String.class)
|
||||
.flatMap(cachedToken -> {
|
||||
if (cachedToken != null) {
|
||||
log.debug("从缓存获取服务号access_token");
|
||||
@@ -322,7 +322,7 @@ public class WechatOfficialServiceImpl implements WechatOfficialService {
|
||||
throw new RuntimeException("获取AccessToken失败: " + response.get("errmsg"));
|
||||
}
|
||||
String accessToken = (String) response.get("access_token");
|
||||
return redisUtil.setWithExpire(cacheKey, accessToken, ACCESS_TOKEN_EXPIRE_SECONDS)
|
||||
return cacheOperations.setWithExpire(cacheKey, accessToken, ACCESS_TOKEN_EXPIRE_SECONDS)
|
||||
.then(Mono.just(accessToken));
|
||||
});
|
||||
});
|
||||
@@ -373,7 +373,7 @@ public class WechatOfficialServiceImpl implements WechatOfficialService {
|
||||
|
||||
private Mono<Long> clearMemberCache(Long memberId) {
|
||||
String cacheKey = MEMBER_INFO_CACHE_PREFIX + memberId;
|
||||
return redisUtil.delete(cacheKey)
|
||||
return cacheOperations.delete(cacheKey)
|
||||
.doOnSuccess(result -> log.debug("清除会员缓存, memberId: {}", memberId));
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,6 +1,6 @@
|
||||
package cn.novalon.gym.manage.member.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCard;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardRecord;
|
||||
import cn.novalon.gym.manage.member.enums.MemberCardRecordStatus;
|
||||
@@ -37,7 +37,7 @@ class MemberCardRecordServiceImplTest {
|
||||
private MemberCardRepository memberCardRepository;
|
||||
|
||||
@Mock
|
||||
private RedisUtil redisUtil;
|
||||
private CacheOperations cacheOperations;
|
||||
|
||||
@InjectMocks
|
||||
private MemberCardRecordServiceImpl memberCardRecordService;
|
||||
@@ -82,7 +82,7 @@ class MemberCardRecordServiceImplTest {
|
||||
@DisplayName("缓存命中时应从缓存返回")
|
||||
void shouldReturnFromCacheWhenHit() {
|
||||
MemberCardRecord record = createRecord();
|
||||
when(redisUtil.get("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(record));
|
||||
when(cacheOperations.get("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(record));
|
||||
|
||||
Mono<MemberCardRecord> result = memberCardRecordService.findById(RECORD_ID);
|
||||
|
||||
@@ -97,7 +97,7 @@ class MemberCardRecordServiceImplTest {
|
||||
@DisplayName("缓存未命中时应从数据库查询并更新缓存")
|
||||
void shouldQueryDatabaseWhenCacheMiss() {
|
||||
MemberCardRecord record = createRecord();
|
||||
when(redisUtil.get("member:card:record:" + RECORD_ID)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get("member:card:record:" + RECORD_ID)).thenReturn(Mono.empty());
|
||||
when(memberCardRecordRepository.findById(anyLong())).thenReturn(Mono.just(record));
|
||||
|
||||
Mono<MemberCardRecord> result = memberCardRecordService.findById(RECORD_ID);
|
||||
@@ -112,7 +112,7 @@ class MemberCardRecordServiceImplTest {
|
||||
@Test
|
||||
@DisplayName("记录不存在时应返回空")
|
||||
void shouldReturnEmptyWhenNotFound() {
|
||||
when(redisUtil.get("member:card:record:" + RECORD_ID)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get("member:card:record:" + RECORD_ID)).thenReturn(Mono.empty());
|
||||
when(memberCardRecordRepository.findById(anyLong())).thenReturn(Mono.empty());
|
||||
|
||||
Mono<MemberCardRecord> result = memberCardRecordService.findById(RECORD_ID);
|
||||
@@ -210,7 +210,7 @@ class MemberCardRecordServiceImplTest {
|
||||
@DisplayName("扣减成功时应清除缓存")
|
||||
void shouldClearCacheWhenDeducted() {
|
||||
when(memberCardRecordRepository.deductUsage(RECORD_ID, 1, 0.0)).thenReturn(Mono.just(1));
|
||||
when(redisUtil.delete("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
Mono<Integer> result = memberCardRecordService.deductUsage(RECORD_ID, 1, 0.0);
|
||||
|
||||
@@ -218,7 +218,7 @@ class MemberCardRecordServiceImplTest {
|
||||
.assertNext(updated -> assertThat(updated).isEqualTo(1))
|
||||
.verifyComplete();
|
||||
|
||||
verify(redisUtil).delete("member:card:record:" + RECORD_ID);
|
||||
verify(cacheOperations).delete("member:card:record:" + RECORD_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -232,7 +232,7 @@ class MemberCardRecordServiceImplTest {
|
||||
.assertNext(updated -> assertThat(updated).isZero())
|
||||
.verifyComplete();
|
||||
|
||||
verify(redisUtil, never()).delete(anyString());
|
||||
verify(cacheOperations, never()).delete(anyString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ class MemberCardRecordServiceImplTest {
|
||||
void shouldClearCacheWhenRenewed() {
|
||||
LocalDateTime newExpire = LocalDateTime.now().plusDays(30);
|
||||
when(memberCardRecordRepository.renewCard(RECORD_ID, 10, null, newExpire)).thenReturn(Mono.just(1));
|
||||
when(redisUtil.delete("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
Mono<Integer> result = memberCardRecordService.renewCard(RECORD_ID, 10, null, newExpire);
|
||||
|
||||
@@ -267,7 +267,7 @@ class MemberCardRecordServiceImplTest {
|
||||
@DisplayName("状态更新成功时应清除缓存")
|
||||
void shouldClearCacheWhenStatusUpdated() {
|
||||
when(memberCardRecordRepository.updateStatus(RECORD_ID, "USED_UP")).thenReturn(Mono.just(1));
|
||||
when(redisUtil.delete("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:card:record:" + RECORD_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
Mono<Integer> result = memberCardRecordService.updateStatus(RECORD_ID, "USED_UP");
|
||||
|
||||
|
||||
+7
-7
@@ -1,6 +1,6 @@
|
||||
package cn.novalon.gym.manage.member.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCard;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardRecord;
|
||||
import cn.novalon.gym.manage.member.enums.CardEvent;
|
||||
@@ -57,7 +57,7 @@ class MemberCardServiceImplTest {
|
||||
private RefundSagaHandler refundSagaHandler;
|
||||
|
||||
@Mock
|
||||
private RedisUtil redisUtil;
|
||||
private CacheOperations cacheOperations;
|
||||
|
||||
@InjectMocks
|
||||
private MemberCardServiceImpl memberCardService;
|
||||
@@ -155,7 +155,7 @@ class MemberCardServiceImplTest {
|
||||
@DisplayName("缓存未命中时应从数据库查询并更新缓存")
|
||||
void shouldQueryDatabaseWhenCacheMiss() {
|
||||
MemberCard card = createTimeCard();
|
||||
when(redisUtil.get("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.empty());
|
||||
when(memberCardRepository.findByMemberCardIdAndDeletedAtIsNull(MEMBER_CARD_ID))
|
||||
.thenReturn(Mono.just(card));
|
||||
|
||||
@@ -171,7 +171,7 @@ class MemberCardServiceImplTest {
|
||||
@Test
|
||||
@DisplayName("卡片不存在时应返回空")
|
||||
void shouldReturnEmptyWhenCardNotFound() {
|
||||
when(redisUtil.get("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.empty());
|
||||
when(memberCardRepository.findByMemberCardIdAndDeletedAtIsNull(MEMBER_CARD_ID))
|
||||
.thenReturn(Mono.empty());
|
||||
|
||||
@@ -214,7 +214,7 @@ class MemberCardServiceImplTest {
|
||||
void shouldClearCacheWhenSaved() {
|
||||
MemberCard card = createTimeCard();
|
||||
when(memberCardRepository.save(card)).thenReturn(Mono.just(card));
|
||||
when(redisUtil.delete("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
Mono<MemberCard> result = memberCardService.save(card);
|
||||
|
||||
@@ -222,7 +222,7 @@ class MemberCardServiceImplTest {
|
||||
.assertNext(c -> assertThat(c.getMemberCardName()).isEqualTo("月卡"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(redisUtil).delete("member:card:" + MEMBER_CARD_ID);
|
||||
verify(cacheOperations).delete("member:card:" + MEMBER_CARD_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ class MemberCardServiceImplTest {
|
||||
@DisplayName("购买时间卡应成功创建记录")
|
||||
void shouldPurchaseTimeCardSuccessfully() {
|
||||
MemberCard timeCard = createTimeCard();
|
||||
lenient().when(redisUtil.get("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.empty());
|
||||
lenient().when(cacheOperations.get("member:card:" + MEMBER_CARD_ID)).thenReturn(Mono.empty());
|
||||
when(memberCardRepository.findByIdAndDeletedAtIsNull(MEMBER_CARD_ID)).thenReturn(Mono.just(timeCard));
|
||||
when(recordRepository.insertActiveRecord(anyLong(), anyLong(), any(), anyInt(), anyDouble(), any()))
|
||||
.thenReturn(Mono.just(createActiveRecord(timeCard, MemberCardRecordStatus.ACTIVE)));
|
||||
|
||||
+25
-25
@@ -4,7 +4,7 @@ import cn.novalon.gym.manage.common.exception.ConflictException;
|
||||
import cn.novalon.gym.manage.common.exception.ErrorCode;
|
||||
import cn.novalon.gym.manage.common.exception.NotFoundException;
|
||||
import cn.novalon.gym.manage.common.util.HtmlEscapeUtil;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import cn.novalon.gym.manage.common.cache.CacheOperations;
|
||||
import cn.novalon.gym.manage.member.dto.SearchMemberDto;
|
||||
import cn.novalon.gym.manage.member.dto.UpdateMemberInfoDto;
|
||||
import cn.novalon.gym.manage.member.entity.Member;
|
||||
@@ -52,7 +52,7 @@ class MemberServiceImplTest {
|
||||
private EsSyncUtils esSyncUtils;
|
||||
|
||||
@Mock
|
||||
private RedisUtil redisUtil;
|
||||
private CacheOperations cacheOperations;
|
||||
|
||||
@InjectMocks
|
||||
private MemberServiceImpl memberServiceImpl;
|
||||
@@ -140,7 +140,7 @@ class MemberServiceImplTest {
|
||||
@DisplayName("缓存命中时应直接返回缓存数据")
|
||||
void shouldReturnCachedDataWhenCacheHit() {
|
||||
MemberInfoVO cachedVO = createTestMemberInfoVO();
|
||||
when(redisUtil.get(CACHE_INFO_KEY, MemberInfoVO.class)).thenReturn(Mono.just(cachedVO));
|
||||
when(cacheOperations.get(CACHE_INFO_KEY, MemberInfoVO.class)).thenReturn(Mono.just(cachedVO));
|
||||
|
||||
Mono<MemberInfoVO> result = memberServiceImpl.getMemberInfo(MEMBER_ID);
|
||||
|
||||
@@ -151,17 +151,17 @@ class MemberServiceImplTest {
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
verify(redisUtil).get(CACHE_INFO_KEY, MemberInfoVO.class);
|
||||
verify(cacheOperations).get(CACHE_INFO_KEY, MemberInfoVO.class);
|
||||
verifyNoInteractions(memberRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("缓存未命中时应从数据库查询并更新缓存")
|
||||
void shouldQueryDatabaseAndCacheWhenCacheMiss() {
|
||||
when(redisUtil.get(CACHE_INFO_KEY, MemberInfoVO.class)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get(CACHE_INFO_KEY, MemberInfoVO.class)).thenReturn(Mono.empty());
|
||||
Member member = createTestMember();
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.just(member));
|
||||
when(redisUtil.setWithExpire(eq(CACHE_INFO_KEY), any(MemberInfoVO.class), anyLong()))
|
||||
when(cacheOperations.setWithExpire(eq(CACHE_INFO_KEY), any(MemberInfoVO.class), anyLong()))
|
||||
.thenReturn(Mono.just(true));
|
||||
|
||||
try (MockedStatic<AesUtil> aesUtilMock = mockStatic(AesUtil.class)) {
|
||||
@@ -179,14 +179,14 @@ class MemberServiceImplTest {
|
||||
.verifyComplete();
|
||||
|
||||
verify(memberRepository).findById(MEMBER_ID);
|
||||
verify(redisUtil).setWithExpire(eq(CACHE_INFO_KEY), any(MemberInfoVO.class), eq(300L));
|
||||
verify(cacheOperations).setWithExpire(eq(CACHE_INFO_KEY), any(MemberInfoVO.class), eq(300L));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("会员不存在时应抛出 NotFoundException")
|
||||
void shouldThrowNotFoundExceptionWhenMemberNotFound() {
|
||||
when(redisUtil.get(CACHE_INFO_KEY, MemberInfoVO.class)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get(CACHE_INFO_KEY, MemberInfoVO.class)).thenReturn(Mono.empty());
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.empty());
|
||||
|
||||
Mono<MemberInfoVO> result = memberServiceImpl.getMemberInfo(MEMBER_ID);
|
||||
@@ -198,7 +198,7 @@ class MemberServiceImplTest {
|
||||
&& throwable.getMessage().equals("会员不存在"))
|
||||
.verify();
|
||||
|
||||
verify(redisUtil).get(CACHE_INFO_KEY, MemberInfoVO.class);
|
||||
verify(cacheOperations).get(CACHE_INFO_KEY, MemberInfoVO.class);
|
||||
verify(memberRepository).findById(MEMBER_ID);
|
||||
}
|
||||
}
|
||||
@@ -217,8 +217,8 @@ class MemberServiceImplTest {
|
||||
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.just(member));
|
||||
when(memberRepository.save(any(Member.class))).thenAnswer(invocation -> Mono.just(invocation.getArgument(0)));
|
||||
when(redisUtil.delete("member:info:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(redisUtil.delete("member:detail:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:info:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:detail:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
try (MockedStatic<AesUtil> aesUtilMock = mockStatic(AesUtil.class)) {
|
||||
aesUtilMock.when(() -> AesUtil.decrypt(ENCRYPTED_PHONE)).thenReturn(DECRYPTED_PHONE);
|
||||
@@ -236,8 +236,8 @@ class MemberServiceImplTest {
|
||||
verify(memberRepository).findById(MEMBER_ID);
|
||||
verify(memberRepository).save(any(Member.class));
|
||||
verify(mockSyncer).sync(any(Member.class));
|
||||
verify(redisUtil).delete("member:info:" + MEMBER_ID);
|
||||
verify(redisUtil).delete("member:detail:" + MEMBER_ID);
|
||||
verify(cacheOperations).delete("member:info:" + MEMBER_ID);
|
||||
verify(cacheOperations).delete("member:detail:" + MEMBER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +274,8 @@ class MemberServiceImplTest {
|
||||
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.just(member));
|
||||
when(memberRepository.save(any(Member.class))).thenAnswer(invocation -> Mono.just(invocation.getArgument(0)));
|
||||
when(redisUtil.delete("member:info:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(redisUtil.delete("member:detail:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:info:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:detail:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
try (MockedStatic<AesUtil> aesUtilMock = mockStatic(AesUtil.class)) {
|
||||
aesUtilMock.when(() -> AesUtil.encrypt(TEST_PHONE)).thenReturn(ENCRYPTED_PHONE);
|
||||
@@ -493,7 +493,7 @@ class MemberServiceImplTest {
|
||||
.nickname("测试会员")
|
||||
.build();
|
||||
|
||||
when(redisUtil.get(CACHE_DETAIL_KEY, MemberDetailVO.class)).thenReturn(Mono.just(cachedDetail));
|
||||
when(cacheOperations.get(CACHE_DETAIL_KEY, MemberDetailVO.class)).thenReturn(Mono.just(cachedDetail));
|
||||
|
||||
Mono<MemberDetailVO> result = memberServiceImpl.getMemberDetail(MEMBER_ID);
|
||||
|
||||
@@ -504,14 +504,14 @@ class MemberServiceImplTest {
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
verify(redisUtil).get(CACHE_DETAIL_KEY, MemberDetailVO.class);
|
||||
verify(cacheOperations).get(CACHE_DETAIL_KEY, MemberDetailVO.class);
|
||||
verifyNoInteractions(memberRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("缓存未命中时应从数据库查询并构建详情")
|
||||
void shouldQueryDatabaseAndBuildDetailWhenCacheMiss() {
|
||||
when(redisUtil.get(CACHE_DETAIL_KEY, MemberDetailVO.class)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get(CACHE_DETAIL_KEY, MemberDetailVO.class)).thenReturn(Mono.empty());
|
||||
|
||||
Member member = createTestMember();
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.just(member));
|
||||
@@ -520,7 +520,7 @@ class MemberServiceImplTest {
|
||||
when(memberRepository.findCardRecordsWithCardInfoByMemberId(MEMBER_ID))
|
||||
.thenReturn(Flux.just(cardInfo));
|
||||
|
||||
when(redisUtil.setWithExpire(eq(CACHE_DETAIL_KEY), any(MemberDetailVO.class), anyLong()))
|
||||
when(cacheOperations.setWithExpire(eq(CACHE_DETAIL_KEY), any(MemberDetailVO.class), anyLong()))
|
||||
.thenReturn(Mono.just(true));
|
||||
|
||||
Mono<MemberDetailVO> result = memberServiceImpl.getMemberDetail(MEMBER_ID);
|
||||
@@ -539,13 +539,13 @@ class MemberServiceImplTest {
|
||||
|
||||
verify(memberRepository).findById(MEMBER_ID);
|
||||
verify(memberRepository).findCardRecordsWithCardInfoByMemberId(MEMBER_ID);
|
||||
verify(redisUtil).setWithExpire(eq(CACHE_DETAIL_KEY), any(MemberDetailVO.class), eq(300L));
|
||||
verify(cacheOperations).setWithExpire(eq(CACHE_DETAIL_KEY), any(MemberDetailVO.class), eq(300L));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("会员不存在时应抛出 NotFoundException")
|
||||
void shouldThrowNotFoundExceptionWhenMemberNotFound() {
|
||||
when(redisUtil.get(CACHE_DETAIL_KEY, MemberDetailVO.class)).thenReturn(Mono.empty());
|
||||
when(cacheOperations.get(CACHE_DETAIL_KEY, MemberDetailVO.class)).thenReturn(Mono.empty());
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.empty());
|
||||
// zipWith 会订阅所有源,即使另一个是 error,也需要桩避免 NPE
|
||||
lenient().when(memberRepository.findCardRecordsWithCardInfoByMemberId(MEMBER_ID))
|
||||
@@ -577,8 +577,8 @@ class MemberServiceImplTest {
|
||||
|
||||
when(memberRepository.findById(MEMBER_ID)).thenReturn(Mono.just(member));
|
||||
when(memberRepository.save(any(Member.class))).thenAnswer(invocation -> Mono.just(invocation.getArgument(0)));
|
||||
when(redisUtil.delete("member:info:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(redisUtil.delete("member:detail:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:info:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
when(cacheOperations.delete("member:detail:" + MEMBER_ID)).thenReturn(Mono.just(1L));
|
||||
|
||||
Mono<Boolean> result = memberServiceImpl.adminUpdateMemberInfo(MEMBER_ID, dto);
|
||||
|
||||
@@ -589,8 +589,8 @@ class MemberServiceImplTest {
|
||||
verify(memberRepository).findById(MEMBER_ID);
|
||||
verify(memberRepository).save(any(Member.class));
|
||||
verify(mockSyncer).sync(any(Member.class));
|
||||
verify(redisUtil).delete("member:info:" + MEMBER_ID);
|
||||
verify(redisUtil).delete("member:detail:" + MEMBER_ID);
|
||||
verify(cacheOperations).delete("member:info:" + MEMBER_ID);
|
||||
verify(cacheOperations).delete("member:detail:" + MEMBER_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user