You've already forked FrameTour-BE
feat(notify): 添加批量查询用户授权余额功能
- 新增批量查询用户授权余额接口 /api/mobile/notify/auth/batch-remaining - 实现批量检查用户对多个模板的授权记录功能 - 添加景区所有场景及模板列表查询接口并支持缓存 - 优化授权记录查询性能,使用批量查询替代逐个查询 - 新增批量查询请求对象 BatchRemainingCountReq 和响应对象 WechatSubscribeAllScenesResp - 在数据层添加批量查询用户授权记录的 SQL 映射 - 实现缓存管理机制,支持所有场景模板配置的缓存读写与清理
This commit is contained in:
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.ycwl.basic.mapper.WechatSubscribeEventTemplateMapper;
|
||||
import com.ycwl.basic.mapper.WechatSubscribeSceneTemplateMapper;
|
||||
import com.ycwl.basic.mapper.WechatSubscribeTemplateConfigMapper;
|
||||
import com.ycwl.basic.model.mobile.notify.resp.WechatSubscribeAllScenesResp;
|
||||
import com.ycwl.basic.model.pc.notify.entity.WechatSubscribeEventTemplateEntity;
|
||||
import com.ycwl.basic.model.pc.notify.entity.WechatSubscribeSceneTemplateEntity;
|
||||
import com.ycwl.basic.model.pc.notify.entity.WechatSubscribeTemplateConfigEntity;
|
||||
@@ -58,6 +59,11 @@ public class WechatSubscribeNotifyConfigRepository {
|
||||
*/
|
||||
private static final String EVENT_TEMPLATE_SCENIC_PREFIX = "wechat:subscribe:event:configs:%s:*";
|
||||
|
||||
/**
|
||||
* 景区所有场景及模板缓存KEY
|
||||
*/
|
||||
private static final String ALL_SCENES_TEMPLATES_KEY = "wechat:subscribe:all-scenes:configs:%s";
|
||||
|
||||
/**
|
||||
* 缓存过期时间(小时)
|
||||
*/
|
||||
@@ -208,6 +214,98 @@ public class WechatSubscribeNotifyConfigRepository {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取景区下所有启用的场景Key列表(去重)
|
||||
* 包含默认配置(scenicId=0)和景区特定配置
|
||||
*
|
||||
* @param scenicId 景区ID
|
||||
* @return 去重后的场景Key列表
|
||||
*/
|
||||
public List<String> listAllSceneKeys(Long scenicId) {
|
||||
Objects.requireNonNull(scenicId, "scenicId is null");
|
||||
|
||||
List<Long> scenicIds = List.of(DEFAULT_SCENIC_ID, scenicId);
|
||||
QueryWrapper<WechatSubscribeSceneTemplateEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.in("scenic_id", scenicIds)
|
||||
.eq("enabled", 1)
|
||||
.select("DISTINCT scene_key");
|
||||
List<WechatSubscribeSceneTemplateEntity> rows = sceneTemplateMapper.selectList(wrapper);
|
||||
return rows.stream()
|
||||
.map(WechatSubscribeSceneTemplateEntity::getSceneKey)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取景区下所有场景及其模板列表(带缓存,不含用户授权信息)
|
||||
*
|
||||
* @param scenicId 景区ID
|
||||
* @return 所有场景及模板配置
|
||||
*/
|
||||
public WechatSubscribeAllScenesResp getAllScenesWithTemplatesCached(Long scenicId) {
|
||||
Objects.requireNonNull(scenicId, "scenicId is null");
|
||||
|
||||
String cacheKey = String.format(ALL_SCENES_TEMPLATES_KEY, scenicId);
|
||||
|
||||
// 1. 尝试从缓存读取
|
||||
Boolean hasKey = redisTemplate.hasKey(cacheKey);
|
||||
if (Boolean.TRUE.equals(hasKey)) {
|
||||
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
|
||||
if (cacheValue != null) {
|
||||
log.debug("从缓存读取所有场景模板配置: scenicId={}", scenicId);
|
||||
return JacksonUtil.parseObject(cacheValue, WechatSubscribeAllScenesResp.class);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 从数据库加载
|
||||
WechatSubscribeAllScenesResp resp = loadAllScenesWithTemplates(scenicId);
|
||||
|
||||
// 3. 写入缓存
|
||||
String json = JacksonUtil.toJSONString(resp);
|
||||
redisTemplate.opsForValue().set(cacheKey, json, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
|
||||
log.debug("所有场景模板配置缓存写入: scenicId={}, sceneCount={}",
|
||||
scenicId, resp.getScenes() != null ? resp.getScenes().size() : 0);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载所有场景及其模板配置(内部方法)
|
||||
*/
|
||||
private WechatSubscribeAllScenesResp loadAllScenesWithTemplates(Long scenicId) {
|
||||
List<String> sceneKeys = listAllSceneKeys(scenicId);
|
||||
|
||||
WechatSubscribeAllScenesResp resp = new WechatSubscribeAllScenesResp();
|
||||
resp.setScenicId(scenicId);
|
||||
|
||||
List<WechatSubscribeAllScenesResp.SceneWithTemplates> scenes = new ArrayList<>();
|
||||
for (String sceneKey : sceneKeys) {
|
||||
List<WechatSubscribeTemplateConfigEntity> configs = getSceneTemplateConfigsCached(scenicId, sceneKey);
|
||||
|
||||
WechatSubscribeAllScenesResp.SceneWithTemplates sceneWithTemplates = new WechatSubscribeAllScenesResp.SceneWithTemplates();
|
||||
sceneWithTemplates.setSceneKey(sceneKey);
|
||||
|
||||
List<WechatSubscribeAllScenesResp.StaticTemplateInfo> templates = new ArrayList<>();
|
||||
for (WechatSubscribeTemplateConfigEntity cfg : configs) {
|
||||
if (cfg == null || StringUtils.isBlank(cfg.getWechatTemplateId())) {
|
||||
continue;
|
||||
}
|
||||
WechatSubscribeAllScenesResp.StaticTemplateInfo info = new WechatSubscribeAllScenesResp.StaticTemplateInfo();
|
||||
info.setTemplateKey(cfg.getTemplateKey());
|
||||
info.setWechatTemplateId(cfg.getWechatTemplateId());
|
||||
info.setTitle(StringUtils.isNotBlank(cfg.getTitleTemplate()) ? cfg.getTitleTemplate() : cfg.getTemplateKey());
|
||||
info.setDescription(cfg.getDescription());
|
||||
templates.add(info);
|
||||
}
|
||||
sceneWithTemplates.setTemplates(templates);
|
||||
scenes.add(sceneWithTemplates);
|
||||
}
|
||||
resp.setScenes(scenes);
|
||||
return resp;
|
||||
}
|
||||
|
||||
// ==================== 带缓存的配置查询方法 ====================
|
||||
|
||||
/**
|
||||
@@ -386,6 +484,10 @@ public class WechatSubscribeNotifyConfigRepository {
|
||||
String eventPattern = String.format(EVENT_TEMPLATE_SCENIC_PREFIX, scenicId);
|
||||
deleteByPattern(eventPattern);
|
||||
|
||||
// 清除所有场景模板缓存
|
||||
String allScenesKey = String.format(ALL_SCENES_TEMPLATES_KEY, scenicId);
|
||||
redisTemplate.delete(allScenesKey);
|
||||
|
||||
log.info("清除景区所有订阅消息配置缓存: scenicId={}", scenicId);
|
||||
}
|
||||
|
||||
@@ -396,6 +498,7 @@ public class WechatSubscribeNotifyConfigRepository {
|
||||
public void clearAllConfigsCache() {
|
||||
deleteByPattern("wechat:subscribe:scene:configs:*");
|
||||
deleteByPattern("wechat:subscribe:event:configs:*");
|
||||
deleteByPattern("wechat:subscribe:all-scenes:configs:*");
|
||||
log.warn("清除所有订阅消息配置缓存");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user