From 5a8fe60c208e09d0f44ed10db7fc6fd399bd0f68 Mon Sep 17 00:00:00 2001 From: luofu Date: Tue, 17 Oct 2023 12:35:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(REQ-1465):=20=E6=B6=88=E6=81=AF=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E5=88=86=E9=A1=B5=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 背景: https://jira.axzo.cn/browse/REQ-1465?goToView=1 修改: 1、消息模板分页查询接口实现 影响: 无 --- .../controller/MessageTemplateController.java | 3 +- .../MessageGroupTreeNodeCacheServiceImpl.java | 11 +-- .../impl/MessageTemplateNewServiceImpl.java | 7 +- .../common/{utils => redis}/RedisUtil.java | 90 +++++++++---------- .../axzo/msg/center/RedisConfiguration.java | 50 +++++++++++ 5 files changed, 106 insertions(+), 55 deletions(-) rename msg-center-common/src/main/java/cn/axzo/msg/center/common/{utils => redis}/RedisUtil.java (84%) create mode 100644 start/src/main/java/cn/axzo/msg/center/RedisConfiguration.java diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java index 9fdc269d..789b0af5 100644 --- a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java +++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java @@ -47,8 +47,7 @@ public class MessageTemplateController implements MessageTemplateClient { @Override public CommonResponse> page(MessageTemplatePageRequest request) { - // TODO:[cold_blade] [P0] page query template - return null; + return CommonResponse.success(messageTemplateNewService.page(request)); } @Override diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java index 118de001..b9cdd89e 100644 --- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java +++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java @@ -2,7 +2,7 @@ package cn.axzo.msg.center.message.service.impl; import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.msg.center.common.enums.TableIsDeleteEnum; -import cn.axzo.msg.center.common.utils.RedisUtil; +import cn.axzo.msg.center.common.redis.RedisUtil; import cn.axzo.msg.center.dal.MessageGroupNodeDao; import cn.axzo.msg.center.domain.entity.MessageGroupNode; import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO; @@ -37,6 +37,7 @@ public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNod private static final String CACHE_VALUE = "msg-center:message:group:cache-val"; private static final long CACHE_KEY_TIMEOUT_DAYS = 1; + private final RedisUtil redisUtil; private final MessageGroupNodeDao messageGroupNodeDao; private List allGroupTreeRootNodesCache = Collections.emptyList(); @@ -84,7 +85,7 @@ public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNod @Override public void refreshCache() { // 清除redis中的缓存标识 - RedisUtil.KeyOps.delete(CACHE_KEY); + redisUtil.getKeyOps().delete(CACHE_KEY); // 清除本地缓存 allGroupTreeRootNodesCache = Collections.emptyList(); leafTreeNodePathsCache = Collections.emptyList(); @@ -107,7 +108,7 @@ public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNod } private List getAllGroupTreeRootNodesCache() { - if (RedisUtil.KeyOps.hasKey(CACHE_KEY)) { + if (redisUtil.getKeyOps().hasKey(CACHE_KEY)) { // 其它结点进行了本地缓存,但是当前服务进程还未进行缓存 if (CollectionUtils.isEmpty(allGroupTreeRootNodesCache)) { // 本地缓存初始化,不更新redis中的缓存标识 @@ -121,7 +122,7 @@ public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNod } private List getLeafTreeNodePathsCache() { - if (RedisUtil.KeyOps.hasKey(CACHE_KEY)) { + if (redisUtil.getKeyOps().hasKey(CACHE_KEY)) { // 其它结点进行了本地缓存,但是当前服务进程还未进行缓存 if (leafTreeNodePathsCache.isEmpty()) { // 本地缓存初始化,不更新redis中的缓存标识 @@ -141,7 +142,7 @@ public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNod .flatMap(e -> parseRootNode(e).stream()) .collect(Collectors.toList()); if (refreshCache) { - RedisUtil.StringOps.setIfAbsent(CACHE_KEY, CACHE_VALUE, CACHE_KEY_TIMEOUT_DAYS, TimeUnit.DAYS); + redisUtil.getStringOps().setIfAbsent(CACHE_KEY, CACHE_VALUE, CACHE_KEY_TIMEOUT_DAYS, TimeUnit.DAYS); } } diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java index d34241fd..e6a1d08f 100644 --- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java +++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java @@ -2,8 +2,8 @@ package cn.axzo.msg.center.message.service.impl; import cn.axzo.basics.common.util.AssertUtil; import cn.axzo.msg.center.common.enums.ServiceErrorCodeEnum; +import cn.axzo.msg.center.common.redis.RedisUtil; import cn.axzo.msg.center.common.utils.PageHelperUtil; -import cn.axzo.msg.center.common.utils.RedisUtil; import cn.axzo.msg.center.dal.MessageBaseTemplateDao; import cn.axzo.msg.center.domain.entity.MessageBaseTemplate; import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO; @@ -51,6 +51,7 @@ public class MessageTemplateNewServiceImpl implements MessageTemplateNewService private static final long TRY_LOCK_TIMEOUT_MILLS = 1000; private static final int RETRY_CNT_MAX = 3; + private final RedisUtil redisUtil; private final MessageBaseTemplateDao messageBaseTemplateDao; private final MessageGroupNodeService messageGroupNodeService; private final MessageTemplateGroupService messageTemplateGroupService; @@ -167,7 +168,7 @@ public class MessageTemplateNewServiceImpl implements MessageTemplateNewService String requestId = UUIDUtil.uuidRawString(); try { String opKey = String.format(SAVE_TEMPLATE_MUTEX_KEY, templateCode); - boolean lockResult = RedisUtil.LockOps.getLockUntilTimeout(opKey, requestId, TRY_LOCK_TIMEOUT_MILLS); + boolean lockResult = redisUtil.getLockOps().getLockUntilTimeout(opKey, requestId, TRY_LOCK_TIMEOUT_MILLS); AssertUtil.isTrue(lockResult, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc()); if (isTemplateExist(templateCode)) { return false; @@ -176,7 +177,7 @@ public class MessageTemplateNewServiceImpl implements MessageTemplateNewService messageBaseTemplateDao.save(template); return true; } finally { - RedisUtil.LockOps.releaseLock(SAVE_TEMPLATE_MUTEX_KEY, requestId); + redisUtil.getLockOps().releaseLock(SAVE_TEMPLATE_MUTEX_KEY, requestId); } } diff --git a/msg-center-common/src/main/java/cn/axzo/msg/center/common/utils/RedisUtil.java b/msg-center-common/src/main/java/cn/axzo/msg/center/common/redis/RedisUtil.java similarity index 84% rename from msg-center-common/src/main/java/cn/axzo/msg/center/common/utils/RedisUtil.java rename to msg-center-common/src/main/java/cn/axzo/msg/center/common/redis/RedisUtil.java index fe650fb1..ccc5b449 100644 --- a/msg-center-common/src/main/java/cn/axzo/msg/center/common/utils/RedisUtil.java +++ b/msg-center-common/src/main/java/cn/axzo/msg/center/common/redis/RedisUtil.java @@ -1,15 +1,16 @@ -package cn.axzo.msg.center.common.utils; +package cn.axzo.msg.center.common.redis; -import cn.hutool.extra.spring.SpringUtil; import lombok.AccessLevel; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; import java.time.Instant; @@ -22,23 +23,25 @@ import java.util.concurrent.TimeUnit; * @version 1.0 */ @Slf4j -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class RedisUtil implements InitializingBean { +@Getter +@Component +@RequiredArgsConstructor +public class RedisUtil { /** * 使用StringRedisTemplate(,其是RedisTemplate的定制化升级) */ - private static StringRedisTemplate redisTemplate; + private final StringRedisTemplate redisTemplate; - @Override - public void afterPropertiesSet() throws Exception { - RedisUtil.redisTemplate = SpringUtil.getBean(StringRedisTemplate.class); - } + private final KeyOps keyOps = new KeyOps(); + private final StringOps stringOps = new StringOps(); + private final LockOps lockOps = new LockOps(); /** * key相关操作 */ - public static class KeyOps { + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public class KeyOps { /** * 根据key, 删除redis中的对应key-value @@ -50,7 +53,7 @@ public final class RedisUtil implements InitializingBean { * @param key 要删除的key * @return 删除是否成功 */ - public static Boolean delete(String key) { + public Boolean delete(String key) { log.info("delete(...) => key= {}", key); // 返回值只可能为true/false, 不可能为null Boolean result = redisTemplate.delete(key); @@ -72,7 +75,7 @@ public final class RedisUtil implements InitializingBean { * 要删除的key集合 * @return 删除了的key-value个数 */ - public static Long delete(Collection keys) { + public Long delete(Collection keys) { log.info("delete(...) => keys= {}", keys); Long count = redisTemplate.delete(keys); log.info("delete(...) => count= {}", count); @@ -88,7 +91,7 @@ public final class RedisUtil implements InitializingBean { * @param key 指定的key * @return 是否存在对应的key-value */ - public static Boolean hasKey(String key) { + public Boolean hasKey(String key) { log.info("hasKey(...) => key= {}", key); Boolean result = redisTemplate.hasKey(key); log.info("hasKey(...) => result= {}", result); @@ -109,7 +112,7 @@ public final class RedisUtil implements InitializingBean { * @param unit timeout的单位 * @return 操作是否成功 */ - public static Boolean expire(String key, Long timeout, TimeUnit unit) { + public Boolean expire(String key, Long timeout, TimeUnit unit) { log.info("expire(...) => key= {}, timeout= {}, unit= {}", key, timeout, unit); Boolean result = redisTemplate.expire(key, timeout, unit); log.info("expire(...) => result is= {}", result); @@ -126,7 +129,8 @@ public final class RedisUtil implements InitializingBean { * 提示: redis中String的数据结构可参考resources/data-structure/String(字符串)的数据结构(示例一).png * redis中String的数据结构可参考resources/data-structure/String(字符串)的数据结构(示例二).png */ - public static class StringOps { + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public class StringOps { /** * 设置key-value @@ -135,7 +139,7 @@ public final class RedisUtil implements InitializingBean { * @param key key * @param value key对应的value */ - public static void set(String key, String value) { + public void set(String key, String value) { log.info("set(...) => key= {}, value= {}", key, value); redisTemplate.opsForValue().set(key, value); } @@ -149,7 +153,7 @@ public final class RedisUtil implements InitializingBean { * @param timeout 过时时长 * @param unit timeout的单位 */ - public static void setEx(String key, String value, Long timeout, TimeUnit unit) { + public void setEx(String key, String value, Long timeout, TimeUnit unit) { log.info("setEx(...) => key= {}, value= {}, timeout= {}, unit= {}", key, value, timeout, unit); redisTemplate.opsForValue().set(key, value, timeout, unit); } @@ -163,7 +167,7 @@ public final class RedisUtil implements InitializingBean { * * @return set是否成功 */ - public static Boolean setIfAbsent(String key, String value) { + public Boolean setIfAbsent(String key, String value) { log.info("setIfAbsent(...) => key= {}, value= {}", key, value); Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value); log.info("setIfAbsent(...) => result= {}", result); @@ -184,7 +188,7 @@ public final class RedisUtil implements InitializingBean { * * @return set是否成功 */ - public static Boolean setIfAbsent(String key, String value, Long timeout, TimeUnit unit) { + public Boolean setIfAbsent(String key, String value, Long timeout, TimeUnit unit) { log.info("setIfAbsent(...) => key= {}, value= {}, key= {}, value= {}", key, value, timeout, unit); Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit); log.info("setIfAbsent(...) => result= {}", result); @@ -201,7 +205,7 @@ public final class RedisUtil implements InitializingBean { * @param key key-value对应的key * @return 该key对应的值。 */ - public static String get(String key) { + public String get(String key) { log.info("get(...) => key= {}", key); String result = redisTemplate.opsForValue().get(key); log.info("get(...) => result= {} ", result); @@ -233,26 +237,22 @@ public final class RedisUtil implements InitializingBean { * } * } */ - public static class LockOps { + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public class LockOps { /** lua脚本, 保证 释放锁脚本 的原子性(以避免, 并发场景下, 释放了别人的锁) */ - private static final String RELEASE_LOCK_LUA; + private final String RELEASE_LOCK_LUA = "if redis.call('get',KEYS[1]) == ARGV[1] " + + "then " + + " return redis.call('del',KEYS[1]) " + + "else " + + " return 0 " + + "end "; /** 分布式锁默认(最大)存活时长 */ - public static final long DEFAULT_LOCK_TIMEOUT = 3; + public final long DEFAULT_LOCK_TIMEOUT = 3; /** DEFAULT_LOCK_TIMEOUT的单位 */ - public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS; - - static { - // 不论lua中0是否代表失败; 对于java的Boolean而言, 返回0, 则会被解析为false - RELEASE_LOCK_LUA = "if redis.call('get',KEYS[1]) == ARGV[1] " - + "then " - + " return redis.call('del',KEYS[1]) " - + "else " - + " return 0 " - + "end "; - } + public final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS; /** * 获取(分布式)锁. @@ -260,7 +260,7 @@ public final class RedisUtil implements InitializingBean { * * @see LockOps#getLock(String, String, Long, TimeUnit) */ - public static Boolean getLock(final String key, final String value) { + public Boolean getLock(final String key, final String value) { return getLock(key, value, DEFAULT_LOCK_TIMEOUT, DEFAULT_TIMEOUT_UNIT); } @@ -276,7 +276,7 @@ public final class RedisUtil implements InitializingBean { * * @return 是否成功 */ - public static Boolean getLockUntilTimeout(final String key, final String value, final Long retryTimeoutLimit) { + public Boolean getLockUntilTimeout(final String key, final String value, final Long retryTimeoutLimit) { return getLockUntilTimeout(key, value, DEFAULT_LOCK_TIMEOUT, DEFAULT_TIMEOUT_UNIT, retryTimeoutLimit); } @@ -293,9 +293,9 @@ public final class RedisUtil implements InitializingBean { * * @return 是否成功 */ - public static Boolean getLockUntilTimeout(final String key, final String value, - final Long timeout, final TimeUnit unit, - final Long retryTimeoutLimit) { + public Boolean getLockUntilTimeout(final String key, final String value, + final Long timeout, final TimeUnit unit, + final Long retryTimeoutLimit) { log.info("getLockUntilTimeout(...) => key= {}, value= {}, timeout= {}, unit= {}, " + "retryTimeoutLimit= {}ms", key, value, timeout, unit, retryTimeoutLimit); long startTime = Instant.now().toEpochMilli(); @@ -322,7 +322,7 @@ public final class RedisUtil implements InitializingBean { * * @see LockOps#getLock(String, String, Long, TimeUnit, Boolean) */ - public static Boolean getLock(final String key, final String value, final Long timeout, final TimeUnit unit) { + public Boolean getLock(final String key, final String value, final Long timeout, final TimeUnit unit) { return getLock(key, value, timeout, unit, true); } @@ -347,9 +347,9 @@ public final class RedisUtil implements InitializingBean { * * @return 是否成功 */ - public static Boolean getLock(final String key, final String value, - final Long timeout, final TimeUnit unit, - Boolean recordLog) { + public Boolean getLock(final String key, final String value, + final Long timeout, final TimeUnit unit, + Boolean recordLog) { if (recordLog) { log.info("getLock(...) => key= {}, value= {}, timeout= {}, unit= {}, recordLog= {}", key, value, timeout, unit, recordLog); @@ -379,7 +379,7 @@ public final class RedisUtil implements InitializingBean { * * @return 释放锁是否成功 */ - public static Boolean releaseLock(final String key, final String value) { + public Boolean releaseLock(final String key, final String value) { log.info("releaseLock(...) => key= {}, lockValue= {}", key, value); Boolean result = redisTemplate.execute((RedisConnection connection) -> connection.eval(RELEASE_LOCK_LUA.getBytes(), diff --git a/start/src/main/java/cn/axzo/msg/center/RedisConfiguration.java b/start/src/main/java/cn/axzo/msg/center/RedisConfiguration.java new file mode 100644 index 00000000..453472d7 --- /dev/null +++ b/start/src/main/java/cn/axzo/msg/center/RedisConfiguration.java @@ -0,0 +1,50 @@ +package cn.axzo.msg.center; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * @author cold_blade + * @date 2023/10/17 + * @version 1.0 + */ +@Configuration +public class RedisConfiguration { + + @Bean + public RedisSerializer redisKeySerializer() { + return new StringRedisSerializer(); + } + + @Bean + public RedisSerializer redisValueSerializer() { + return new StringRedisSerializer(); + } + + /** + * RedisTemplate配置 + */ + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory, + RedisSerializer redisKeySerializer, + RedisSerializer redisValueSerializer) { + StringRedisTemplate redisTemplate = new StringRedisTemplate(); + redisTemplate.setConnectionFactory(factory); + + //设置Key的序列化采用StringRedisSerializer + redisTemplate.setKeySerializer(redisKeySerializer); + redisTemplate.setHashKeySerializer(redisKeySerializer); + + //设置值的序列化 + redisTemplate.setValueSerializer(redisValueSerializer); + redisTemplate.setHashValueSerializer(redisValueSerializer); + + redisTemplate.afterPropertiesSet(); + + return redisTemplate; + } +}