ci: 模块名变更
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.jero.boot</groupId>
|
||||
<artifactId>kh-base</artifactId>
|
||||
<version>2.5.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<description>公共模块</description>
|
||||
<artifactId>kh-base-tools</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!--集成springmvc框架 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<!--加载hutool-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
<!--加载beanutils-->
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.jero.common.annotation;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @Author:zyf
|
||||
* @Date:2019-07-31 10:43
|
||||
* @Description: 消息队列初始化注解
|
||||
**/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Component
|
||||
public @interface RabbitComponent {
|
||||
@AliasFor(
|
||||
annotation = Component.class
|
||||
)
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.jero.common.base;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
|
||||
import org.apache.commons.beanutils.ConvertUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 自定义Map
|
||||
*/
|
||||
public class BaseMap extends HashMap<String, Object> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
public BaseMap() {
|
||||
|
||||
}
|
||||
|
||||
public BaseMap(Map<String, Object> map) {
|
||||
this.putAll(map);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BaseMap put(String key, Object value) {
|
||||
super.put(key, Optional.ofNullable(value).orElse(""));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseMap add(String key, Object value) {
|
||||
this.put(key,value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key) {
|
||||
Object obj = super.get(key);
|
||||
if (ObjectUtil.isNotEmpty(obj)) {
|
||||
return (T) obj;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Boolean getBoolean(String key) {
|
||||
Object obj = super.get(key);
|
||||
if (ObjectUtil.isNotEmpty(obj)) {
|
||||
return Boolean.valueOf(obj.toString());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Long getLong(String key) {
|
||||
Object v = get(key);
|
||||
if (ObjectUtil.isNotEmpty(v)) {
|
||||
return new Long(v.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Long[] getLongs(String key) {
|
||||
Object v = get(key);
|
||||
if (ObjectUtil.isNotEmpty(v)) {
|
||||
return (Long[]) v;
|
||||
}
|
||||
return new Long[0];
|
||||
}
|
||||
|
||||
public List<Long> getListLong(String key) {
|
||||
List<String> list = get(key);
|
||||
if (ObjectUtil.isNotEmpty(list)) {
|
||||
return list.stream().map(Long::new).collect(Collectors.toList());
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public Long[] getLongIds(String key) {
|
||||
Object ids = get(key);
|
||||
if (ObjectUtil.isNotEmpty(ids)) {
|
||||
return (Long[]) ConvertUtils.convert(ids.toString().split(","), Long.class);
|
||||
} else {
|
||||
return new Long[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Integer getInt(String key, Integer def) {
|
||||
Object v = get(key);
|
||||
if (ObjectUtil.isNotEmpty(v)) {
|
||||
return Integer.parseInt(v.toString());
|
||||
} else {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getInt(String key) {
|
||||
Object v = get(key);
|
||||
if (ObjectUtil.isNotEmpty(v)) {
|
||||
return Integer.parseInt(v.toString());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal getBigDecimal(String key) {
|
||||
Object v = get(key);
|
||||
if (ObjectUtil.isNotEmpty(v)) {
|
||||
return new BigDecimal(v.toString());
|
||||
}
|
||||
return new BigDecimal("0");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key, T def) {
|
||||
Object obj = super.get(key);
|
||||
if (ObjectUtil.isEmpty(obj)) {
|
||||
return def;
|
||||
}
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
public static BaseMap toBaseMap(Map<String, Object> obj) {
|
||||
BaseMap map = new BaseMap();
|
||||
map.putAll(obj);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.jero.common.config;
|
||||
|
||||
import com.jero.common.util.SpringContextHolder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class CommonConfig {
|
||||
|
||||
/**
|
||||
* Spring上下文工具配置
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SpringContextHolder.class)
|
||||
public SpringContextHolder springContextHolder() {
|
||||
return new SpringContextHolder();
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.jero.common.config.mqtoken;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 存放token到上下文供队列调用feign使用
|
||||
* @author zyf
|
||||
*/
|
||||
public class TransmitUserTokenFilter implements Filter {
|
||||
|
||||
private static final String X_ACCESS_TOKEN = "X-Access-Token";
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
// do other
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
this.initUserInfo((HttpServletRequest) request);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private void initUserInfo(HttpServletRequest request) {
|
||||
String token = request.getHeader(X_ACCESS_TOKEN);
|
||||
if (token!=null) {
|
||||
try {
|
||||
//将token放入上下文中
|
||||
UserTokenContext.setToken(token);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// do other
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.jero.common.config.mqtoken;
|
||||
|
||||
|
||||
/**
|
||||
* 用户token上下文
|
||||
* @author zyf
|
||||
*/
|
||||
public class UserTokenContext {
|
||||
|
||||
private UserTokenContext(){
|
||||
|
||||
}
|
||||
|
||||
private static ThreadLocal<String> userToken = new ThreadLocal<>();
|
||||
|
||||
public static String getToken(){
|
||||
return userToken.get();
|
||||
}
|
||||
|
||||
public static void setToken(String token){
|
||||
userToken.set(token);
|
||||
}
|
||||
|
||||
public static void delToken(){
|
||||
userToken.remove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.jero.common.constant;
|
||||
|
||||
/**
|
||||
* @author: huangxutao
|
||||
* @date: 2019-06-14
|
||||
* @description: 缓存常量
|
||||
*/
|
||||
public class CacheConstant {
|
||||
|
||||
private CacheConstant(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典信息缓存(含禁用的字典项)
|
||||
*/
|
||||
public static final String SYS_DICT_CACHE = "sys:cache:dict";
|
||||
|
||||
/**
|
||||
* 字典信息缓存 status为有效的
|
||||
*/
|
||||
public static final String SYS_ENABLE_DICT_CACHE = "sys:cache:dictEnable";
|
||||
/**
|
||||
* 表字典信息缓存
|
||||
*/
|
||||
public static final String SYS_DICT_TABLE_CACHE = "sys:cache:dictTable";
|
||||
public static final String SYS_DICT_TABLE_BY_KEYS_CACHE = SYS_DICT_TABLE_CACHE + "ByKeys";
|
||||
|
||||
/**
|
||||
* 数据权限配置缓存
|
||||
*/
|
||||
public static final String SYS_DATA_PERMISSIONS_CACHE = "sys:cache:permission:datarules";
|
||||
|
||||
/**
|
||||
* 缓存用户信息
|
||||
*/
|
||||
public static final String SYS_USERS_CACHE = "sys:cache:user";
|
||||
|
||||
/**
|
||||
* 全部部门信息缓存
|
||||
*/
|
||||
public static final String SYS_DEPARTS_CACHE = "sys:cache:depart:alldata";
|
||||
|
||||
|
||||
/**
|
||||
* 全部部门ids缓存
|
||||
*/
|
||||
public static final String SYS_DEPART_IDS_CACHE = "sys:cache:depart:allids";
|
||||
|
||||
|
||||
/**
|
||||
* 测试缓存key
|
||||
*/
|
||||
public static final String TEST_DEMO_CACHE = "test:demo";
|
||||
|
||||
/**
|
||||
* 字典信息缓存
|
||||
*/
|
||||
public static final String SYS_DYNAMICDB_CACHE = "sys:cache:dbconnect:dynamic:";
|
||||
|
||||
/**
|
||||
* gateway路由缓存
|
||||
*/
|
||||
public static final String GATEWAY_ROUTES = "gateway_routes";
|
||||
|
||||
|
||||
/**
|
||||
* gateway路由 reload key
|
||||
*/
|
||||
public static final String ROUTE_JVM_RELOAD_TOPIC = "gateway_jvm_route_reload_topic";
|
||||
|
||||
/**
|
||||
* 冗余代码 待删除
|
||||
*插件商城排行榜
|
||||
*/
|
||||
public static final String PLUGIN_MALL_RANKING = "pluginMall::rankingList";
|
||||
/**
|
||||
* 冗余代码 待删除
|
||||
*插件商城排行榜
|
||||
*/
|
||||
public static final String PLUGIN_MALL_PAGE_LIST = "pluginMall::queryPageList";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.jero.common.constant;
|
||||
|
||||
public class GlobalConstants {
|
||||
|
||||
private GlobalConstants(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务处理器beanName传递参数
|
||||
*/
|
||||
public static final String HANDLER_NAME = "handlerName";
|
||||
|
||||
/**
|
||||
* redis消息通道名称
|
||||
*/
|
||||
public static final String REDIS_TOPIC_NAME="jero_redis_topic";
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.jero.common.modules.redis.client;
|
||||
|
||||
import com.jero.common.base.BaseMap;
|
||||
import com.jero.common.constant.GlobalConstants;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* redis客户端
|
||||
*/
|
||||
@Configuration
|
||||
public class JeroRedisClient {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param handlerName
|
||||
* @param params
|
||||
*/
|
||||
public void sendMessage(String handlerName, BaseMap params) {
|
||||
params.put(GlobalConstants.HANDLER_NAME, handlerName);
|
||||
redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package com.jero.common.modules.redis.config;
|
||||
|
||||
import com.jero.common.constant.CacheConstant;
|
||||
import com.jero.common.constant.GlobalConstants;
|
||||
import com.jero.common.modules.redis.receiver.RedisReceiver;
|
||||
import com.jero.common.modules.redis.writer.JeroRedisCacheWriter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
/**
|
||||
* 开启缓存支持
|
||||
* @author zyf
|
||||
* @Return:
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableCaching
|
||||
@Configuration
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Resource
|
||||
private LettuceConnectionFactory lettuceConnectionFactory;
|
||||
|
||||
private GenericJackson2JsonRedisSerializer jacksonSerializer = new GenericJackson2JsonRedisSerializer();
|
||||
|
||||
/**
|
||||
* RedisTemplate配置
|
||||
* @param lettuceConnectionFactory
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
|
||||
log.info(" --- redis config init --- ");
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
|
||||
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
|
||||
|
||||
// key序列化
|
||||
redisTemplate.setKeySerializer(stringSerializer);
|
||||
// value序列化
|
||||
redisTemplate.setValueSerializer(this.jacksonSerializer);
|
||||
// Hash key序列化
|
||||
redisTemplate.setHashKeySerializer(stringSerializer);
|
||||
// Hash value序列化
|
||||
redisTemplate.setHashValueSerializer(this.jacksonSerializer);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存配置管理器
|
||||
*
|
||||
* @param factory
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public CacheManager cacheManager(LettuceConnectionFactory factory) {
|
||||
// 配置序列化(解决乱码的问题),并且配置缓存默认有效期 6小时
|
||||
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(6));
|
||||
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(this.jacksonSerializer));
|
||||
|
||||
// 以锁写入的方式创建RedisCacheWriter对象
|
||||
//update-begin-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*
|
||||
RedisCacheWriter writer = new JeroRedisCacheWriter(factory, Duration.ofMillis(50L));
|
||||
// 创建默认缓存配置对象
|
||||
return RedisCacheManager.builder(writer).cacheDefaults(redisCacheConfiguration)
|
||||
.withInitialCacheConfigurations(singletonMap(CacheConstant.SYS_DICT_TABLE_CACHE, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)).disableCachingNullValues().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(this.jacksonSerializer))))
|
||||
.transactionAware().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* redis 监听配置
|
||||
*
|
||||
* @param redisConnectionFactory redis 配置
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory, RedisReceiver redisReceiver, MessageListenerAdapter commonListenerAdapter) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(redisConnectionFactory);
|
||||
container.addMessageListener(commonListenerAdapter, new ChannelTopic(GlobalConstants.REDIS_TOPIC_NAME));
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
MessageListenerAdapter commonListenerAdapter(RedisReceiver redisReceiver) {
|
||||
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "onMessage");
|
||||
messageListenerAdapter.setSerializer(this.jacksonSerializer);
|
||||
return messageListenerAdapter;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.jero.common.modules.redis.listener;
|
||||
|
||||
import com.jero.common.base.BaseMap;
|
||||
|
||||
/**
|
||||
* 自定义消息监听
|
||||
*/
|
||||
public interface JeroRedisListerer {
|
||||
|
||||
void onMessage(BaseMap message);
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.jero.common.modules.redis.receiver;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.jero.common.modules.redis.listener.JeroRedisListerer;
|
||||
import lombok.Data;
|
||||
import com.jero.common.base.BaseMap;
|
||||
import com.jero.common.constant.GlobalConstants;
|
||||
import com.jero.common.util.SpringContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author zyf
|
||||
*/
|
||||
@Component
|
||||
@Data
|
||||
public class RedisReceiver {
|
||||
|
||||
|
||||
/**
|
||||
* 接受消息并调用业务逻辑处理器
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
public void onMessage(BaseMap params) {
|
||||
Object handlerName = params.get(GlobalConstants.HANDLER_NAME);
|
||||
JeroRedisListerer messageListener = SpringContextHolder.getHandler(handlerName.toString(), JeroRedisListerer.class);
|
||||
if (ObjectUtil.isNotEmpty(messageListener)) {
|
||||
messageListener.onMessage(params);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
package com.jero.common.modules.redis.writer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 该类参照 DefaultRedisCacheWriter 重写了 remove 方法实现通配符*删除
|
||||
*/
|
||||
@Slf4j
|
||||
public class JeroRedisCacheWriter implements RedisCacheWriter {
|
||||
|
||||
private static final String NAME_MUST_NOT_BE_NULL = "Name must not be null!";
|
||||
private static final String KEY_MUST_NOT_BE_NULL = "Key must not be null!";
|
||||
|
||||
|
||||
private final RedisConnectionFactory connectionFactory;
|
||||
private final Duration sleepTime;
|
||||
|
||||
public JeroRedisCacheWriter(RedisConnectionFactory connectionFactory) {
|
||||
this(connectionFactory, Duration.ZERO);
|
||||
}
|
||||
|
||||
public JeroRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {
|
||||
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
|
||||
Assert.notNull(sleepTime, "SleepTime must not be null!");
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.sleepTime = sleepTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
|
||||
Assert.notNull(name, NAME_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(key, KEY_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
this.execute(name, connection -> {
|
||||
if (shouldExpireWithin(ttl)) {
|
||||
connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
|
||||
} else {
|
||||
connection.set(key, value);
|
||||
}
|
||||
|
||||
return "OK";
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String name, byte[] key) {
|
||||
Assert.notNull(name, NAME_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(key, KEY_MUST_NOT_BE_NULL);
|
||||
return this.execute(name, connection -> connection.get(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
|
||||
Assert.notNull(name, NAME_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(key, KEY_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return this.execute(name, connection -> {
|
||||
if (this.isLockingCacheWriter()) {
|
||||
this.doLock(name, connection);
|
||||
}
|
||||
|
||||
Object var7;
|
||||
try {
|
||||
boolean put;
|
||||
if (shouldExpireWithin(ttl)) {
|
||||
put = connection.set(key, value, Expiration.from(ttl), SetOption.ifAbsent());
|
||||
} else {
|
||||
put = connection.setNX(key, value);
|
||||
}
|
||||
|
||||
if (!put) {
|
||||
return connection.get(key);
|
||||
}
|
||||
|
||||
var7 = null;
|
||||
} finally {
|
||||
if (this.isLockingCacheWriter()) {
|
||||
this.doUnlock(name, connection);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (byte[])var7;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String name, byte[] key) {
|
||||
Assert.notNull(name, NAME_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(key, KEY_MUST_NOT_BE_NULL);
|
||||
String keyString = new String(key);
|
||||
log.info("redis remove key:" + keyString);
|
||||
if(keyString.endsWith("*")){
|
||||
execute(name, connection -> {
|
||||
// 获取某个前缀所拥有的所有的键,某个前缀开头,后面肯定是*
|
||||
Set<byte[]> keys = connection.keys(key);
|
||||
int delNum = 0;
|
||||
for (byte[] keyByte : keys) {
|
||||
delNum += connection.del(keyByte);
|
||||
}
|
||||
return delNum;
|
||||
});
|
||||
}else{
|
||||
this.execute(name, connection -> connection.del(new byte[][]{key}));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean(String name, byte[] pattern) {
|
||||
Assert.notNull(name, NAME_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(pattern, "Pattern must not be null!");
|
||||
this.execute(name, connection -> {
|
||||
boolean wasLocked = false;
|
||||
|
||||
try {
|
||||
if (this.isLockingCacheWriter()) {
|
||||
this.doLock(name, connection);
|
||||
wasLocked = true;
|
||||
}
|
||||
|
||||
byte[][] keys = (byte[][])((Set)Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())).toArray(new byte[0][]);
|
||||
if (keys.length > 0) {
|
||||
connection.del(keys);
|
||||
}
|
||||
} finally {
|
||||
if (wasLocked && this.isLockingCacheWriter()) {
|
||||
this.doUnlock(name, connection);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return "OK";
|
||||
});
|
||||
}
|
||||
|
||||
void lock(String name) {
|
||||
this.execute(name, connection -> this.doLock(name, connection));
|
||||
}
|
||||
|
||||
void unlock(String name) {
|
||||
this.executeLockFree(connection -> this.doUnlock(name, connection));
|
||||
}
|
||||
|
||||
private Boolean doLock(String name, RedisConnection connection) {
|
||||
return connection.setNX(createCacheLockKey(name), new byte[0]);
|
||||
}
|
||||
|
||||
private Long doUnlock(String name, RedisConnection connection) {
|
||||
return connection.del(new byte[][]{createCacheLockKey(name)});
|
||||
}
|
||||
|
||||
boolean doCheckLock(String name, RedisConnection connection) {
|
||||
return connection.exists(createCacheLockKey(name));
|
||||
}
|
||||
|
||||
private boolean isLockingCacheWriter() {
|
||||
return !this.sleepTime.isZero() && !this.sleepTime.isNegative();
|
||||
}
|
||||
|
||||
private <T> T execute(String name, Function<RedisConnection, T> callback) {
|
||||
RedisConnection connection = this.connectionFactory.getConnection();
|
||||
|
||||
try {
|
||||
this.checkAndPotentiallyWaitUntilUnlocked(name, connection);
|
||||
return callback.apply(connection);
|
||||
} finally {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void executeLockFree(Consumer<RedisConnection> callback) {
|
||||
RedisConnection connection = this.connectionFactory.getConnection();
|
||||
|
||||
try {
|
||||
callback.accept(connection);
|
||||
} finally {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
|
||||
if (this.isLockingCacheWriter()) {
|
||||
try {
|
||||
while(this.doCheckLock(name, connection)) {
|
||||
Thread.sleep(this.sleepTime.toMillis());
|
||||
}
|
||||
|
||||
} catch (InterruptedException var4) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name), var4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldExpireWithin(@Nullable Duration ttl) {
|
||||
return ttl != null && !ttl.isZero() && !ttl.isNegative();
|
||||
}
|
||||
|
||||
private static byte[] createCacheLockKey(String name) {
|
||||
return (name + "~lock").getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,647 @@
|
||||
package com.jero.common.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* redis 工具类
|
||||
* @Author Scott
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class RedisUtil {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
@Autowired
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean expire(String key, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据key 获取过期时间
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @return 时间(秒) 返回0代表为永久有效
|
||||
*/
|
||||
public long getExpire(String key) {
|
||||
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
*
|
||||
* @param key 可以传一个值 或多个
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void del(String... key) {
|
||||
if (key != null && key.length > 0) {
|
||||
if (key.length == 1) {
|
||||
redisTemplate.delete(key[0]);
|
||||
} else {
|
||||
redisTemplate.delete(CollectionUtils.arrayToList(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================String=============================
|
||||
/**
|
||||
* 普通缓存获取
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean set(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public boolean set(String key, Object value, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递增
|
||||
*
|
||||
* @param key 键
|
||||
* @param by 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public long incr(String key, long delta) {
|
||||
if (delta < 0) {
|
||||
throw new IllegalArgumentException("递增因子必须大于0");
|
||||
}
|
||||
return redisTemplate.opsForValue().increment(key, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递减
|
||||
*
|
||||
* @param key 键
|
||||
* @param by 要减少几(小于0)
|
||||
* @return
|
||||
*/
|
||||
public long decr(String key, long delta) {
|
||||
if (delta < 0) {
|
||||
throw new IllegalArgumentException("递减因子必须大于0");
|
||||
}
|
||||
return redisTemplate.opsForValue().increment(key, -delta);
|
||||
}
|
||||
|
||||
// ================================Map=================================
|
||||
/**
|
||||
* HashGet
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return 值
|
||||
*/
|
||||
public Object hget(String key, String item) {
|
||||
return redisTemplate.opsForHash().get(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取hashKey对应的所有键值
|
||||
*
|
||||
* @param key 键
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public Map<Object, Object> hmget(String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet 并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @param time 时间(秒)
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除hash表中的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 可以使多个 不能为null
|
||||
*/
|
||||
public void hdel(String key, Object... item) {
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断hash表中是否有该项的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hHasKey(String key, String item) {
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public double hincr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递减
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要减少记(小于0)
|
||||
* @return
|
||||
*/
|
||||
public double hdecr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
|
||||
// ============================set=============================
|
||||
/**
|
||||
* 根据key获取Set中的所有值
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> sGet(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据value从一个set中查询,是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean sHasKey(String key, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据放入set缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSet(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将set数据放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSetAndTime(String key, long time, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().add(key, values);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取set缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long sGetSetSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除值为value的
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long setRemove(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().remove(key, values);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// ===============================list=================================
|
||||
|
||||
/**
|
||||
* 获取list缓存的内容
|
||||
*
|
||||
* @param key 键
|
||||
* @param start 开始
|
||||
* @param end 结束 0 到 -1代表所有值
|
||||
* @return
|
||||
*/
|
||||
public List<Object> lGet(String key, long start, long end) {
|
||||
try {
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取list缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long lGetListSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForList().size(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过索引 获取list中的值
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
|
||||
* @return
|
||||
*/
|
||||
public Object lGetIndex(String key, long index) {
|
||||
try {
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引修改list中的某条数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lUpdateIndex(String key, long index, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除N个值为value
|
||||
*
|
||||
* @param key 键
|
||||
* @param count 移除多少个
|
||||
* @param value 值
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long lRemove(String key, long count, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForList().remove(key, count, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定前缀的一系列key
|
||||
* 使用scan命令代替keys, Redis是单线程处理,keys命令在KEY数量较多时,
|
||||
* 操作效率极低【时间复杂度为O(N)】,该命令一旦执行会严重阻塞线上其它命令的正常请求
|
||||
* @param keyPrefix
|
||||
* @return
|
||||
*/
|
||||
private Set<String> keys(String keyPrefix) {
|
||||
String realKey = keyPrefix + "*";
|
||||
|
||||
try {
|
||||
return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
|
||||
Set<String> binaryKeys = new HashSet<>();
|
||||
Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(realKey).count(Integer.MAX_VALUE).build());
|
||||
while (cursor.hasNext()) {
|
||||
binaryKeys.add(new String(cursor.next()));
|
||||
}
|
||||
|
||||
return binaryKeys;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定前缀的一系列key
|
||||
* @param keyPrefix
|
||||
*/
|
||||
public void removeAll(String keyPrefix) {
|
||||
try {
|
||||
Set<String> keys = keys(keyPrefix);
|
||||
if(keys == null){
|
||||
return;
|
||||
}
|
||||
redisTemplate.delete(keys);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setnx
|
||||
*/
|
||||
public boolean setnx(String key, String value) {
|
||||
try {
|
||||
return redisTemplate.opsForValue().setIfAbsent(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setnx
|
||||
*/
|
||||
public boolean setnx(String key, String value,long time) {
|
||||
try {
|
||||
return redisTemplate.opsForValue().setIfAbsent(key,value, Duration.ofSeconds(time));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* eval
|
||||
*/
|
||||
public Boolean eval(RedisScript<Long> luaScripts, List<String> keys, String values) {
|
||||
Long flag = redisTemplate.execute(luaScripts, keys, values);
|
||||
//判断是不是为1
|
||||
return flag == 1L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
package com.jero.common.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.
|
||||
*
|
||||
* @author zyf
|
||||
*/
|
||||
@Slf4j
|
||||
public class SpringContextHolder implements ApplicationContextAware {
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
synchronized (SpringContextHolder.class){
|
||||
if(SpringContextHolder.applicationContext == null){
|
||||
// NOSONAR
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得存储在静态变量中的ApplicationContext.
|
||||
*/
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
checkApplicationContext();
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(String name) {
|
||||
checkApplicationContext();
|
||||
return (T) applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getHandler(String name, Class<T> cls) {
|
||||
T t = null;
|
||||
if (ObjectUtil.isNotEmpty(name)) {
|
||||
checkApplicationContext();
|
||||
try {
|
||||
t = applicationContext.getBean(name, cls);
|
||||
} catch (Exception e) {
|
||||
log.error("####################" + name + "未定义");
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(Class<T> clazz) {
|
||||
checkApplicationContext();
|
||||
return applicationContext.getBean(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除applicationContext静态变量.
|
||||
*/
|
||||
public static void cleanApplicationContext() {
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
private static void checkApplicationContext() {
|
||||
if (applicationContext == null) {
|
||||
throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user