Merge branch 'feature/REQ-1465' of axzsource.com:universal/infrastructure/backend/msg-center-plat into dev

This commit is contained in:
luofu 2023-10-17 12:35:53 +08:00
commit 72d1a564f9
5 changed files with 106 additions and 55 deletions

View File

@ -47,8 +47,7 @@ public class MessageTemplateController implements MessageTemplateClient {
@Override
public CommonResponse<Page<MessageTemplatePageResponse>> page(MessageTemplatePageRequest request) {
// TODO:[cold_blade] [P0] page query template
return null;
return CommonResponse.success(messageTemplateNewService.page(request));
}
@Override

View File

@ -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<GroupTreeNodeDTO> 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<GroupTreeNodeDTO> 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<GroupTreeNodePathDTO> 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);
}
}

View File

@ -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);
}
}

View File

@ -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<String> keys) {
public Long delete(Collection<String> 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(),

View File

@ -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<String> redisKeySerializer() {
return new StringRedisSerializer();
}
@Bean
public RedisSerializer<String> redisValueSerializer() {
return new StringRedisSerializer();
}
/**
* RedisTemplate配置
*/
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory,
RedisSerializer<String> redisKeySerializer,
RedisSerializer<String> 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;
}
}