From ab4215a25b70d1a5d313d73dc0367ef87f0b91bc Mon Sep 17 00:00:00 2001 From: Administrator Date: Tue, 27 Oct 2020 17:44:20 +0800 Subject: [PATCH] =?UTF-8?q?redis=20=E5=A2=9E=E5=8A=A0=E4=BA=86=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=B0=81=E8=A3=85=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mall-ebtp-cloud-jpa-starter/pom.xml | 4 - .../cloud/jpa/starter/CommonConstants.java | 13 + .../jpa/starter/JpaStarterConfiguration.java | 58 + .../resoureces/jpa-configuration.properties | 10 + mall-ebtp-cloud-redis-starter/pom.xml | 29 + .../starter/config/JsonRedisSerializer.java | 90 ++ .../config/RedisAutoConfiguration.java | 56 + .../config/RedisConnectionConfiguration.java | 182 +++ .../starter/config/RedisInitializer.java | 20 + .../config/RedisInitializerPostProcessor.java | 33 + .../config/cache/RedisCacheConfiguration.java | 82 + .../jedis/JedisConnectionConfiguration.java | 107 ++ .../LettuceConnectionConfiguration.java | 126 ++ .../config/lettuce/LettuceTypeHint.java | 312 ++++ .../redisson/RedissonAutoConfiguration.java | 147 ++ .../config/redisson/RedissonClientHelper.java | 44 + .../RedissonConnectionConfiguration.java | 434 +++++ .../redisson/RedissonConnectionFactory.java | 132 ++ .../config/redisson/RedissonProperties.java | 25 + .../redis/starter/handler/BitmapHandler.java | 279 ++++ .../redis/starter/handler/ClusterHandler.java | 294 ++++ .../starter/handler/CustomCommandHandler.java | 144 ++ .../redis/starter/handler/DBHandler.java | 385 +++++ .../redis/starter/handler/GeoHandler.java | 536 +++++++ .../redis/starter/handler/HandlerManager.java | 292 ++++ .../starter/handler/HandlerManagerProxy.java | 80 + .../redis/starter/handler/HandlerType.java | 108 ++ .../redis/starter/handler/HashHandler.java | 478 ++++++ .../starter/handler/HyperLogLogHandler.java | 142 ++ .../redis/starter/handler/KeyHandler.java | 660 ++++++++ .../redis/starter/handler/ListHandler.java | 923 +++++++++++ .../redis/starter/handler/NumberHandler.java | 793 ++++++++++ .../redis/starter/handler/PubSubHandler.java | 213 +++ .../redis/starter/handler/RedisHandler.java | 11 + .../starter/handler/RedisLockHandler.java | 112 ++ .../redis/starter/handler/ScriptHandler.java | 357 +++++ .../starter/handler/SentinelHandler.java | 143 ++ .../redis/starter/handler/SetHandler.java | 544 +++++++ .../redis/starter/handler/StreamHandler.java | 1305 +++++++++++++++ .../redis/starter/handler/StringHandler.java | 364 +++++ .../starter/handler/TransactionHandler.java | 345 ++++ .../redis/starter/handler/ZsetHandler.java | 1398 +++++++++++++++++ .../starter/util/ApplicationContextUtil.java | 37 + .../cloud/redis/starter/util/ConvertUtil.java | 336 ++++ .../cloud/redis/starter/util/RedisUtil.java | 381 +++++ .../main/resources/META-INF/spring.factories | 2 + 46 files changed, 12562 insertions(+), 4 deletions(-) create mode 100644 mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/CommonConstants.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/JsonRedisSerializer.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisAutoConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisConnectionConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializer.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializerPostProcessor.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/cache/RedisCacheConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/jedis/JedisConnectionConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceConnectionConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceTypeHint.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonAutoConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonClientHelper.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionConfiguration.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionFactory.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonProperties.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/BitmapHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ClusterHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/CustomCommandHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/DBHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/GeoHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManager.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManagerProxy.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerType.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HashHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HyperLogLogHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/KeyHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ListHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/NumberHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/PubSubHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisLockHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ScriptHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SentinelHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SetHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StreamHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StringHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/TransactionHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ZsetHandler.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ApplicationContextUtil.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ConvertUtil.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/RedisUtil.java create mode 100644 mall-ebtp-cloud-redis-starter/src/main/resources/META-INF/spring.factories diff --git a/mall-ebtp-cloud-jpa-starter/pom.xml b/mall-ebtp-cloud-jpa-starter/pom.xml index 2b5f77e..e1378f6 100644 --- a/mall-ebtp-cloud-jpa-starter/pom.xml +++ b/mall-ebtp-cloud-jpa-starter/pom.xml @@ -20,10 +20,6 @@ com.baomidou mybatis-plus-boot-starter - - org.springframework.boot - spring-boot-starter-cache - com.alibaba druid diff --git a/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/CommonConstants.java b/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/CommonConstants.java new file mode 100644 index 0000000..7d297e2 --- /dev/null +++ b/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/CommonConstants.java @@ -0,0 +1,13 @@ +package com.chinaunicom.mall.ebtp.cloud.jpa.starter; + +public interface CommonConstants { + /** + * 删除 + */ + String STATUS_DEL = "deleted"; + + /** + * 正常 + */ + String STATUS_NORMAL = "normal"; +} diff --git a/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/JpaStarterConfiguration.java b/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/JpaStarterConfiguration.java index f209f8f..58b073d 100644 --- a/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/JpaStarterConfiguration.java +++ b/mall-ebtp-cloud-jpa-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/jpa/starter/JpaStarterConfiguration.java @@ -1,10 +1,68 @@ package com.chinaunicom.mall.ebtp.cloud.jpa.starter; +import java.time.LocalDateTime; + +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.PropertySource; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; + +import cn.chinaunicom.sdsi.framework.config.mybatis.MyMetaObjectHandler; + @Configuration +@ComponentScan(value = "cn.chinaunicom.sdsi.framework.config.mybatis", excludeFilters = { + @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { MyMetaObjectHandler.class }) }) @PropertySource("classpath:jpa-configuration.properties") public class JpaStarterConfiguration { + @Bean + MetaObjectHandler metaObjectHandler() { + return new MetaObjectHandler() { + /** + * 更新元对象字段填充(用于更新时对公共字段的填充) + * + * @param metaObject 元对象 + */ + @Override + public void updateFill(MetaObject metaObject) { + final LocalDateTime now = LocalDateTime.now(); + + setFieldValByName("updateDate", now, metaObject); + setFieldValByName("lastUpdateTime", now, metaObject); + } + + /** + * 插入元对象字段填充(用于插入时对公共字段的填充) + * + * @param metaObject 元对象 + */ + @Override + public void insertFill(MetaObject metaObject) { + Object obj = getFieldValByName("createBy", metaObject); + obj = getFieldValByName("createDate", metaObject); + if (obj == null) { + setFieldValByName("createDate", LocalDateTime.now(), metaObject); + } + obj = getFieldValByName("updateDate", metaObject); + if (obj == null) { + setFieldValByName("updateDate", LocalDateTime.now(), metaObject); + } + obj = getFieldValByName("tenantId", metaObject); + if (obj == null) { + setFieldValByName("tenantId", "ebtp_mall", metaObject); + } + obj = getFieldValByName("tenantName", metaObject); + if (obj == null) { + setFieldValByName("tenantName", "ebtp_mall", metaObject); + } + setFieldValByName("deleteFlag", CommonConstants.STATUS_NORMAL, metaObject); + } + }; + } + } diff --git a/mall-ebtp-cloud-jpa-starter/src/main/resoureces/jpa-configuration.properties b/mall-ebtp-cloud-jpa-starter/src/main/resoureces/jpa-configuration.properties index e69de29..26aef9f 100644 --- a/mall-ebtp-cloud-jpa-starter/src/main/resoureces/jpa-configuration.properties +++ b/mall-ebtp-cloud-jpa-starter/src/main/resoureces/jpa-configuration.properties @@ -0,0 +1,10 @@ +# 默认开启驼峰映射 +mybatis-plus.configuration.map-undersore-to-camel-case=true +# 对所有的 resultMap 都进行自动映射 +mybatis-plus.configuration.auto-mapping-behavior=full +# 项目统一mapper存放位置 +mybatis-plus.mapper-locations=classpath*:com/chinaunicom/mall/ebtp/**/mapper/*Mapper.xml +# 逻辑已删除值 +mybatis-plus.global-config.db-config.logic-delete-value=0 +# 逻辑未删除值 +mybatis-plus.global-config.db-config.logic-not-delete-value=1 \ No newline at end of file diff --git a/mall-ebtp-cloud-redis-starter/pom.xml b/mall-ebtp-cloud-redis-starter/pom.xml index f239aaf..4376894 100644 --- a/mall-ebtp-cloud-redis-starter/pom.xml +++ b/mall-ebtp-cloud-redis-starter/pom.xml @@ -14,15 +14,44 @@ mall-ebtp-cloud-redis-starter 0.0.1 mall-ebtp-cloud-redis-starter + + + 2.7.0 + 3.1.0 + 3.11.4 + 4.6.10 + org.springframework.boot spring-boot-starter-data-redis + + org.apache.commons + commons-pool2 + + + cn.hutool + hutool-json + ${hutool-json.version} + redis.clients jedis + provided + + org.redisson + redisson-spring-data-21 + ${redisson.version} + provided + + + org.springframework.data + spring-data-redis + + + diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/JsonRedisSerializer.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/JsonRedisSerializer.java new file mode 100644 index 0000000..aacdecb --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/JsonRedisSerializer.java @@ -0,0 +1,90 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config; + +import cn.hutool.json.JSONUtil; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; + +import javax.management.openmbean.SimpleType; +import java.nio.charset.StandardCharsets; + +/** + * redis序列化器 + * @author xsx + * @date 2019/7/5 + * @since 1.8 + */ +public class JsonRedisSerializer implements RedisSerializer { + + /** + * 序列化 + * @param t 对象 + * @return 返回字节数组 + * @throws SerializationException 序列化异常 + */ + @Override + public byte[] serialize(Object t) throws SerializationException { + if (t == null) { + return new byte[0]; + } + byte[] bytes; + if (this.isSimpleType(t)) { + bytes = t.toString().getBytes(StandardCharsets.UTF_8); + }else { + try { + bytes = JSONUtil.toJsonStr(t).getBytes(StandardCharsets.UTF_8); + } catch (Exception ex) { + throw new SerializationException("Could not serialize: " + ex.getMessage(), ex); + } + } + return bytes; + } + + /** + * 反序列化 + * @param bytes 字节数组 + * @return 返回对象 + * @throws SerializationException 序列化异常 + */ + @Override + public Object deserialize(byte[] bytes) throws SerializationException { + return this.tryDeserialize(bytes); + } + + /** + * 尝试反序列化 + * @param bytes 字节数组 + * @return 返回对象 + * @throws SerializationException 序列化异常 + */ + private Object tryDeserialize(byte[] bytes) throws SerializationException { + if (bytes == null || bytes.length == 0) { + return null; + } + String str = new String(bytes, StandardCharsets.UTF_8); + if (JSONUtil.isJsonArray(str)) { + return JSONUtil.parseArray(str); + }else if (JSONUtil.isJsonObj(str)) { + return JSONUtil.parseObj(str); + }else { + return str; + } + } + + /** + * 是否简单类型 + * @param t 实体 + * @return 返回布尔值 + */ + private boolean isSimpleType(Object t) { + return SimpleType.BYTE.isValue(t) || + SimpleType.CHARACTER.isValue(t) || + SimpleType.SHORT.isValue(t) || + SimpleType.INTEGER.isValue(t) || + SimpleType.LONG.isValue(t) || + SimpleType.FLOAT.isValue(t) || + SimpleType.DOUBLE.isValue(t) || + SimpleType.BOOLEAN.isValue(t) || + SimpleType.BIGINTEGER.isValue(t) || + SimpleType.BIGDECIMAL.isValue(t); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisAutoConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisAutoConfiguration.java new file mode 100644 index 0000000..cc8b150 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisAutoConfiguration.java @@ -0,0 +1,56 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.cache.RedisCacheConfiguration; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.jedis.JedisConnectionConfiguration; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.lettuce.LettuceConnectionConfiguration; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson.RedissonAutoConfiguration; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ApplicationContextUtil; + +/** + * redis自动配置 + * @author xsx + * @date 2019/4/18 + * @since 1.8 + */ +@Configuration +@ConditionalOnClass({RedisTemplate.class}) +@Import({ + ApplicationContextUtil.class, + LettuceConnectionConfiguration.class, + JedisConnectionConfiguration.class, + RedissonAutoConfiguration.class, + RedisCacheConfiguration.class +}) +public class RedisAutoConfiguration { + + @Bean + @ConditionalOnMissingBean({RedisTemplate.class}) + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + JsonRedisSerializer jsonRedisSerializer = new JsonRedisSerializer(); + RedisTemplate template = new RedisTemplate<>(); + template.setKeySerializer(RedisSerializer.string()); + template.setValueSerializer(jsonRedisSerializer); + template.setHashKeySerializer(RedisSerializer.string()); + template.setHashValueSerializer(jsonRedisSerializer); + template.setConnectionFactory(redisConnectionFactory); + return template; + } + + @Bean + @ConditionalOnMissingBean({StringRedisTemplate.class}) + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(redisConnectionFactory); + return template; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisConnectionConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisConnectionConfiguration.java new file mode 100644 index 0000000..e43b5cd --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisConnectionConfiguration.java @@ -0,0 +1,182 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.data.redis.connection.*; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +/** + * redis连接配置 + * 重写org.springframework.boot.autoconfigure.data.redis.RedisConnectionConfiguration + * @author xsx + * @date 2019/5/7 + * @since 1.8 + */ +public abstract class RedisConnectionConfiguration { + private final RedisProperties properties; + + private final RedisSentinelConfiguration sentinelConfiguration; + + private final RedisClusterConfiguration clusterConfiguration; + + protected RedisConnectionConfiguration( + RedisProperties properties, + ObjectProvider sentinelConfigurationProvider, + ObjectProvider clusterConfigurationProvider + ) { + this.properties = properties; + this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable(); + this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable(); + } + + protected final GenericObjectPoolConfig getPoolConfig( + RedisProperties.Pool properties, + GenericObjectPoolConfig config + ) { + config.setMaxTotal(properties.getMaxActive()); + config.setMaxIdle(properties.getMaxIdle()); + config.setMinIdle(properties.getMinIdle()); + if (properties.getTimeBetweenEvictionRuns() != null) { + config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis()); + } + if (properties.getMaxWait() != null) { + config.setMaxWaitMillis(properties.getMaxWait().toMillis()); + } + return config; + } + + protected final RedisStandaloneConfiguration getStandaloneConfig() { + RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); + if (StringUtils.hasText(this.properties.getUrl())) { + RedisConnectionConfiguration.ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl()); + config.setHostName(connectionInfo.getHostName()); + config.setPort(connectionInfo.getPort()); + config.setPassword(RedisPassword.of(connectionInfo.getPassword())); + } + else { + config.setHostName(this.properties.getHost()); + config.setPort(this.properties.getPort()); + config.setPassword(RedisPassword.of(this.properties.getPassword())); + } + config.setDatabase(this.properties.getDatabase()); + return config; + } + + protected final RedisSentinelConfiguration getSentinelConfig() { + if (this.sentinelConfiguration != null) { + return this.sentinelConfiguration; + } + RedisProperties.Sentinel sentinelProperties = this.properties.getSentinel(); + if (sentinelProperties != null) { + RedisSentinelConfiguration config = new RedisSentinelConfiguration(); + config.master(sentinelProperties.getMaster()); + config.setSentinels(createSentinels(sentinelProperties)); + if (this.properties.getPassword() != null) { + config.setPassword(RedisPassword.of(this.properties.getPassword())); + } + config.setDatabase(this.properties.getDatabase()); + return config; + } + return null; + } + + /** + * Create a {@link RedisClusterConfiguration} if necessary. + * @return {@literal null} if no cluster settings are set. + */ + protected final RedisClusterConfiguration getClusterConfiguration() { + if (this.clusterConfiguration != null) { + return this.clusterConfiguration; + } + if (this.properties.getCluster() == null) { + return null; + } + RedisProperties.Cluster clusterProperties = this.properties.getCluster(); + RedisClusterConfiguration config = new RedisClusterConfiguration(clusterProperties.getNodes()); + if (clusterProperties.getMaxRedirects() != null) { + config.setMaxRedirects(clusterProperties.getMaxRedirects()); + } + if (this.properties.getPassword() != null) { + config.setPassword(RedisPassword.of(this.properties.getPassword())); + } + return config; + } + + protected final RedisProperties getProperties() { + return this.properties; + } + + private List createSentinels(RedisProperties.Sentinel sentinel) { + List nodes = new ArrayList<>(); + for (String node : sentinel.getNodes()) { + try { + String[] parts = StringUtils.split(node, ":"); + Assert.notNull(parts, "Must be defined as 'host:port'"); + Assert.state(parts.length == 2, "Must be defined as 'host:port'"); + nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1]))); + } + catch (RuntimeException ex) { + throw new IllegalStateException("Invalid redis sentinel " + "property '" + node + "'", ex); + } + } + return nodes; + } + + protected RedisConnectionConfiguration.ConnectionInfo parseUrl(String url) { + try { + URI uri = new URI(url); + boolean useSsl = (url.startsWith("rediss://")); + String password = null; + if (uri.getUserInfo() != null) { + password = uri.getUserInfo(); + int index = password.indexOf(':'); + if (index >= 0) { + password = password.substring(index + 1); + } + } + return new RedisConnectionConfiguration.ConnectionInfo(uri, useSsl, password); + } + catch (URISyntaxException ex) { + throw new IllegalArgumentException("Malformed url '" + url + "'", ex); + } + } + + protected static class ConnectionInfo { + + private final URI uri; + + private final boolean useSsl; + + private final String password; + + public ConnectionInfo(URI uri, boolean useSsl, String password) { + this.uri = uri; + this.useSsl = useSsl; + this.password = password; + } + + public boolean isUseSsl() { + return this.useSsl; + } + + public String getHostName() { + return this.uri.getHost(); + } + + public int getPort() { + return this.uri.getPort(); + } + + public String getPassword() { + return this.password; + } + + } +} \ No newline at end of file diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializer.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializer.java new file mode 100644 index 0000000..c3103fe --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializer.java @@ -0,0 +1,20 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config; + +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * redis初始化类 + * @author xsx + * @date 2019/6/12 + * @since 1.8 + */ +public class RedisInitializer implements ApplicationContextInitializer { + + @Override + public void initialize(ConfigurableApplicationContext context) { + context.addBeanFactoryPostProcessor(new RedisInitializerPostProcessor()); + } +} + + diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializerPostProcessor.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializerPostProcessor.java new file mode 100644 index 0000000..fb1a1c6 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/RedisInitializerPostProcessor.java @@ -0,0 +1,33 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; + +/** + * redis初始化后置处理器 + * @author xsx + * @date 2019/6/12 + * @since 1.8 + */ +public class RedisInitializerPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor { + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + registry.registerBeanDefinition(RedisAutoConfiguration.class.getName(), new RootBeanDefinition(RedisAutoConfiguration.class)); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { + + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } +} \ No newline at end of file diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/cache/RedisCacheConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/cache/RedisCacheConfiguration.java new file mode 100644 index 0000000..009565a --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/cache/RedisCacheConfiguration.java @@ -0,0 +1,82 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.cache; + +import java.util.LinkedHashSet; +import java.util.List; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers; +import org.springframework.boot.autoconfigure.cache.CacheProperties; +import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.RedisSerializationContext; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.JsonRedisSerializer; + +/** + * redis缓存配置 + * 重写org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration + * @author xsx + * @date 2019/10/4 + * @since 1.8 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnBean(RedisConnectionFactory.class) +@ConditionalOnMissingBean(CacheManager.class) +@EnableConfigurationProperties({CacheProperties.class}) +public class RedisCacheConfiguration { + + @Bean + RedisCacheManager cacheManager( + CacheProperties cacheProperties, + ObjectProvider redisCacheConfiguration, + ObjectProvider redisCacheManagerBuilderCustomizers, + RedisConnectionFactory redisConnectionFactory + ) { + RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults( + determineConfiguration(cacheProperties, redisCacheConfiguration)); + List cacheNames = cacheProperties.getCacheNames(); + if (!cacheNames.isEmpty()) { + builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); + } + redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return new CacheManagerCustomizers(null).customize(builder.build()); + } + + private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration( + CacheProperties cacheProperties, + ObjectProvider redisCacheConfiguration + ) { + return redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties)); + } + + private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration( + CacheProperties cacheProperties) { + CacheProperties.Redis redisProperties = cacheProperties.getRedis(); + org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration + .defaultCacheConfig(); + config = config.serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer(new JsonRedisSerializer()) + ); + if (redisProperties.getTimeToLive() != null) { + config = config.entryTtl(redisProperties.getTimeToLive()); + } + if (redisProperties.getKeyPrefix() != null) { + config = config.prefixKeysWith(redisProperties.getKeyPrefix()); + } + if (!redisProperties.isCacheNullValues()) { + config = config.disableCachingNullValues(); + } + if (!redisProperties.isUseKeyPrefix()) { + config = config.disableKeyPrefix(); + } + return config; + } + +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/jedis/JedisConnectionConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/jedis/JedisConnectionConfiguration.java new file mode 100644 index 0000000..53ebe11 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/jedis/JedisConnectionConfiguration.java @@ -0,0 +1,107 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.jedis; + +import java.time.Duration; + +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.JedisClientConfigurationBuilderCustomizer; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnection; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.util.StringUtils; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.RedisConnectionConfiguration; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPoolConfig; + +/** + * jedis连接配置 + * 重写org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration + * @author xsx + * @date 2019/5/7 + * @since 1.8 + */ +@Configuration +@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class}) +@AutoConfigureAfter({RedisProperties.class}) +@EnableConfigurationProperties({RedisProperties.class}) +public class JedisConnectionConfiguration extends RedisConnectionConfiguration { + + JedisConnectionConfiguration(RedisProperties properties, ObjectProvider sentinelConfiguration, ObjectProvider clusterConfiguration, ObjectProvider builderCustomizers) { + super(properties, sentinelConfiguration, clusterConfiguration); + } + + @Bean + @Scope("prototype") + @ConditionalOnMissingBean({RedisConnectionFactory.class}) + public RedisConnectionFactory redisConnectionFactory( + ObjectProvider builderCustomizers + ) { + return this.createJedisConnectionFactory(builderCustomizers); + } + + private JedisConnectionFactory createJedisConnectionFactory( + ObjectProvider builderCustomizers + ) { + JedisClientConfiguration clientConfiguration = this.getJedisClientConfiguration(builderCustomizers); + if (getSentinelConfig() != null) { + return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration); + } + if (getClusterConfiguration() != null) { + return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration); + } + return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration); + } + + private JedisClientConfiguration getJedisClientConfiguration( + ObjectProvider builderCustomizers + ) { + JedisClientConfiguration.JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder()); + RedisProperties.Pool pool = getProperties().getJedis().getPool(); + if (pool != null) { + applyPooling(pool, builder); + } + if (StringUtils.hasText(getProperties().getUrl())) { + customizeConfigurationFromUrl(builder); + } + builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return builder.build(); + } + + private JedisClientConfiguration.JedisClientConfigurationBuilder applyProperties(JedisClientConfiguration.JedisClientConfigurationBuilder builder) { + if (getProperties().isSsl()) { + builder.useSsl(); + } + if (getProperties().getTimeout() != null) { + Duration timeout = getProperties().getTimeout(); + builder.readTimeout(timeout).connectTimeout(timeout); + } + return builder; + } + + private void applyPooling( + RedisProperties.Pool pool, + JedisClientConfiguration.JedisClientConfigurationBuilder builder + ) { + builder.usePooling().poolConfig(this.getPoolConfig(pool, new JedisPoolConfig())); + } + + private void customizeConfigurationFromUrl(JedisClientConfiguration.JedisClientConfigurationBuilder builder) { + RedisConnectionConfiguration.ConnectionInfo connectionInfo = parseUrl(getProperties().getUrl()); + if (connectionInfo.isUseSsl()) { + builder.useSsl(); + } + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceConnectionConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceConnectionConfiguration.java new file mode 100644 index 0000000..2c5bf43 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceConnectionConfiguration.java @@ -0,0 +1,126 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.lettuce; + +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; +import org.springframework.util.StringUtils; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.RedisConnectionConfiguration; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.resource.ClientResources; +import io.lettuce.core.resource.DefaultClientResources; + +/** + * lettuce连接配置 + * 重写org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration + * @author xsx + * @date 2019/5/7 + * @since 1.8 + */ +@Configuration +@ConditionalOnClass({GenericObjectPool.class, RedisClient.class}) +@AutoConfigureAfter({RedisProperties.class}) +@EnableConfigurationProperties({RedisProperties.class}) +public class LettuceConnectionConfiguration extends RedisConnectionConfiguration { + + public LettuceConnectionConfiguration( + RedisProperties properties, + ObjectProvider sentinelConfigurationProvider, + ObjectProvider clusterConfigurationProvider + ) { + super(properties, sentinelConfigurationProvider, clusterConfigurationProvider); + } + + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean({ClientResources.class}) + public DefaultClientResources lettuceClientResources() { + return DefaultClientResources.create(); + } + + @Bean + @Scope("prototype") + @ConditionalOnMissingBean({RedisConnectionFactory.class}) + public RedisConnectionFactory redisConnectionFactory( + ObjectProvider builderCustomizers, + ClientResources clientResources + ) { + LettuceClientConfiguration clientConfig = this.getLettuceClientConfiguration( + builderCustomizers, + clientResources, + this.getProperties().getLettuce().getPool() + ); + return createLettuceConnectionFactory(clientConfig); + } + + private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientConfiguration clientConfiguration) { + if (getSentinelConfig() != null) { + return new LettuceConnectionFactory(getSentinelConfig(), clientConfiguration); + } + if (getClusterConfiguration() != null) { + return new LettuceConnectionFactory(getClusterConfiguration(), clientConfiguration); + } + return new LettuceConnectionFactory(getStandaloneConfig(), clientConfiguration); + } + + private LettuceClientConfiguration getLettuceClientConfiguration( + ObjectProvider builderCustomizers, + ClientResources clientResources, RedisProperties.Pool pool) { + LettuceClientConfiguration.LettuceClientConfigurationBuilder builder = createBuilder(pool); + applyProperties(builder); + if (StringUtils.hasText(getProperties().getUrl())) { + customizeConfigurationFromUrl(builder); + } + builder.clientResources(clientResources); + builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return builder.build(); + } + + private LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool pool) { + if (pool == null) { + return LettuceClientConfiguration.builder(); + } + return LettucePoolingClientConfiguration.builder().poolConfig( + this.getPoolConfig(pool, new GenericObjectPoolConfig<>()) + ); + } + + private LettuceClientConfiguration.LettuceClientConfigurationBuilder applyProperties( + LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) { + if (getProperties().isSsl()) { + builder.useSsl(); + } + if (getProperties().getTimeout() != null) { + builder.commandTimeout(getProperties().getTimeout()); + } + if (getProperties().getLettuce() != null) { + RedisProperties.Lettuce lettuce = getProperties().getLettuce(); + if (lettuce.getShutdownTimeout() != null && !lettuce.getShutdownTimeout().isZero()) { + builder.shutdownTimeout(getProperties().getLettuce().getShutdownTimeout()); + } + } + return builder; + } + + private void customizeConfigurationFromUrl(LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) { + RedisConnectionConfiguration.ConnectionInfo connectionInfo = parseUrl(getProperties().getUrl()); + if (connectionInfo.isUseSsl()) { + builder.useSsl(); + } + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceTypeHint.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceTypeHint.java new file mode 100644 index 0000000..410c8fe --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/lettuce/LettuceTypeHint.java @@ -0,0 +1,312 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.lettuce; + +import io.lettuce.core.codec.ByteArrayCodec; +import io.lettuce.core.codec.RedisCodec; +import io.lettuce.core.output.*; +import org.springframework.beans.BeanUtils; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static io.lettuce.core.protocol.CommandType.*; + +/** + * lettuce命令映射 + * 重写org.springframework.data.redis.connection.lettuce.LettuceConnection.TypeHints + * @author xsx + * @date 2019/7/4 + * @since 1.8 + */ +public class LettuceTypeHint { + /** + * 命令输出对象字典 + */ + @SuppressWarnings("rawtypes") + private static final Map> COMMAND_OUTPUT_TYPE_MAPPING = new HashMap<>(); + /** + * 命令输出对象构造字典 + */ + @SuppressWarnings("rawtypes") + private static final Map, Constructor> CONSTRUCTORS = new ConcurrentHashMap<>(); + + static { + // INTEGER + COMMAND_OUTPUT_TYPE_MAPPING.put(BITCOUNT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BITOP, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BITPOS, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(DBSIZE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(DECR, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(DECRBY, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(DEL, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GETBIT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HDEL, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HINCRBY, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HLEN, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(INCR, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(INCRBY, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LINSERT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LLEN, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LPUSH, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LPUSHX, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LREM, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PTTL, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PUBLISH, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RPUSH, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RPUSHX, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SADD, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SCARD, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SDIFFSTORE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SETBIT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SETRANGE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SINTERSTORE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SREM, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SUNIONSTORE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(STRLEN, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(TTL, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZADD, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZCOUNT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZINTERSTORE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZRANK, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREM, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREMRANGEBYRANK, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREMRANGEBYSCORE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREVRANK, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZUNIONSTORE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PFCOUNT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PFMERGE, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PFADD, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XACK, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XDEL, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XLEN, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XTRIM, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(TOUCH, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(UNLINK, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(APPEND, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HSTRLEN, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZCARD, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZLEXCOUNT, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREMRANGEBYLEX, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GEOADD, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GEORADIUS, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GEORADIUSBYMEMBER, IntegerOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(WAIT, IntegerOutput.class); + + // DOUBLE + COMMAND_OUTPUT_TYPE_MAPPING.put(HINCRBYFLOAT, DoubleOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(INCRBYFLOAT, DoubleOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZINCRBY, DoubleOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZSCORE, DoubleOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GEODIST, DoubleOutput.class); + + // SCORED VALUE + COMMAND_OUTPUT_TYPE_MAPPING.put(ZPOPMIN, ScoredValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZPOPMAX, ScoredValueOutput.class); + + // MAP + COMMAND_OUTPUT_TYPE_MAPPING.put(CONFIG, MapOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HGETALL, MapOutput.class); + + // KEY LIST + COMMAND_OUTPUT_TYPE_MAPPING.put(HKEYS, KeyListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(KEYS, KeyListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PUBSUB, KeyListOutput.class); + + // KEY VALUE + COMMAND_OUTPUT_TYPE_MAPPING.put(BRPOP, KeyValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BLPOP, KeyValueOutput.class); + + // SINGLE VALUE + COMMAND_OUTPUT_TYPE_MAPPING.put(BRPOPLPUSH, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ECHO, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GET, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GETRANGE, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(GETSET, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HGET, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LINDEX, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LPOP, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RANDOMKEY, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RENAME, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RPOP, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RPOPLPUSH, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SPOP, ValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SRANDMEMBER, ValueOutput.class); + + // STATUS VALUE + COMMAND_OUTPUT_TYPE_MAPPING.put(AUTH, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PING, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(READONLY, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(READWRITE, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SWAPDB, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BGREWRITEAOF, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BGSAVE, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(CLIENT, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(DEBUG, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(DISCARD, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(FLUSHALL, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(FLUSHDB, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HMSET, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(INFO, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LSET, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LTRIM, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(MIGRATE, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(MSET, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(QUIT, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RESTORE, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SAVE, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SELECT, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SET, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SETEX, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SHUTDOWN, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SLAVEOF, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SYNC, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(TYPE, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(WATCH, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(UNWATCH, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XADD, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XGROUP, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(OBJECT, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PSETEX, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ASKING, StatusOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(CLUSTER, StatusOutput.class); + + // VALUE LIST + COMMAND_OUTPUT_TYPE_MAPPING.put(HMGET, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(MGET, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HVALS, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(LRANGE, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SORT, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZRANGE, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZRANGEBYSCORE, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREVRANGE, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREVRANGEBYSCORE, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZREVRANGEBYLEX, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ZRANGEBYLEX, ValueListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(TIME, ValueListOutput.class); + + // STRING VALUE LIST + COMMAND_OUTPUT_TYPE_MAPPING.put(GEOHASH, StringValueListOutput.class); + + // BOOLEAN + COMMAND_OUTPUT_TYPE_MAPPING.put(EXISTS, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(EXPIRE, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(EXPIREAT, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HEXISTS, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HSET, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(HSETNX, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(MOVE, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(MSETNX, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PERSIST, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PEXPIRE, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(PEXPIREAT, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(RENAMENX, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SETNX, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SISMEMBER, BooleanOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SMOVE, BooleanOutput.class); + + // MULTI + COMMAND_OUTPUT_TYPE_MAPPING.put(EXEC, MultiOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(MULTI, MultiOutput.class); + + + // DATE + COMMAND_OUTPUT_TYPE_MAPPING.put(LASTSAVE, DateOutput.class); + + // GEO COORDINATES LIST + COMMAND_OUTPUT_TYPE_MAPPING.put(GEOPOS, GeoCoordinatesListOutput.class); + + + // VALUE SET + COMMAND_OUTPUT_TYPE_MAPPING.put(SDIFF, ValueSetOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SINTER, ValueSetOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SMEMBERS, ValueSetOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SUNION, ValueSetOutput.class); + + // KEY VALUE SCORED VALUE + COMMAND_OUTPUT_TYPE_MAPPING.put(BZPOPMIN, KeyValueScoredValueOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BZPOPMAX, KeyValueScoredValueOutput.class); + + // STREAM MESSAGE LIST + COMMAND_OUTPUT_TYPE_MAPPING.put(XCLAIM, StreamMessageListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XREVRANGE, StreamMessageListOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XRANGE, StreamMessageListOutput.class); + + // NESTED MULTI + COMMAND_OUTPUT_TYPE_MAPPING.put(XPENDING, NestedMultiOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(SLOWLOG, NestedMultiOutput.class); + + // STREAM READ + COMMAND_OUTPUT_TYPE_MAPPING.put(XREAD, StreamReadOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(XREADGROUP, StreamReadOutput.class); + + // ARRAY + COMMAND_OUTPUT_TYPE_MAPPING.put(COMMAND, ArrayOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(ROLE, ArrayOutput.class); + + // BYTE ARRAY + COMMAND_OUTPUT_TYPE_MAPPING.put(DUMP, ArrayOutput.class); + COMMAND_OUTPUT_TYPE_MAPPING.put(BITFIELD, ArrayOutput.class); + + // KEY SCAN + COMMAND_OUTPUT_TYPE_MAPPING.put(SCAN, KeyScanOutput.class); + + // MAP SCAN + COMMAND_OUTPUT_TYPE_MAPPING.put(HSCAN, MapScanOutput.class); + + // VALUE SCAN + COMMAND_OUTPUT_TYPE_MAPPING.put(SSCAN, ValueScanOutput.class); + + // SCORED VALUE SCAN + COMMAND_OUTPUT_TYPE_MAPPING.put(ZSCAN, ScoredValueScanOutput.class); + } + + /** + * 获取命令输出对象 + * @param command 命令 + * @param key 键 + * @return 返回命令输出对象 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static CommandOutput getTypeHint(String command, String key) { + Class type = COMMAND_OUTPUT_TYPE_MAPPING.get(valueOf(command)); + if (type.isAssignableFrom(StreamMessageListOutput.class)) { + return new StreamMessageListOutput(ByteArrayCodec.INSTANCE, key); + }else { + return getTypeHint(type, new ByteArrayOutput<>(ByteArrayCodec.INSTANCE)); + } + } + + /** + * 获取命令输出对象 + * @param type 类型 + * @param defaultType 默认类型 + * @return 返回命令输出对象 + */ + @SuppressWarnings("rawtypes") + private static CommandOutput getTypeHint(Class type, CommandOutput defaultType) { + if (type == null) { + return defaultType; + } + CommandOutput outputType = instanciateCommandOutput(type); + return outputType != null ? outputType : defaultType; + } + + /** + * 初始化命令输出对象 + * @param type 类型 + * @return 返回命令输出对象 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static CommandOutput instanciateCommandOutput(Class type) { + Assert.notNull(type, "Cannot create instance for 'null' type."); + Constructor constructor = CONSTRUCTORS.get(type); + if (constructor == null) { + constructor = (Constructor) ClassUtils.getConstructorIfAvailable(type, RedisCodec.class); + CONSTRUCTORS.put(type, constructor); + } + return BeanUtils.instantiateClass(constructor, ByteArrayCodec.INSTANCE); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonAutoConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonAutoConfiguration.java new file mode 100644 index 0000000..9bb730c --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonAutoConfiguration.java @@ -0,0 +1,147 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.util.ReflectionUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * redisson连接配置 + * 重写org.redisson.spring.starter.RedissonAutoConfiguration + * @author xsx + * @date 2019/5/10 + * @since 1.8 + */ +@Configuration +@ConditionalOnClass({Redisson.class, RedisOperations.class}) +@EnableConfigurationProperties({RedissonProperties.class, RedisProperties.class}) +public class RedissonAutoConfiguration { + @Autowired + private RedissonProperties redissonProperties; + @Autowired + private RedisProperties redisProperties; + @Autowired + private ApplicationContext ctx; + + public RedissonAutoConfiguration() { + } + + @Bean + @ConditionalOnMissingBean({RedisConnectionFactory.class}) + public RedisConnectionFactory redisConnectionFactory(RedissonClient redisson) { + return new RedissonConnectionFactory(redisson); + } + + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean({RedissonClient.class}) + public RedissonClient redisson() { + return Redisson.create(this.createConfig(null)); + } + + public RedissonConnectionConfiguration createConfig(Integer dbIndex) { + if (dbIndex==null) { + dbIndex = this.redisProperties.getDatabase(); + } + RedissonConnectionConfiguration redissonConnectionConfiguration; + Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster"); + Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout"); + Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, this.redisProperties); + int timeout; + Method nodesMethod; + if (null == timeoutValue) { + timeout = 0; + } else if (!(timeoutValue instanceof Integer)) { + nodesMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis"); + timeout = ((Long)ReflectionUtils.invokeMethod(nodesMethod, timeoutValue)).intValue(); + } else { + timeout = (Integer)timeoutValue; + } + + if (this.redissonProperties.getConfig() != null) { + try { + InputStream is = this.getConfigStream(); + redissonConnectionConfiguration = RedissonConnectionConfiguration.fromJSON(is); + } catch (IOException e) { + try { + InputStream is = this.getConfigStream(); + redissonConnectionConfiguration = RedissonConnectionConfiguration.fromYAML(is); + } catch (IOException e1) { + throw new IllegalArgumentException("Can't parse redissonConnectionConfiguration", e1); + } + } + } else if (this.redisProperties.getSentinel() != null) { + nodesMethod = ReflectionUtils.findMethod(RedisProperties.Sentinel.class, "getNodes"); + Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, this.redisProperties.getSentinel()); + String[] nodes; + if (nodesValue instanceof String) { + nodes = this.convert(Arrays.asList(((String)nodesValue).split(","))); + } else { + nodes = this.convert((List)nodesValue); + } + + redissonConnectionConfiguration = new RedissonConnectionConfiguration(); + redissonConnectionConfiguration.useSentinelServers().setMasterName(this.redisProperties.getSentinel().getMaster()).addSentinelAddress(nodes).setDatabase(dbIndex).setConnectTimeout(timeout).setPassword(this.redisProperties.getPassword()); + } else { + Method method; + if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties) != null) { + Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties); + method = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes"); + List nodesObject = (List)ReflectionUtils.invokeMethod(method, clusterObject); + String[] nodes = this.convert(nodesObject); + redissonConnectionConfiguration = new RedissonConnectionConfiguration(); + redissonConnectionConfiguration.useClusterServers().addNodeAddress(nodes).setConnectTimeout(timeout).setPassword(this.redisProperties.getPassword()); + } else { + redissonConnectionConfiguration = new RedissonConnectionConfiguration(); + String prefix = "redis://"; + method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl"); + if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, this.redisProperties)) { + prefix = "rediss://"; + } + + redissonConnectionConfiguration.useSingleServer().setAddress(prefix + this.redisProperties.getHost() + ":" + this.redisProperties.getPort()).setConnectTimeout(timeout).setDatabase(dbIndex).setPassword(this.redisProperties.getPassword()); + } + } + return redissonConnectionConfiguration; + } + + private String[] convert(List nodesObject) { + List nodes = new ArrayList<>(nodesObject.size()); + Iterator var3 = nodesObject.iterator(); + + while(true) { + while(var3.hasNext()) { + String node = (String)var3.next(); + if (!node.startsWith("redis://") && !node.startsWith("rediss://")) { + nodes.add("redis://" + node); + } else { + nodes.add(node); + } + } + return nodes.toArray(new String[nodes.size()]); + } + } + + private InputStream getConfigStream() throws IOException { + Resource resource = this.ctx.getResource(this.redissonProperties.getConfig()); + InputStream is = resource.getInputStream(); + return is; + } +} \ No newline at end of file diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonClientHelper.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonClientHelper.java new file mode 100644 index 0000000..cd81290 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonClientHelper.java @@ -0,0 +1,44 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ApplicationContextUtil; + +/** + * org.redisson.api.RedissonClient帮助类 + * @author xsx + * @date 2019/5/16 + * @since 1.8 + */ +public class RedissonClientHelper { + + /** + * 获取客户端名称 + * @return 返回客户端名称 + */ + public static String getClientName() { + return "redisson"; + } + + /** + * 获取客户端类型 + * @return 返回客户端类型 + */ + public static Class getClientType() { + return RedissonClient.class; + } + + /** + * 创建客户端 + * @param dbIndex 数据库索引 + * @return 返回客户端 + */ + public static RedissonClient createClient(int dbIndex) { + return Redisson.create( + ApplicationContextUtil.getContext() + .getBean(RedissonAutoConfiguration.class) + .createConfig(dbIndex) + ); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionConfiguration.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionConfiguration.java new file mode 100644 index 0000000..f16077c --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionConfiguration.java @@ -0,0 +1,434 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson; + +import org.redisson.cluster.ClusterConnectionManager; +import org.redisson.config.*; +import org.redisson.connection.*; +import org.springframework.data.redis.connection.RedisConfiguration; +import org.springframework.util.Assert; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; +import java.util.UUID; + +/** + * redisson配置类 + * 重写org.redisson.config.RedissonConnectionConfiguration + * @author xsx + * @date 2019/5/14 + * @since 1.8 + */ +public class RedissonConnectionConfiguration extends Config implements RedisConfiguration { + /** + * 哨兵配置 + */ + private SentinelServersConfig sentinelServersConfig; + /** + * 主从配置 + */ + private MasterSlaveServersConfig masterSlaveServersConfig; + /** + * 单机配置 + */ + private SingleServerConfig singleServerConfig; + /** + * 集群配置 + */ + private ClusterServersConfig clusterServersConfig; + /** + * 云托管配置 + */ + private ReplicatedServersConfig replicatedServersConfig; + /** + * 连接管理器 + */ + private ConnectionManager connectionManager; + /** + * 数据库索引 + */ + private int database = 0; + + /** + * 无参构造 + */ + public RedissonConnectionConfiguration() { + } + + /** + * 获取哨兵配置 + * @return 返回哨兵配置 + */ + public SentinelServersConfig getSentinelServersConfig() { + return sentinelServersConfig; + } + + /** + * 设置哨兵配置 + * @param sentinelServersConfig 哨兵配置 + */ + public void setSentinelServersConfig(SentinelServersConfig sentinelServersConfig) { + this.sentinelServersConfig = sentinelServersConfig; + } + + /** + * 获取主从配置 + * @return 返回主从配置 + */ + public MasterSlaveServersConfig getMasterSlaveServersConfig() { + return masterSlaveServersConfig; + } + + /** + * 设置主从配置 + * @param masterSlaveServersConfig 主从配置 + */ + public void setMasterSlaveServersConfig(MasterSlaveServersConfig masterSlaveServersConfig) { + this.masterSlaveServersConfig = masterSlaveServersConfig; + } + + /** + * 获取单机配置 + * @return 返回单机配置 + */ + public SingleServerConfig getSingleServerConfig() { + return singleServerConfig; + } + + /** + * 设置单机配置 + * @param singleServerConfig 单机配置 + */ + public void setSingleServerConfig(SingleServerConfig singleServerConfig) { + this.singleServerConfig = singleServerConfig; + } + + /** + * 获取集群配置 + * @return 返回集群配置 + */ + public ClusterServersConfig getClusterServersConfig() { + return clusterServersConfig; + } + + /** + * 设置集群配置 + * @param clusterServersConfig 集群配置 + */ + public void setClusterServersConfig(ClusterServersConfig clusterServersConfig) { + this.clusterServersConfig = clusterServersConfig; + } + + /** + * 获取云托管配置 + * @return 返回云托管配置 + */ + public ReplicatedServersConfig getReplicatedServersConfig() { + return replicatedServersConfig; + } + + /** + * 设置云托管配置 + * @param replicatedServersConfig 云托管配置 + */ + public void setReplicatedServersConfig(ReplicatedServersConfig replicatedServersConfig) { + this.replicatedServersConfig = replicatedServersConfig; + } + + /** + * 获取连接管理器 + * @return 返回连接管理器 + */ + public ConnectionManager getConnectionManager() { + return connectionManager; + } + + /** + * 设置连接管理器 + * @param connectionManager 连接管理器 + */ + public void setConnectionManager(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + } + + /** + * 使用自定义模式 + * @param connectionManager 连接管理器 + */ + @Override + public void useCustomServers(ConnectionManager connectionManager) { + super.useCustomServers(connectionManager); + this.connectionManager = connectionManager; + this.initDatabase(); + } + + /** + * 获取配置(json格式) + * @param content 配置内容 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromJSON(String content) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromJSON(content, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(json格式) + * @param inputStream 配置内容 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromJSON(InputStream inputStream) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromJSON(inputStream, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(json格式) + * @param file 配置文件 + * @param classLoader 类加载器 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromJSON(File file, ClassLoader classLoader) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromJSON(file, RedissonConnectionConfiguration.class, classLoader); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(json格式) + * @param file 配置文件 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromJSON(File file) throws IOException { + return fromJSON(file, null); + } + + /** + * 获取配置(json格式) + * @param url 配置文件路径 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromJSON(URL url) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromJSON(url, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(json格式) + * @param reader 配置文件读取器 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromJSON(Reader reader) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromJSON(reader, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 配置转为字符串 + * @return 返回字符串 + * @throws IOException + */ + @Override + public String toJSON() throws IOException { + return new ConfigSupport().toJSON(this); + } + + /** + * 获取配置(yml格式) + * @param content 配置内容 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromYAML(String content) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromYAML(content, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(yml格式) + * @param inputStream 配置内容 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromYAML(InputStream inputStream) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromYAML(inputStream, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(yml格式) + * @param file 配置文件 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromYAML(File file) throws IOException { + return fromYAML(file, null); + } + + /** + * 获取配置(yml格式) + * @param file 配置文件 + * @param classLoader 类加载器 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromYAML(File file, ClassLoader classLoader) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromYAML(file, RedissonConnectionConfiguration.class, classLoader); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(yml格式) + * @param url 配置文件路径 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromYAML(URL url) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromYAML(url, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 获取配置(yml格式) + * @param reader 配置文件读取器 + * @return 返回配置 + * @throws IOException + */ + public static RedissonConnectionConfiguration fromYAML(Reader reader) throws IOException { + RedissonConnectionConfiguration configuration = new ConfigSupport().fromYAML(reader, RedissonConnectionConfiguration.class); + configuration.useCustomServers(createConnectionManager(configuration)); + return configuration; + } + + /** + * 配置转为字符串 + * @return 返回字符串 + * @throws IOException + */ + @Override + public String toYAML() throws IOException { + return new ConfigSupport().toYAML(this); + } + + /** + * 创建连接管理器 + * @param configCopy 配置 + * @return 返回连接管理器 + */ + public static ConnectionManager createConnectionManager(RedissonConnectionConfiguration configCopy) { + UUID id = UUID.randomUUID(); + + if (configCopy.getMasterSlaveServersConfig() != null) { + validate(configCopy.getMasterSlaveServersConfig()); + return new MasterSlaveConnectionManager(configCopy.getMasterSlaveServersConfig(), configCopy, id); + } else if (configCopy.getSingleServerConfig() != null) { + validate(configCopy.getSingleServerConfig()); + return new SingleConnectionManager(configCopy.getSingleServerConfig(), configCopy, id); + } else if (configCopy.getSentinelServersConfig() != null) { + validate(configCopy.getSentinelServersConfig()); + return new SentinelConnectionManager(configCopy.getSentinelServersConfig(), configCopy, id); + } else if (configCopy.getClusterServersConfig() != null) { + validate(configCopy.getClusterServersConfig()); + return new ClusterConnectionManager(configCopy.getClusterServersConfig(), configCopy, id); + } else if (configCopy.getReplicatedServersConfig() != null) { + validate(configCopy.getReplicatedServersConfig()); + return new ReplicatedConnectionManager(configCopy.getReplicatedServersConfig(), configCopy, id); + } else if (configCopy.getConnectionManager() != null) { + return configCopy.getConnectionManager(); + }else { + throw new IllegalArgumentException("server(s) address(es) not defined!"); + } + } + + /** + * 验证配置 + * @param config 配置 + */ + private static void validate(SingleServerConfig config) { + if (config.getConnectionPoolSize() < config.getConnectionMinimumIdleSize()) { + throw new IllegalArgumentException("connectionPoolSize can't be lower than connectionMinimumIdleSize"); + } + } + + /** + * 验证配置 + * @param config 配置 + */ + private static void validate(BaseMasterSlaveServersConfig config) { + if (config.getSlaveConnectionPoolSize() < config.getSlaveConnectionMinimumIdleSize()) { + throw new IllegalArgumentException("slaveConnectionPoolSize can't be lower than slaveConnectionMinimumIdleSize"); + } + if (config.getMasterConnectionPoolSize() < config.getMasterConnectionMinimumIdleSize()) { + throw new IllegalArgumentException("masterConnectionPoolSize can't be lower than masterConnectionMinimumIdleSize"); + } + if (config.getSubscriptionConnectionPoolSize() < config.getSubscriptionConnectionMinimumIdleSize()) { + throw new IllegalArgumentException("slaveSubscriptionConnectionMinimumIdleSize can't be lower than slaveSubscriptionConnectionPoolSize"); + } + } + + /** + * 设置数据库索引 + * @param index 数据库索引 + */ + public void setDatabase(int index) { + Assert.isTrue(index >= 0, "invalid DB index (a positive index required)"); + this.database = index; + if (this.isSentinelConfig()) { + this.getSentinelServersConfig().setDatabase(this.database); + }else if (this.isClusterConfig()) { + this.database = 0; + }else if (this.getReplicatedServersConfig()!=null) { + this.getReplicatedServersConfig().setDatabase(this.database); + }else { + if (this.getMasterSlaveServersConfig()!=null) { + this.getMasterSlaveServersConfig().setDatabase(this.database); + }else { + this.getSingleServerConfig().setDatabase(this.database); + } + } + } + + /** + * 获取数据库索引 + * @return 返回数据库索引 + */ + public int getDatabase() { + if (this.isSentinelConfig()) { + this.database = this.getSentinelServersConfig().getDatabase(); + }else if (this.isClusterConfig()) { + this.database = 0; + }else if (this.getReplicatedServersConfig()!=null) { + this.database = this.getReplicatedServersConfig().getDatabase(); + }else { + if (this.getMasterSlaveServersConfig()!=null) { + this.database = this.getMasterSlaveServersConfig().getDatabase(); + }else { + this.database = this.getSingleServerConfig().getDatabase(); + } + } + return this.database; + } + + /** + * 初始化数据库索引 + */ + private void initDatabase() { + this.getDatabase(); + } + +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionFactory.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionFactory.java new file mode 100644 index 0000000..3122071 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonConnectionFactory.java @@ -0,0 +1,132 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.RedisClient; +import org.redisson.client.protocol.RedisCommands; +import org.redisson.connection.SentinelConnectionManager; +import org.redisson.reactive.CommandReactiveService; +import org.redisson.spring.data.connection.*; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.data.redis.ExceptionTranslationStrategy; +import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; +import org.springframework.data.redis.connection.*; +import org.springframework.util.Assert; + +/** + * redisson连接工厂 + * 重写org.redisson.spring.data.connection.RedissonConnectionFactory + * @author xsx + * @date 2019/5/14 + * @since 1.8 + */ +public class RedissonConnectionFactory implements RedisConnectionFactory, + ReactiveRedisConnectionFactory, InitializingBean, DisposableBean { + + private final static Log log = LogFactory.getLog(RedissonConnectionFactory.class); + + public static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = + new PassThroughExceptionTranslationStrategy(new RedissonExceptionConverter()); + + private RedissonConnectionConfiguration configuration; + private RedissonClient redisson; + + public RedissonConnectionFactory() { + this(Redisson.create()); + } + + public RedissonConnectionFactory(RedissonClient redisson) { + this.redisson = redisson; + this.configuration = (RedissonConnectionConfiguration) this.redisson.getConfig(); + } + + public RedissonConnectionFactory(RedissonConnectionConfiguration configuration) { + super(); + this.configuration = configuration; + } + + @Override + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return EXCEPTION_TRANSLATION.translate(ex); + } + + @Override + public void destroy() { + } + + @Override + public void afterPropertiesSet() { + if (configuration != null) { + redisson = Redisson.create(configuration); + } + } + + @Override + public RedisConnection getConnection() { + return new RedissonConnection(redisson); + } + + @Override + public RedisClusterConnection getClusterConnection() { + if (!redisson.getConfig().isClusterConfig()) { + throw new InvalidDataAccessResourceUsageException("Redisson is not in Cluster mode"); + } + return new RedissonClusterConnection(redisson); + } + + @Override + public boolean getConvertPipelineAndTxResults() { + return true; + } + + @Override + public RedisSentinelConnection getSentinelConnection() { + if (!redisson.getConfig().isSentinelConfig()) { + throw new InvalidDataAccessResourceUsageException("Redisson is not in Sentinel mode"); + } + + SentinelConnectionManager manager = ((SentinelConnectionManager)((Redisson)redisson).getConnectionManager()); + for (RedisClient client : manager.getSentinels()) { + org.redisson.client.RedisConnection connection = client.connect(); + try { + String res = connection.sync(RedisCommands.PING); + if ("pong".equalsIgnoreCase(res)) { + return new RedissonSentinelConnection(connection); + } + } catch (Exception e) { + log.warn("Can't connect to " + client, e); + connection.closeAsync(); + } + } + + throw new InvalidDataAccessResourceUsageException("Sentinels are not found"); + } + + @Override + public ReactiveRedisConnection getReactiveConnection() { + return new RedissonReactiveRedisConnection(new CommandReactiveService(((Redisson)redisson).getConnectionManager())); + } + + @Override + public ReactiveRedisClusterConnection getReactiveClusterConnection() { + return new RedissonReactiveRedisClusterConnection(new CommandReactiveService(((Redisson)redisson).getConnectionManager())); + } + + public int getDatabase() { + return RedisConfiguration.getDatabaseOrElse(configuration, configuration::getDatabase); + } + + public void setDatabase(int index) { + Assert.isTrue(index >= 0, "invalid DB index (a positive index required)"); + if (RedisConfiguration.isDatabaseIndexAware(configuration)) { + ((RedisConfiguration.WithDatabaseIndex) configuration).setDatabase(index); + return; + } + this.configuration.setDatabase(index); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonProperties.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonProperties.java new file mode 100644 index 0000000..13bb7a7 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/config/redisson/RedissonProperties.java @@ -0,0 +1,25 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * redisson配置类 + * 重写org.redisson.spring.starter.RedissonProperties + * @author xsx + * @date 2019/5/10 + * @since 1.8 + */ +@ConfigurationProperties(prefix = "spring.redis.redisson") +public class RedissonProperties { + + private String config; + + public String getConfig() { + return config; + } + + public void setConfig(String config) { + this.config = config; + } + +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/BitmapHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/BitmapHandler.java new file mode 100644 index 0000000..36726bb --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/BitmapHandler.java @@ -0,0 +1,279 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.data.domain.Range; +import org.springframework.data.redis.connection.BitFieldSubCommands; +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 位图助手 + * @author xsx + * @date 2019/4/22 + * @since 1.8 + */ +public final class BitmapHandler implements RedisHandler { + + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 字符串命令 + */ + private RedisStringCommands commands; + + /** + * 位图助手构造 + * @param dbIndex 数据库索引 + */ + BitmapHandler(Integer dbIndex) { + this.stringRedisTemplate = HandlerManager.createStringRedisTemplate(dbIndex); + this.commands = this.stringRedisTemplate.getRequiredConnectionFactory().getConnection().stringCommands(); + } + + /** + * 位图助手构造 + * @param transactionHandler 事务助手 + */ + BitmapHandler(TransactionHandler transactionHandler) { + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.commands = this.stringRedisTemplate.getRequiredConnectionFactory().getConnection().stringCommands(); + } + + /** + * 设置位 + * @see Redis Documentation: SETBIT + * @since redis 2.2.0 + * @param key 键 + * @param offset 偏移量 + * @param bit 位值,true=1,false=0 + * @return 返回布尔值 + */ + public Boolean set(String key, Long offset, boolean bit) { + return this.stringRedisTemplate.opsForValue().setBit(key, offset, bit); + } + + /** + * 获取位 + * @see Redis Documentation: GETBIT + * @since redis 2.2.0 + * @param key 键 + * @param offset 偏移量 + * @return 返回布尔值 + */ + public Boolean get(String key, Long offset) { + return this.stringRedisTemplate.opsForValue().getBit(key, offset); + } + + /** + * 位长度 + * @see Redis Documentation: GET + * @since redis 2.2.0 + * @param key 键 + * @return 返回位的总长度 + */ + public Long bitLength(String key) { + String s = this.stringRedisTemplate.opsForValue().get(key); + if (s==null) { + return 0L; + } + return (long) (s.length()<<3); + } + + /** + * 二进制 + * @see Redis Documentation: GET + * @since redis 2.2.0 + * @param key 键 + * @return 返回二进制字符串 + */ + public String binary(String key) { + String value = this.stringRedisTemplate.opsForValue().get(key); + if (value==null) { + return null; + } + char[] chars = value.toCharArray(); + int count = chars.length; + int length = count<<3; + int bit = 8; + StringBuilder builder = new StringBuilder(length); + for (char aChar : chars) { + for (int j = bit - 1; j >= 0; j--) { + builder.append(aChar >>> j & 1); + } + builder.append(' '); + } + return builder.substring(0, length+count-1); + } + + /** + * 统计 + * @see Redis Documentation: BITCOUNT + * @since redis 2.6.0 + * @param key 键 + * @return 返回统计总数 + */ + public Long count(String key) { + return this.commands.bitCount( + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), key) + ); + } + + /** + * 统计 + * @see Redis Documentation: BITCOUNT + * @since redis 2.6.0 + * @param key 键 + * @param startIndex 开始字节索引 + * @param endIndex 结束字节索引 + * @return 返回统计总数 + */ + public Long count(String key, Long startIndex, Long endIndex) { + final long startByteIndex = startIndex << 3; + final long endByteIndex = endIndex << 3; + return this.commands.bitCount( + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), key), + startByteIndex, + endByteIndex + ); + } + + /** + * 定位 + * @see Redis Documentation: BITPOS + * @since redis 2.8.7 + * @param key 键 + * @param bit 位值,true=1,false=0 + * @return 返回二进制中首次出现的索引 + */ + public Long position(String key, boolean bit) { + return this.commands.bitPos( + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), key), + bit + ); + } + + /** + * 定位 + * @see Redis Documentation: BITPOS + * @since redis 2.8.7 + * @param key 键 + * @param bit 位值,true=1,false=0 + * @param startIndex 开始字节索引 + * @param endIndex 结束字节索引 + * @return 返回二进制中首次出现的索引 + */ + public Long position(String key, boolean bit, Long startIndex, Long endIndex) { + final Range range = Range.of(Range.Bound.inclusive(startIndex), Range.Bound.inclusive(endIndex)); + return this.commands.bitPos( + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), key), + bit, + range + ); + } + + /** + * 逻辑与 + * @see Redis Documentation: BITPOS + * @since redis 2.6.0 + * @param storeKey 存储键 + * @param keys 键 + * @return 返回最长字符串长度 + */ + public Long bitOpWithAnd(String storeKey, String ...keys) { + final byte[][] keyBytes = ConvertUtil.toByteArray(RedisSerializer.string(), keys); + return this.commands.bitOp( + RedisStringCommands.BitOperation.AND, + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), storeKey), + keyBytes + ); + } + + /** + * 逻辑或 + * @see Redis Documentation: BITPOS + * @since redis 2.6.0 + * @param storeKey 存储键 + * @param keys 键 + * @return 返回最长字符串长度 + */ + public Long bitOpWithOr(String storeKey, String ...keys) { + final byte[][] keyBytes = ConvertUtil.toByteArray(RedisSerializer.string(), keys); + return this.commands.bitOp( + RedisStringCommands.BitOperation.OR, + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), storeKey), + keyBytes + ); + } + + /** + * 逻辑异或 + * @see Redis Documentation: BITPOS + * @since redis 2.6.0 + * @param storeKey 存储键 + * @param keys 键 + * @return 返回最长字符串长度 + */ + public Long bitOpWithXor(String storeKey, String ...keys) { + final byte[][] keyBytes = ConvertUtil.toByteArray(RedisSerializer.string(), keys); + return this.commands.bitOp( + RedisStringCommands.BitOperation.XOR, + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), storeKey), + keyBytes + ); + } + + /** + * 逻辑非 + * @see Redis Documentation: BITPOS + * @since redis 2.6.0 + * @param storeKey 存储键 + * @param key 键 + * @return 返回最长字符串长度 + */ + public Long bitOpWithNot(String storeKey, String key) { + final byte[] keyBytes = ConvertUtil.toBytes(RedisSerializer.string(), key); + return this.commands.bitOp( + RedisStringCommands.BitOperation.NOT, + ConvertUtil.toBytes(this.stringRedisTemplate.getKeySerializer(), storeKey), + keyBytes + ); + } + + /** + * 多位操作 + * @see Redis Documentation: BITFIELD + * @since redis 3.2.0 + * @param key 键 + * @param commands 指令 + * @return 返回指令结果列表(十进制) + */ + public List bitField(String key, BitFieldSubCommands commands) { + return this.stringRedisTemplate.opsForValue().bitField(key, commands); + } + + /** + * 移除字符串 + * @see Redis Documentation: DEL + * @since redis 1.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long remove(String ...keys) { + return this.stringRedisTemplate.opsForValue().getOperations().delete(Arrays.asList(keys)); + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ClusterHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ClusterHandler.java new file mode 100644 index 0000000..bba480a --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ClusterHandler.java @@ -0,0 +1,294 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.springframework.data.redis.connection.ClusterInfo; +import org.springframework.data.redis.connection.RedisClusterCommands; +import org.springframework.data.redis.connection.RedisClusterNode; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 集群助手 + * @author xsx + * @date 2019/5/31 + * @since 1.8 + */ +public final class ClusterHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 连接工厂 + */ + private RedisConnectionFactory connectionFactory; + + /** + * 集群助手构造 + * @param dbIndex 数据库索引 + */ + ClusterHandler(Integer dbIndex) { + this(HandlerManager.createRedisTemplate(dbIndex)); + } + + /** + * 集群助手构造 + * @param redisTemplate 对象模板 + */ + @SuppressWarnings("unchecked") + ClusterHandler(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + this.connectionFactory = this.redisTemplate.getRequiredConnectionFactory(); + } + + /** + * 集群助手构造 + * @param transactionHandler 事务助手 + */ + ClusterHandler(TransactionHandler transactionHandler) { + this(transactionHandler.getRedisTemplate()); + } + + /** + * 集群信息 + * @see Redis Documentation: CLUSTER INFO + * @since redis 3.0.0 + * @return 返回集群信息 + */ + public ClusterInfo info() { + return this.connectionFactory.getClusterConnection().clusterGetClusterInfo(); + } + + /** + * 集群节点 + * @see Redis Documentation: CLUSTER NODES + * @since redis 3.0.0 + * @return 返回集群节点 + */ + public Iterable nodes() { + return this.connectionFactory.getClusterConnection().clusterGetNodes(); + } + + /** + * 从节点集合 + * @see Redis Documentation: CLUSTER SLAVES + * @since redis 3.0.0 + * @param masterId 主节点id + * @return 返回从节点集合 + */ + public Collection slaves(String masterId) { + return this.connectionFactory + .getClusterConnection() + .clusterGetSlaves(RedisClusterNode.newRedisClusterNode().withId(masterId).build()); + } + + /** + * 主从节点字典 + * @see Redis Documentation: CLUSTER SLAVES + * @since redis 3.0.0 + * @return 返回主从节点字典 + */ + public Map> masterSlaves() { + return this.connectionFactory.getClusterConnection().clusterGetMasterSlaveMap(); + } + + /** + * 根据键获取节点 + * @param key 键 + * @return 返回节点 + */ + public RedisClusterNode nodeForKey(String key) { + return this.connectionFactory + .getClusterConnection() + .clusterGetNodeForKey(ConvertUtil.toBytes(this.redisTemplate.getKeySerializer(), key)); + } + + /** + * 根据键获取节点 + * @param slotIndex 槽索引 + * @return 返回节点 + */ + public RedisClusterNode nodeForSlot(int slotIndex) { + return this.connectionFactory.getClusterConnection().clusterGetNodeForSlot(slotIndex); + } + + /** + * 连接集群节点 + * @see Redis Documentation: CLUSTER MEET + * @since redis 3.0.0 + * @param clusterNode 集群节点 + */ + public void meet(RedisClusterNode clusterNode) { + this.connectionFactory.getClusterConnection().clusterMeet(clusterNode); + } + + /** + * 连接集群节点 + * @see Redis Documentation: CLUSTER MEET + * @since redis 3.0.0 + * @param ip 服务器IP + * @param port 服务器端口 + */ + public void meet(String ip, String port) { + this.connectionFactory + .getClusterConnection() + .clusterMeet( + RedisClusterNode.newRedisClusterNode().listeningAt(ip, Integer.valueOf(port)).build() + ); + } + + /** + * 移除节点 + * @see Redis Documentation: CLUSTER FORGET + * @since redis 3.0.0 + * @param clusterNode 节点 + */ + public void forget(RedisClusterNode clusterNode) { + this.connectionFactory.getClusterConnection().clusterForget(clusterNode); + } + + /** + * 移除节点 + * @see Redis Documentation: CLUSTER FORGET + * @since redis 3.0.0 + * @param nodeId 节点id + */ + public void forget(String nodeId) { + this.connectionFactory + .getClusterConnection() + .clusterForget( + RedisClusterNode.newRedisClusterNode().withId(nodeId).build() + ); + } + + /** + * 设置从节点 + * @see Redis Documentation: CLUSTER REPLICATE + * @since redis 3.0.0 + * @param master 主节点 + * @param replica 从节点 + */ + public void replicate(RedisClusterNode master, RedisClusterNode replica) { + this.connectionFactory.getClusterConnection().clusterReplicate(master, replica); + } + + /** + * 添加槽 + * @see Redis Documentation: CLUSTER ADDSLOTS + * @since redis 3.0.0 + * @param clusterNode 节点 + * @param slotIndex 槽索引 + */ + public void addSlot(RedisClusterNode clusterNode, int ...slotIndex) { + this.connectionFactory.getClusterConnection().clusterAddSlots(clusterNode, slotIndex); + } + + /** + * 添加槽 + * @see Redis Documentation: CLUSTER ADDSLOTS + * @since redis 3.0.0 + * @param clusterNode 节点 + * @param beginSlotIndex 槽开始索引 + * @param endSlotIndex 槽结束索引 + */ + public void addSlotInRange(RedisClusterNode clusterNode, int beginSlotIndex, int endSlotIndex) { + this.connectionFactory + .getClusterConnection() + .clusterAddSlots(clusterNode, new RedisClusterNode.SlotRange(beginSlotIndex, endSlotIndex)); + } + + /** + * 移除槽 + * @see Redis Documentation: CLUSTER DELSLOTS + * @since redis 3.0.0 + * @param clusterNode 节点 + * @param slotIndex 槽索引 + */ + public void removeSlot(RedisClusterNode clusterNode, int ...slotIndex) { + this.connectionFactory.getClusterConnection().clusterDeleteSlots(clusterNode, slotIndex); + } + + /** + * 移除槽 + * @see Redis Documentation: CLUSTER DELSLOTS + * @since redis 3.0.0 + * @param clusterNode 节点 + * @param beginSlotIndex 槽开始索引 + * @param endSlotIndex 槽结束索引 + */ + public void removeSlotInRange(RedisClusterNode clusterNode, int beginSlotIndex, int endSlotIndex) { + this.connectionFactory + .getClusterConnection() + .clusterDeleteSlotsInRange(clusterNode, new RedisClusterNode.SlotRange(beginSlotIndex, endSlotIndex)); + } + + /** + * 设置槽 + * @see Redis Documentation: CLUSTER SETSLOT + * @since redis 3.0.0 + * @param node 节点 + * @param slotIndex 槽索引 + * @param mode 模式 + */ + public void setSlot(RedisClusterNode node, int slotIndex, RedisClusterCommands.AddSlots mode) { + this.connectionFactory.getClusterConnection().clusterSetSlot(node, slotIndex, mode); + } + + /** + * 键对应的槽 + * @see Redis Documentation: CLUSTER KEYSLOT + * @since redis 3.0.0 + * @param key 键 + * @return 返回槽索引 + */ + public Integer keySlot(String key) { + return this.connectionFactory + .getClusterConnection() + .clusterGetSlotForKey(ConvertUtil.toBytes(this.redisTemplate.getKeySerializer(), key)); + } + + /** + * 在指定槽中键的数量 + * @see Redis Documentation: CLUSTER COUNTKEYSINSLOT + * @since redis 3.0.0 + * @param slotIndex 槽索引 + * @return 返回键的数量 + */ + public Long countKeyInSlot(int slotIndex) { + return this.connectionFactory.getClusterConnection().clusterCountKeysInSlot(slotIndex); + } + + /** + * 在指定槽中键的列表 + * @see Redis Documentation: CLUSTER GETKEYSINSLOT + * @since redis 3.0.0 + * @param slotIndex 槽索引 + * @param count 返回数量 + * @return 返回键的列表 + */ + public List keysInSlot(int slotIndex, Integer count) { + List byteList = this.connectionFactory.getClusterConnection().clusterGetKeysInSlot(slotIndex, count); + if (byteList!=null&&byteList.size()>0) { + List keys = new ArrayList<>(byteList.size()); + for (byte[] bytes : byteList) { + keys.add(ConvertUtil.toStr(this.redisTemplate.getKeySerializer(), bytes)); + } + return keys; + } + return new ArrayList<>(0); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/CustomCommandHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/CustomCommandHandler.java new file mode 100644 index 0000000..e58f8ff --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/CustomCommandHandler.java @@ -0,0 +1,144 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.lettuce.LettuceConnection; +import org.springframework.data.redis.core.RedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.lettuce.LettuceTypeHint; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 自定义命令助手 + * @author xsx + * @date 2019/6/6 + * @since 1.8 + */ +public final class CustomCommandHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + + /** + * 自定义命令助手构造 + * @param dbIndex 数据库索引 + */ + CustomCommandHandler(Integer dbIndex) { + this.redisTemplate = HandlerManager.createRedisTemplate(dbIndex); + } + + /** + * 自定义命令助手构造 + * @param transactionHandler 事务助手 + */ + CustomCommandHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + } + + /** + * 执行redis命令 + * @param command 命令 + * @param args 参数列表 + * @return 返回信息 + */ + public Object execute(String command, byte[] ...args) { + return this.executeCommand(command, args); + } + + /** + * 序列化对象 + * @param value 对象 + * @return 返回字节数组 + */ + public byte[] serializeAsObj(Object value) { + return ConvertUtil.toBytes(this.redisTemplate.getValueSerializer(), value); + } + + /** + * 序列化字符串 + * @param value 字符串 + * @return 返回字节数组 + */ + public byte[] serialize(String value) { + return ConvertUtil.toBytes(this.redisTemplate.getKeySerializer(), value); + } + + /** + * 反序列化对象 + * @param bytes 字节数组 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T deserializeAsObj(byte[] bytes) { + return (T) ConvertUtil.toJavaType(this.redisTemplate.getValueSerializer().deserialize(bytes), Object.class); + } + + /** + * 反序列化对象 + * @param type 返回值类型 + * @param bytes 字节数组 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T deserializeAsObj(Class type, byte[] bytes) { + return (T) ConvertUtil.toJavaType(this.redisTemplate.getValueSerializer().deserialize(bytes), type); + } + + /** + * 反序列化字符串 + * @param bytes 字节数组 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T deserialize(byte[] bytes) { + return (T) this.redisTemplate.getKeySerializer().deserialize(bytes); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 执行命令 + * @param command 命令 + * @param args 参数列表 + * @return 返回结果 + */ + private Object executeCommand(String command, byte[] ...args) { + RedisConnection connection = this.redisTemplate.getRequiredConnectionFactory().getConnection(); + if (connection instanceof LettuceConnection) { + return this.executeCommandByLettuce(connection, command, args); + } + return connection.execute(command, args); + } + + /** + * 执行命令(lettuce客户端) + * @param connection 连接对象 + * @param command 命令 + * @param args 参数列表 + * @return 返回结果 + */ + private Object executeCommandByLettuce(RedisConnection connection, String command, byte[] ...args) { + if (args.length>0) { + return ((LettuceConnection) connection).execute( + command, + LettuceTypeHint.getTypeHint(command, this.deserialize(args[0])), + args + ); + }else { + return ((LettuceConnection) connection).execute( + command, + LettuceTypeHint.getTypeHint(command, null), + args + ); + } + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/DBHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/DBHandler.java new file mode 100644 index 0000000..90dbc1f --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/DBHandler.java @@ -0,0 +1,385 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.time.Clock; +import java.util.List; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.data.redis.serializer.RedisSerializer; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.RedisUtil; + +/** + * 数据库助手 + * @author xsx + * @date 2019/4/25 + * @since 1.8 + */ +public final class DBHandler implements RedisHandler { + /** + * 数据库信息选项枚举 + */ + public enum DBOption { + /** + * Redis服务器的一般信息 + */ + SERVER("server"), + /** + * 客户端的连接部分相关信息 + */ + CLIENTS("clients"), + /** + * 内存消耗相关信息 + */ + MEMORY("memory"), + /** + * RDB和AOF相关信息 + */ + PERSISTENCE("persistence"), + /** + * 一般统计信息 + */ + STATS("stats"), + /** + * 主/从复制信息 + */ + REPLICATION("replication"), + /** + * CPU的相关信息 + */ + CPU("cpu"), + /** + * Redis命令统计相关信息 + */ + COMMANDSTATS("commandstats"), + /** + * Redis集群信息 + */ + CLUSTER("cluster"), + /** + * 数据库的相关统计信息 + */ + KEYSPACE("keyspace"), + /** + * 所有信息 + */ + ALL("all"), + /** + * 默认设置的信息 + */ + DEFAULT("default"); + + /** + * 选项 + */ + private String option; + + /** + * 选项枚举构造 + * @param option 选项 + */ + DBOption(String option) { + this.option = option; + } + } + + /** + * 日志 + */ + private static final Logger log = LoggerFactory.getLogger(DBHandler.class); + /** + * 时钟 + */ + private static final Clock CLOCK = Clock.systemDefaultZone(); + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 数据库索引 + */ + private int dbIndex; + + /** + * 数据库助手构造 + * @param dbIndex 数据库索引 + */ + DBHandler(Integer dbIndex) { + this.dbIndex = dbIndex; + this.redisTemplate = HandlerManager.createRedisTemplate(dbIndex); + } + + /** + * 数据库助手构造 + * @param transactionHandler 事务助手 + */ + DBHandler(TransactionHandler transactionHandler) { + this.dbIndex = transactionHandler.getDbIndex(); + this.redisTemplate = transactionHandler.getRedisTemplate(); + } + + /** + * 获取当前数据库索引 + * @since redis 1.0.0 + * @return 返回当前数据库索引 + */ + public int getDBIndex() { + return this.dbIndex; + } + + /** + * 获取当前数据库信息 + * @see Redis Documentation: INFO + * @since redis 1.0.0 + * @return 返回当前数据库信息 + */ + public Properties getDBInfo() { + return this.redisTemplate.getRequiredConnectionFactory().getConnection().serverCommands().info(); + } + + /** + * 获取当前数据库信息 + * @see Redis Documentation: INFO + * @since redis 1.0.0 + * @param dbOption 选项 + *

SERVER: Redis服务器的一般信息

+ *

CLIENTS: 客户端的连接部分相关信息

+ *

MEMORY: 内存消耗相关信息

+ *

PERSISTENCE: RDB和AOF相关信息

+ *

STATS: 一般统计信息

+ *

REPLICATION: 主/从复制信息

+ *

CPU: CPU的相关信息

+ *

COMMANDSTATS: Redis命令统计相关信息

+ *

CLUSTER: Redis集群信息

+ *

KEYSPACE: 数据库的相关统计信息

+ *

ALL: 所有信息

+ *

DEFAULT: 默认设置的信息

+ * @return 返回当前数据库信息 + */ + public Properties getDBInfo(DBOption dbOption) { + RedisServerCommands serverCommands = this.redisTemplate.getRequiredConnectionFactory().getConnection().serverCommands(); + if (dbOption!=null) { + return serverCommands.info(dbOption.option); + } + return serverCommands.info(DBOption.DEFAULT.option); + } + + /** + * 清理当前数据库 + * @see Redis Documentation: FLUSHDB + * @since redis 1.0.0 + */ + public void clearDB() { + try { + this.redisTemplate.getRequiredConnectionFactory().getConnection().serverCommands().flushDb(); + }catch (IllegalStateException e) { + log.error(e.getMessage()); + } + } + + /** + * 清理所有数据库 + * @see Redis Documentation: FLUSHALL + * @since redis 1.0.0 + */ + public void clearDBAll() { + try { + this.redisTemplate.getRequiredConnectionFactory().getConnection().serverCommands().flushAll(); + }catch (IllegalStateException e) { + log.error(e.getMessage()); + } + } + + /** + * 设置数据库配置参数 + * @see Redis Documentation: CONFIG SET + * @since redis 2.0.0 + * @param param 参数名 + * @param value 参数值 + */ + public void setConfig(String param, String value) { + this.redisTemplate.getRequiredConnectionFactory().getConnection().setConfig(param, value); + } + + /** + * 获取数据库配置信息 + * @see Redis Documentation: CONFIG GET + * @since redis 2.0.0 + * @param param 参数名 + * @return 返回数据库配置信息 + */ + public Properties getConfig(String param) { + return this.redisTemplate.getRequiredConnectionFactory().getConnection().getConfig(param); + } + + /** + * 重置配置状态 + * @see Redis Documentation: CONFIG RESETSTAT + * @since redis 2.0.0 + */ + public void resetConfigStats() { + this.redisTemplate.getRequiredConnectionFactory().getConnection().resetConfigStats(); + } + + /** + * 设置客户端连接名称 + * @see Redis Documentation: CLIENT SETNAME + * @since redis 2.6.9 + * @param name 名称 + */ + public void setClientName(String name) { + this.redisTemplate + .getRequiredConnectionFactory() + .getConnection() + .setClientName(RedisSerializer.string().serialize(name)); + } + + /** + * 获取客户端连接名称 + * @see Redis Documentation: CLIENT GETNAME + * @since redis 2.6.9 + * @return 返回客户端连接名称 + */ + public String getClientName() { + return this.redisTemplate.getRequiredConnectionFactory().getConnection().getClientName(); + } + + /** + * 获取客户端连接列表 + * @return 返回客户端连接列表 + */ + public List getClientList() { + return this.redisTemplate.getRequiredConnectionFactory().getConnection().getClientList(); + } + + /** + * 关闭客户端 + * @param ip 客户端IP + * @param port 客户端端口 + */ + public void killClient(String ip, int port) { + this.redisTemplate.killClient(ip, port); + } + + /** + * 角色的信息 + * @see Redis Documentation: ROLE + * @since redis 2.8.12 + * @return 返回当前是master,slave还是sentinel + */ + @SuppressWarnings("unchecked") + public String getRole() { + CustomCommandHandler commandHandler = RedisUtil.getCustomCommandHandler(this.dbIndex); + List list = (List) commandHandler.execute("ROLE"); + return commandHandler.deserialize((byte[]) list.get(0)); + } + + /** + * 转为从服务器 + * @see Redis Documentation: SLAVEOF + * @since redis 1.0.0 + * @param ip 主服务器IP + * @param port 主服务器端口 + */ + public void slaveOf(String ip, int port) { + this.redisTemplate.slaveOf(ip, port); + } + + /** + * 转为主服务器 + * @see Redis Documentation: SLAVEOF NO ONE + * @since redis 1.0.0 + */ + public void slaveOfNoOne() { + this.redisTemplate.slaveOfNoOne(); + } + + /** + * 异步AOF文件重写 + * @see Redis Documentation: BGREWRITEAOF + * @since redis 1.0.0 + */ + public void bgReWriteAof() { + this.redisTemplate.getRequiredConnectionFactory().getConnection().bgReWriteAof(); + } + + /** + * 非阻塞式同步 + * @see Redis Documentation: BGSAVE + * @since redis 1.0.0 + */ + public void bgSave() { + this.redisTemplate.getRequiredConnectionFactory().getConnection().bgSave(); + } + + /** + * 阻塞式同步 + * @see Redis Documentation: SAVE + * @since redis 1.0.0 + */ + public void save() { + this.redisTemplate.getRequiredConnectionFactory().getConnection().save(); + } + + /** + * 最近一次保存的时间戳 + * @see Redis Documentation: LASTSAVE + * @since redis 1.0.0 + * @return 返回时间戳 + */ + public Long lastSave() { + return this.redisTemplate.getRequiredConnectionFactory().getConnection().lastSave(); + } + + /** + * 检查连接 + * @see Redis Documentation: PING + * @since redis 1.0.0 + * @return 返回延迟时间(ms) + */ + public Long ping() { + long begin = CLOCK.millis(); + this.redisTemplate.getRequiredConnectionFactory().getConnection().ping(); + long end = CLOCK.millis(); + return end - begin; + } + + /** + * 服务器时间 + * @see Redis Documentation: TIME + * @since redis 2.6.0 + * @return 返回服务器时间(ms) + */ + public Long time() { + return this.redisTemplate.getRequiredConnectionFactory().getConnection().serverCommands().time(); + } + + /** + * 测试打印 + * @see Redis Documentation: ECHO + * @since redis 1.0.0 + * @param message 信息 + * @return 返回打印信息 + */ + public String echo(String message) { + RedisSerializer serializer = RedisSerializer.string(); + return serializer.deserialize( + this.redisTemplate + .getRequiredConnectionFactory() + .getConnection() + .echo(serializer.serialize(message)) + ); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/GeoHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/GeoHandler.java new file mode 100644 index 0000000..4711360 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/GeoHandler.java @@ -0,0 +1,536 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.data.geo.Circle; +import org.springframework.data.geo.Distance; +import org.springframework.data.geo.GeoResults; +import org.springframework.data.geo.Metric; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.core.GeoOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 地理位置助手 + * @author xsx + * @date 2019/4/25 + * @since 1.8 + */ +public final class GeoHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private GeoOperations geoOperations; + /** + * 字符串模板 + */ + private GeoOperations stringGeoOperations; + + /** + * 地理位置助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + GeoHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.geoOperations = this.redisTemplate.opsForGeo(); + this.stringGeoOperations = this.stringRedisTemplate.opsForGeo(); + } + + /** + * 地理位置助手构造 + * @param transactionHandler 事务助手 + */ + GeoHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.geoOperations = this.redisTemplate.opsForGeo(); + this.stringGeoOperations = this.stringRedisTemplate.opsForGeo(); + } + + /** + * 添加对象 + * @see Redis Documentation: GEOADD + * @since redis 3.2.0 + * @param key 键 + * @param point 坐标 + * @param value 对象 + * @return 返回总数 + */ + public Long addAsObj(String key, Point point, Object value) { + return this.geoOperations.add(key, point, value); + } + + /** + * 添加字符串 + * @see Redis Documentation: GEOADD + * @since redis 3.2.0 + * @param key 键 + * @param point 坐标 + * @param value 字符串 + * @return 返回总数 + */ + public Long add(String key, Point point, String value) { + return this.stringGeoOperations.add(key, point, value); + } + + /** + * 添加对象 + * @see Redis Documentation: GEOADD + * @since redis 3.2.0 + * @param key 键 + * @param params 参数,键为待添加对象,值为待添加坐标 + * @return 返回总数 + */ + public Long addAsObj(String key, Map params) { + return this.geoOperations.add(key, params); + } + + /** + * 添加字符串 + * @see Redis Documentation: GEOADD + * @since redis 3.2.0 + * @param key 键 + * @param params 参数,键为待添加字符串,值为待添加坐标 + * @return 返回总数 + */ + public Long add(String key, Map params) { + return this.stringGeoOperations.add(key, params); + } + + /** + * 定位对象 + * @see Redis Documentation: GEOPOS + * @since redis 3.2.0 + * @param key 键 + * @param values 对象 + * @return 返回坐标列表 + */ + public List positionAsObj(String key, Object ...values) { + return this.geoOperations.position(key, values); + } + + /** + * 定位字符串 + * @see Redis Documentation: GEOPOS + * @since redis 3.2.0 + * @param key 键 + * @param values 字符串 + * @return 返回坐标列表 + */ + public List position(String key, String ...values) { + return this.stringGeoOperations.position(key, values); + } + + /** + * 对象地理位置哈希码 + * @see Redis Documentation: GEOHASH + * @since redis 3.2.0 + * @param key 键 + * @param values 对象 + * @return 返回对象地理位置哈希码 + */ + public List hashAsObj(String key, Object ...values) { + if (values==null||values.length==0) { + return new ArrayList<>(); + } + return this.geoOperations.hash(key, values); + } + + /** + * 字符串地理位置哈希码 + * @see Redis Documentation: GEOHASH + * @since redis 3.2.0 + * @param key 键 + * @param values 对象 + * @return 返回字符串地理位置哈希码 + */ + public List hash(String key, String ...values) { + if (values==null||values.length==0) { + return new ArrayList<>(); + } + return this.stringGeoOperations.hash(key, values); + } + + /** + * 对象距离 + * @see Redis Documentation: GEODIST + * @since redis 3.2.0 + * @param key 键 + * @param member1 对象1 + * @param member2 对象2 + * @return 返回对象间的距离 + */ + public Distance distanceAsObj(String key, Object member1, Object member2) { + return this.geoOperations.distance(key, member1, member2); + } + + /** + * 字符串距离 + * @see Redis Documentation: GEODIST + * @since redis 3.2.0 + * @param key 键 + * @param member1 字符串1 + * @param member2 字符串2 + * @return 返回字符串间的距离 + */ + public Distance distance(String key, String member1, String member2) { + return this.stringGeoOperations.distance(key, member1, member2); + } + + /** + * 对象距离 + * @see Redis Documentation: GEODIST + * @since redis 3.2.0 + * @param key 键 + * @param member1 对象1 + * @param member2 对象2 + * @param metric 单位 + * @return 返回对象间的距离 + */ + public Distance distanceAsObj(String key, Object member1, Object member2, Metric metric) { + return this.geoOperations.distance(key, member1, member2, metric); + } + + /** + * 字符串距离 + * @see Redis Documentation: GEODIST + * @since redis 3.2.0 + * @param key 键 + * @param member1 字符串1 + * @param member2 字符串2 + * @param metric 单位 + * @return 返回字符串间的距离 + */ + public Distance distance(String key, String member1, String member2, Metric metric) { + return this.stringGeoOperations.distance(key, member1, member2, metric); + } + + /** + * 中心范围内的对象 + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 对象 + * @param distance 距离 + * @return 返回包含的对象 + */ + public List radiusByMemberAsObj(String key, Object value, Distance distance) { + GeoResults> results = this.geoOperations.radius(key, value, distance); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的字符串 + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 字符串 + * @param distance 距离 + * @return 返回包含的字符串 + */ + public List radiusByMember(String key, String value, Distance distance) { + GeoResults> results = this.stringGeoOperations.radius(key, value, distance); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的对象 + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 对象 + * @param radius 半径 + * @return 返回包含的对象 + */ + public List radiusByMemberAsObj(String key, Object value, Double radius) { + GeoResults> results = this.geoOperations.radius(key, value, radius); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的字符串 + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 字符串 + * @param radius 半径 + * @return 返回包含的字符串 + */ + public List radiusByMember(String key, String value, Double radius) { + GeoResults> results = this.stringGeoOperations.radius(key, value, radius); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的对象 + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 对象 + * @param distance 距离 + * @param args 命令参数 + * @return 返回包含的对象 + */ + public List radiusByMemberAsObj(String key, Object value, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) { + GeoResults> results = this.geoOperations.radius(key, value, distance, args); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的字符串 + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 字符串 + * @param distance 距离 + * @param args 命令参数 + * @return 返回包含的字符串 + */ + public List radiusByMember(String key, String value, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) { + GeoResults> results = this.stringGeoOperations.radius(key, value, distance, args); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的对象 + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @return 返回包含的对象 + */ + public List radiusAsObj(String key, Circle within) { + GeoResults> results = this.geoOperations.radius(key, within); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的字符串 + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @return 返回包含的字符串 + */ + public List radius(String key, Circle within) { + GeoResults> results = this.stringGeoOperations.radius(key, within); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的对象 + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @param args 命令参数 + * @return 返回包含的对象 + */ + public List radiusAsObj(String key, Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) { + GeoResults> results = this.geoOperations.radius(key, within, args); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的字符串 + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @param args 命令参数 + * @return 返回包含的字符串 + */ + public List radius(String key, Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) { + GeoResults> results = this.stringGeoOperations.radius(key, within, args); + return ConvertUtil.toList(results); + } + + /** + * 中心范围内的对象(带详细信息) + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 对象 + * @param distance 距离 + * @return 返回包含的对象 + */ + public GeoResults> radiusByMemberWithResultAsObj(String key, Object value, Distance distance) { + return this.geoOperations.radius(key, value, distance); + } + + /** + * 中心范围内的字符串(带详细信息) + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 字符串 + * @param distance 距离 + * @return 返回包含的字符串 + */ + public GeoResults> radiusByMemberWithResult(String key, String value, Distance distance) { + return this.stringGeoOperations.radius(key, value, distance); + } + + /** + * 中心范围内的对象(带详细信息) + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 对象 + * @param radius 半径 + * @return 返回包含的对象 + */ + public GeoResults> radiusByMemberAsObjWithResult(String key, Object value, Double radius) { + return this.geoOperations.radius(key, value, radius); + } + + /** + * 中心范围内的字符串(带详细信息) + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 字符串 + * @param radius 半径 + * @return 返回包含的字符串 + */ + public GeoResults> radiusByMemberWithResult(String key, String value, Double radius) { + return this.stringGeoOperations.radius(key, value, radius); + } + + /** + * 中心范围内的对象(带详细信息) + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 对象 + * @param distance 距离 + * @param args 命令参数 + * @return 返回包含的对象 + */ + public GeoResults> radiusByMemberAsObjWithResult(String key, Object value, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) { + return this.geoOperations.radius(key, value, distance, args); + } + + /** + * 中心范围内的字符串(带详细信息) + * @see Redis Documentation: GEORADIUSBYMEMBER + * @since redis 3.2.0 + * @param key 键 + * @param value 字符串 + * @param distance 距离 + * @param args 命令参数 + * @return 返回包含的字符串 + */ + public GeoResults> radiusByMemberWithResult(String key, String value, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) { + return this.stringGeoOperations.radius(key, value, distance, args); + } + + /** + * 中心范围内的对象(带详细信息) + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @return 返回包含的对象 + */ + public GeoResults> radiusAsObjWithResult(String key, Circle within) { + return this.geoOperations.radius(key, within); + } + + /** + * 中心范围内的字符串(带详细信息) + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @return 返回包含的字符串 + */ + public GeoResults> radiusWithResult(String key, Circle within) { + return this.stringGeoOperations.radius(key, within); + } + + /** + * 中心范围内的对象(带详细信息) + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @param args 命令参数 + * @return 返回包含的对象 + */ + public GeoResults> radiusAsObjWithResult(String key, Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) { + return this.geoOperations.radius(key, within, args); + } + + /** + * 中心范围内的字符串(带详细信息) + * @see Redis Documentation: GEORADIUS + * @since redis 3.2.0 + * @param key 键 + * @param within 圆 + * @param args 命令参数 + * @return 返回包含的字符串 + */ + public GeoResults> radiusWithResult(String key, Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) { + return this.stringGeoOperations.radius(key, within, args); + } + + /** + * 移除对象 + * @see Redis Documentation: ZREM + * @since redis 2.4.0 + * @param key 键 + * @param members 对象 + * @return 返回移除数量 + */ + public Long removeAsObj(String key, Object ...members) { + return this.geoOperations.remove(key, (Object[]) members); + } + + /** + * 移除字符串 + * @see Redis Documentation: ZREM + * @since redis 2.4.0 + * @param key 键 + * @param members 字符串 + * @return 返回移除数量 + */ + public Long remove(String key, String ...members) { + return this.stringGeoOperations.remove(key, members); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } + + +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManager.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManager.java new file mode 100644 index 0000000..1bd26af --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManager.java @@ -0,0 +1,292 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.lang.reflect.Constructor; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson.RedissonClientHelper; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson.RedissonConnectionFactory; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ApplicationContextUtil; + +/** + * 助手管理 + * @author xsx + * @date 2019/5/23 + * @since 1.8 + */ +final class HandlerManager { + /** + * redis模板(用于对象) + */ + @SuppressWarnings("unchecked") + private static final RedisTemplate REDIS_TEMPLATE = ApplicationContextUtil.getContext().getBean("redisTemplate", RedisTemplate.class); + /** + * redis模板(用于字符串) + */ + private static final StringRedisTemplate STRING_REDIS_TEMPLATE = ApplicationContextUtil.getContext().getBean("stringRedisTemplate", StringRedisTemplate.class); + /** + * 默认KEY + */ + private static final String DEFAULT_KEY = "default"; + /** + * 默认数据库索引 + */ + private static final int DEFAULT_DB_INDEX = ApplicationContextUtil.getContext().getBean(RedisProperties.class).getDatabase(); + /** + * 助手容器 + */ + private final ConcurrentMap> container = initContainer(); + /** + * 集群助手实例 + */ + private final ClusterHandler clusterHandler = new ClusterHandler(REDIS_TEMPLATE); + + + /** + * 助手管理构造 + */ + HandlerManager(){} + + /** + * 获取默认KEY + * @return 返回默认KEY + */ + String getDefaultKey() { + return DEFAULT_KEY; + } + + /** + * 获取助手 + * @param key KEY + * @param type 助手类型 + * @return 返回助手 + */ + RedisHandler getHandler(String key, HandlerType type) { + // 若是集群助手类型,则直接返回 + if (type==HandlerType.CLUSTER) { + return this.clusterHandler; + } + ConcurrentMap map = this.container.get(type); + RedisHandler handler = map.get(key); + if (handler!=null) { + return handler; + } + synchronized (this.container) { + handler = map.get(key); + if (handler==null) { + RedisHandler instance = this.getHandlerInstance(key, type); + handler = map.putIfAbsent(key, instance); + if (handler==null) { + handler = instance; + } + } + } + return handler; + } + + /** + * 获取助手 + * @param transactionHandler 事务助手 + * @param type 助手类型 + * @return 返回助手 + */ + RedisHandler getHandler( + TransactionHandler transactionHandler, + HandlerType type + ) { + return this.getHandlerInstance(transactionHandler, type); + } + + /** + * 获取默认的对象模板 + * @return 返回默认的对象模板 + */ + RedisTemplate getDefaultRedisTemplate() { + return REDIS_TEMPLATE; + } + + /** + * 获取默认的字符串模板 + * @return 返回默认的字符串模板 + */ + StringRedisTemplate getDefaultStringRedisTemplate() { + return STRING_REDIS_TEMPLATE; + } + + /** + * 获取连接工厂 + * @param dbIndex 数据库索引 + * @return 返回连接工厂 + */ + static RedisConnectionFactory getConnectionFactory(int dbIndex) { + RedisConnectionFactory redisConnectionFactory = ApplicationContextUtil.getContext().getBean(RedisConnectionFactory.class); + if (redisConnectionFactory instanceof LettuceConnectionFactory) { + ((LettuceConnectionFactory)redisConnectionFactory).setDatabase(dbIndex); + }else if (redisConnectionFactory instanceof JedisConnectionFactory) { + JedisConnectionFactory factory = (JedisConnectionFactory) redisConnectionFactory; + if (factory.isRedisSentinelAware()) { + RedisSentinelConfiguration sentinelConfiguration = factory.getSentinelConfiguration(); + if (sentinelConfiguration != null) { + sentinelConfiguration.setDatabase(dbIndex); + } + }else{ + RedisStandaloneConfiguration standaloneConfiguration = factory.getStandaloneConfiguration(); + if (standaloneConfiguration!=null) { + standaloneConfiguration.setDatabase(dbIndex); + } + } + }else if (redisConnectionFactory instanceof RedissonConnectionFactory) { + redisConnectionFactory = new RedissonConnectionFactory( + RedissonClientHelper.createClient(dbIndex) + ); + }else { + throw new RuntimeException("no support connection factory"); + } + return redisConnectionFactory; + } + + /** + * 创建对象模板 + * @param dbIndex 数据库索引 + * @return 返回对象模板 + */ + @SuppressWarnings("unchecked") + static RedisTemplate createRedisTemplate(int dbIndex) { + return createTemplate(dbIndex, false); + } + + /** + * 创建字符串模板 + * @param dbIndex 数据库索引 + * @return 返回字符串模板 + */ + static StringRedisTemplate createStringRedisTemplate(int dbIndex) { + return (StringRedisTemplate) createTemplate(dbIndex, true); + } + + /** + * 创建模板 + * @param dbIndex 数据库索引 + * @param isString 是否为字符串模板 + * @return 返回模板 + */ + static RedisTemplate createTemplate(int dbIndex, boolean isString) { + return initRedisTemplate(getConnectionFactory(dbIndex), isString); + } + + /** + * 创建模板 + * @param dbIndex 数据库索引 + * @return 返回模板 + */ + static List createTemplate(int dbIndex) { + RedisConnectionFactory connectionFactory = getConnectionFactory(dbIndex); + return Arrays.asList( + initRedisTemplate(connectionFactory, false), + initRedisTemplate(connectionFactory, true) + ); + } + + /** + * 初始化模板 + * @param factory 连接工厂 + * @param isString 是否为字符串模板 + * @return 返回模板 + */ + @SuppressWarnings("unchecked") + private static RedisTemplate initRedisTemplate(RedisConnectionFactory factory, boolean isString) { + RedisTemplate redisTemplate; + if (isString) { + redisTemplate = new StringRedisTemplate(factory); + }else{ + redisTemplate = new RedisTemplate(); + redisTemplate.setKeySerializer(REDIS_TEMPLATE.getKeySerializer()); + redisTemplate.setValueSerializer(REDIS_TEMPLATE.getValueSerializer()); + redisTemplate.setHashKeySerializer(REDIS_TEMPLATE.getHashKeySerializer()); + redisTemplate.setHashValueSerializer(REDIS_TEMPLATE.getHashValueSerializer()); + redisTemplate.setEnableDefaultSerializer(REDIS_TEMPLATE.isEnableDefaultSerializer()); + redisTemplate.setConnectionFactory(factory); + redisTemplate.afterPropertiesSet(); + } + return redisTemplate; + } + + /** + * 初始化容器 + * @return 返回容器 + */ + private ConcurrentMap> initContainer() { + String dbIndex = String.valueOf(DEFAULT_DB_INDEX); + ConcurrentMap> container = new ConcurrentHashMap<>(32); + HandlerType[] types = HandlerType.values(); + RedisHandler handler; + for (HandlerType type : types) { + ConcurrentHashMap handlerMap = new ConcurrentHashMap<>(256); + container.put(type, handlerMap); + // 初始化跳过redLock + if (type==HandlerType.REDISLOCK) { + continue; + } + handler = this.getHandlerInstance(dbIndex, type); + handlerMap.put(getDefaultKey(), Objects.requireNonNull(handler)); + handlerMap.put(dbIndex, handler); + + } + return container; + } + + /** + * 获取助手实例 + * @param key KEY + * @param type 助手类型 + * @return 返回实例 + */ + @SuppressWarnings("unchecked") + private RedisHandler getHandlerInstance(String key, HandlerType type) { + try { + Constructor constructor = type.getTypeClass().getDeclaredConstructor(Integer.class); + constructor.setAccessible(true); + RedisHandler handler; + if (type==HandlerType.REDISLOCK&&DEFAULT_KEY.equalsIgnoreCase(key)) { + handler = (RedisHandler) constructor.newInstance(DEFAULT_DB_INDEX); + }else { + handler = (RedisHandler) constructor.newInstance(Integer.valueOf(key)); + } + return handler; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 获取助手实例 + * @param transactionHandler 事务助手 + * @param type 助手类型 + * @return 返回实例 + */ + @SuppressWarnings("unchecked") + private RedisHandler getHandlerInstance( + TransactionHandler transactionHandler, + HandlerType type + ) { + try { + Constructor constructor = type.getTypeClass().getDeclaredConstructor(TransactionHandler.class); + constructor.setAccessible(true); + return (RedisHandler) constructor.newInstance(transactionHandler); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManagerProxy.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManagerProxy.java new file mode 100644 index 0000000..1d26265 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerManagerProxy.java @@ -0,0 +1,80 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.hash.HashMapper; + +/** + * 助手管理代理 + * @author xsx + * @date 2019/6/15 + * @since 1.8 + */ +public class HandlerManagerProxy { + + /** + * 助手管理实例 + */ + private final HandlerManager manager = new HandlerManager(); + + /** + * 获取助手 + * @param type 助手类型 + * @param 返回类型 + * @return 返回助手 + */ + @SuppressWarnings("unchecked") + public T getHandler(HandlerType type) { + return (T) this.manager.getHandler(this.manager.getDefaultKey(), type); + } + + /** + * 获取助手 + * @param key KEY + * @param type 助手类型 + * @param 返回类型 + * @return 返回助手 + */ + @SuppressWarnings("unchecked") + public T getHandler(String key, HandlerType type) { + return (T) this.manager.getHandler(key, type); + } + + /** + * 获取助手 + * @param transactionHandler 事务助手 + * @param type 助手类型 + * @param 返回类型 + * @return 返回助手 + */ + @SuppressWarnings("unchecked") + public T getHandler(TransactionHandler transactionHandler, HandlerType type) { + return (T) this.manager.getHandler(transactionHandler, type); + } + + /** + * 获取流助手 + * @param dbIndex 数据库索引 + * @param mapper 哈希映射器 + * @return 返回流助手 + */ + public StreamHandler getStreamHandler(int dbIndex, HashMapper mapper) { + return new StreamHandler(dbIndex, mapper); + } + + /** + * 获取默认的对象模板 + * @return 返回默认的对象模板 + */ + public RedisTemplate getDefaultRedisTemplate() { + return this.manager.getDefaultRedisTemplate(); + } + + /** + * 获取默认的字符串模板 + * @return 返回默认的字符串模板 + */ + public StringRedisTemplate getDefaultStringRedisTemplate() { + return this.manager.getDefaultStringRedisTemplate(); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerType.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerType.java new file mode 100644 index 0000000..ef076a1 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HandlerType.java @@ -0,0 +1,108 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + + +/** + * 助手类型枚举 + * @author xsx + * @date 2019/6/8 + * @since 1.8 + */ +public enum HandlerType { + /** + * 数据库助手 + */ + DB(DBHandler.class), + /** + * 键助手 + */ + KEY(KeyHandler.class), + /** + * 数字助手 + */ + NUMBER(NumberHandler.class), + /** + * 字符串助手 + */ + STRING(StringHandler.class), + /** + * 列表助手 + */ + LIST(ListHandler.class), + /** + * 哈希助手 + */ + HASH(HashHandler.class), + /** + * 无序集合助手 + */ + SET(SetHandler.class), + /** + * 有序集合助手 + */ + ZSET(ZsetHandler.class), + /** + * 位图助手 + */ + BITMAP(BitmapHandler.class), + /** + * 地理位置助手 + */ + GEO(GeoHandler.class), + /** + * 基数助手 + */ + HYPERLOGLOG(HyperLogLogHandler.class), + /** + * lua脚本助手 + */ + SCRIPT(ScriptHandler.class), + /** + * 发布与订阅助手 + */ + PUBSUB(PubSubHandler.class), + /** + * 流助手 + */ + STREAM(StreamHandler.class), + /** + * 分布式锁助手 + */ + REDISLOCK(RedisLockHandler.class), + /** + * 哨兵助手 + */ + SENTINEL(SentinelHandler.class), + /** + * 集群助手 + */ + CLUSTER(ClusterHandler.class), + /** + * 自定义命令助手 + */ + CUSTOMCOMMAND(CustomCommandHandler.class), + /** + * 事务助手 + */ + TRANSACTION(TransactionHandler.class); + + /** + * 对应类型 + */ + private Class typeClass; + + /** + * 枚举构造 + * @param typeClass 助手类型 + */ + HandlerType(Class typeClass) { + this.typeClass = typeClass; + } + + /** + * 获取助手类型 + * @return 返回助手类型 + */ + public Class getTypeClass() { + return this.typeClass; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HashHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HashHandler.java new file mode 100644 index 0000000..1d68740 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HashHandler.java @@ -0,0 +1,478 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.StringRedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 哈希助手 + * @author xsx + * @date 2019/4/9 + * @since 1.8 + */ +public final class HashHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private HashOperations hashOperations; + /** + * 字符串模板 + */ + private HashOperations stringHashOperations; + + /** + * 哈希助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + HashHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.hashOperations = redisTemplate.opsForHash(); + this.stringHashOperations = stringRedisTemplate.opsForHash(); + } + + /** + * 哈希助手构造 + * @param transactionHandler 事务助手 + */ + HashHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.hashOperations = this.redisTemplate.opsForHash(); + this.stringHashOperations = this.stringRedisTemplate.opsForHash(); + } + + /** + * 存入对象 + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 对象 + */ + public void putAsObj(String key, String hashKey, Object value) { + this.hashOperations.put(key, hashKey, value); + } + + /** + * 存入字符串 + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 字符串 + */ + public void put(String key, String hashKey, String value) { + this.stringHashOperations.put(key, hashKey, value); + } + + /** + * 存入对象如果不存在 + * @see Redis Documentation: HSETNX + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 对象 + * @return 返回布尔值,成功true,失败false + */ + public Boolean putIfAbsentAsObj(String key, String hashKey, Object value) { + return this.hashOperations.putIfAbsent(key, hashKey, value); + } + + /** + * 存入字符串如果不存在 + * @see Redis Documentation: HSETNX + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 字符串 + * @return 返回布尔值,成功true,失败false + */ + public Boolean putIfAbsent(String key, String hashKey, String value) { + return this.stringHashOperations.putIfAbsent(key, hashKey, value); + } + + /** + * 存入对象集合 + * @see Redis Documentation: HMSET + * @since redis 2.0.0 + * @param key 键 + * @param map 对象集合 + */ + public void putAllAsObj(String key, Map map) { + this.hashOperations.putAll(key, map); + } + + /** + * 存入字符串集合 + * @see Redis Documentation: HMSET + * @since redis 2.0.0 + * @param key 键 + * @param map 字符串集合 + */ + public void putAll(String key, Map map) { + this.stringHashOperations.putAll(key, map); + } + + /** + * 获取对象 + * @see Redis Documentation: HGET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T getAsObj(String key, String hashKey) { + return (T) ConvertUtil.toJavaType(this.hashOperations.get(key, hashKey), Object.class); + } + + /** + * 获取对象 + * @see Redis Documentation: HGET + * @since redis 2.0.0 + * @param type 返回值类型 + * @param key 键 + * @param hashKey hash键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T getAsObj(Class type, String key, String hashKey) { + return (T) ConvertUtil.toJavaType(this.hashOperations.get(key, hashKey), type); + } + + /** + * 获取字符串 + * @see Redis Documentation: HGET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回字符串 + */ + public String get(String key, String hashKey) { + return this.stringHashOperations.get(key, hashKey); + } + + /** + * 批量获取对象 + * @see Redis Documentation: HMGET + * @since redis 2.0.0 + * @param key 键 + * @param hashKeys hash键 + * @return 返回对象列表 + */ + public List mgetAsObj(String key, String ...hashKeys) { + return this.hashOperations.multiGet(key, Arrays.asList(hashKeys)); + } + + /** + * 批量获取字符串 + * @see Redis Documentation: HMGET + * @since redis 2.0.0 + * @param key 键 + * @param hashKeys hash键 + * @return 返回字符串列表 + */ + public List mget(String key, String ...hashKeys) { + return this.stringHashOperations.multiGet(key, Arrays.asList(hashKeys)); + } + + /** + * 移除对象 + * @see Redis Documentation: HDEL + * @since redis 2.0.0 + * @param key 键 + * @param hashKeys hash键 + * @return 返回移除数量 + */ + public Long removeAsObj(String key, String ...hashKeys) { + return this.hashOperations.delete(key, (Object[]) hashKeys); + } + + /** + * 移除字符串 + * @see Redis Documentation: HDEL + * @since redis 2.0.0 + * @param key 键 + * @param hashKeys hash键 + * @return 返回移除数量 + */ + public Long remove(String key, String ...hashKeys) { + return this.stringHashOperations.delete(key, (Object[]) hashKeys); + } + + /** + * 获取对象集合 + * @see Redis Documentation: HGETALL + * @since redis 2.0.0 + * @param key 键 + * @return 返回对象字典 + */ + public Map entriesAsObj(String key) { + return this.hashOperations.entries(key); + } + + /** + * 获取字符串集合 + * @see Redis Documentation: HGETALL + * @since redis 2.0.0 + * @param key 键 + * @return 返回字符串字典 + */ + public Map entries(String key) { + return this.stringHashOperations.entries(key); + } + + /** + * 获取对象hash键集合 + * @see Redis Documentation: HKEYS + * @since redis 2.0.0 + * @param key 键 + * @return 返回对象字典键集合 + */ + public Set keysAsObj(String key) { + return this.hashOperations.keys(key); + } + + /** + * 获取字符串hash键集合 + * @see Redis Documentation: HKEYS + * @since redis 2.0.0 + * @param key 键 + * @return 返回字符串字典键集合 + */ + public Set keys(String key) { + return this.stringHashOperations.keys(key); + } + + /** + * 获取对象集合 + * @see Redis Documentation: HVALS + * @since redis 2.0.0 + * @param key 键 + * @return 返回对象列表 + */ + public List valuesAsObj(String key) { + return this.hashOperations.values(key); + } + + /** + * 获取字符串集合 + * @see Redis Documentation: HVALS + * @since redis 2.0.0 + * @param key 键 + * @return 返回字符串列表 + */ + public List values(String key) { + return this.stringHashOperations.values(key); + } + + /** + * 获取字符串长度 + * @see Redis Documentation: HSTRLEN + * @since redis 3.2.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回字符串长度 + */ + public Long lengthOfValue(String key, String hashKey) { + return this.stringHashOperations.lengthOfValue(key, hashKey); + } + + /** + * 获取对象数量 + * @see Redis Documentation: HLEN + * @since redis 2.0.0 + * @param key 键 + * @return 返回对象数量 + */ + public Long sizeAsObj(String key) { + return this.hashOperations.size(key); + } + + /** + * 获取字符串数量 + * @see Redis Documentation: HLEN + * @since redis 2.0.0 + * @param key 键 + * @return 返回字符串数量 + */ + public Long size(String key) { + return this.stringHashOperations.size(key); + } + + /** + * 是否包含对象的key + * @see Redis Documentation: HEXISTS + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回布尔值,存在true,不存在false + */ + public Boolean hasKeyAsObj(String key, String hashKey) { + return this.hashOperations.hasKey(key, hashKey); + } + + /** + * 是否包含字符串的key + * @see Redis Documentation: HEXISTS + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回布尔值,存在true,不存在false + */ + public Boolean hasKey(String key, String hashKey) { + return this.stringHashOperations.hasKey(key, hashKey); + } + + /** + * 自增 + * 已过期,请使用 {@link NumberHandler#addDouble(String, String, double)} 替换 + * @see Redis Documentation: HINCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回自增后的值 + */ + @Deprecated + public Double increment(String key, String hashKey, Double data) { + return this.stringHashOperations.increment(key, hashKey, data); + } + + /** + * 自增 + * 已过期,请使用 {@link NumberHandler#addLong(String, String, long)} 替换 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回自增后的值 + */ + @Deprecated + public Long increment(String key, String hashKey, Long data) { + return this.stringHashOperations.increment(key, hashKey, data); + } + + /** + * 自增 + * 已过期,请使用 {@link NumberHandler#incrementLong(String, String)} 替换 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回自增后的值 + */ + @Deprecated + public Long increment(String key, String hashKey) { + return this.stringHashOperations.increment(key, hashKey, 1L); + } + + /** + * 递减 + * 已过期,请使用 {@link NumberHandler#subtractDouble(String, String, double)} 替换 + * @see Redis Documentation: HINCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回递减后的值 + */ + @Deprecated + public Double decrement(String key, String hashKey, Double data) { + return this.stringHashOperations.increment(key, hashKey, -data); + } + + /** + * 递减 + * 已过期,请使用 {@link NumberHandler#subtractLong(String, String, long)} 替换 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回递减后的值 + */ + @Deprecated + public Long decrement(String key, String hashKey, Long data) { + return this.stringHashOperations.increment(key, hashKey, -data); + } + + /** + * 递减 + * 已过期,请使用 {@link NumberHandler#decrementLong(String, String)} 替换 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回递减后的值 + */ + @Deprecated + public Long decrement(String key, String hashKey) { + return this.stringHashOperations.increment(key, hashKey, -1L); + } + + /** + * 匹配对象 + * @see Redis Documentation: HSCAN + * @since redis 2.8.0 + * @param key 键 + * @param count 数量 + * @param pattern 规则 + * @return 返回匹配对象 + */ + public Cursor> scanAsObj(String key, Long count, String pattern) { + return this.hashOperations.scan(key, ScanOptions.scanOptions().count(count).match(pattern).build()); + } + + /** + * 匹配字符串 + * @see Redis Documentation: HSCAN + * @since redis 2.8.0 + * @param key 键 + * @param count 数量 + * @param pattern 规则 + * @return 返回匹配字符串 + */ + public Cursor> scan(String key, Long count, String pattern) { + return this.stringHashOperations.scan(key, ScanOptions.scanOptions().count(count).match(pattern).build()); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HyperLogLogHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HyperLogLogHandler.java new file mode 100644 index 0000000..c837c19 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/HyperLogLogHandler.java @@ -0,0 +1,142 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.springframework.data.redis.core.HyperLogLogOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.List; + +/** + * 基数助手 + * @author xsx + * @date 2019/4/22 + * @since 1.8 + */ +public final class HyperLogLogHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private HyperLogLogOperations hyperLogLogOperations; + /** + * 字符串模板 + */ + private HyperLogLogOperations stringHyperLogLogOperations; + + /** + * 基数助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + HyperLogLogHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.hyperLogLogOperations = redisTemplate.opsForHyperLogLog(); + this.stringHyperLogLogOperations = stringRedisTemplate.opsForHyperLogLog(); + } + + /** + * 基数助手构造 + * @param transactionHandler 事务助手 + */ + HyperLogLogHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.hyperLogLogOperations = this.redisTemplate.opsForHyperLogLog(); + this.stringHyperLogLogOperations = this.stringRedisTemplate.opsForHyperLogLog(); + } + + /** + * 添加对象 + * @see Redis Documentation: PFADD + * @since redis 2.8.9 + * @param key 键 + * @param values 对象 + * @return 返回添加对象成功数量 + */ + public Long addAsObj(String key, Object ...values) { + return this.hyperLogLogOperations.add(key, values); + } + + /** + * 添加字符串 + * @see Redis Documentation: PFADD + * @since redis 2.8.9 + * @param key 键 + * @param values 字符串 + * @return 返回添加字符串成功数量 + */ + public Long add(String key, String ...values) { + return this.stringHyperLogLogOperations.add(key, values); + } + + /** + * 获取对象基数估算值 + * @see Redis Documentation: PFCOUNT + * @since redis 2.8.9 + * @param keys 键 + * @return 返回对象基数估算值 + */ + public Long sizeAsObj(String ...keys) { + return this.hyperLogLogOperations.size(keys); + } + + /** + * 获取字符串基数估算值 + * @see Redis Documentation: PFCOUNT + * @since redis 2.8.9 + * @param keys 键 + * @return 返回字符串基数估算值 + */ + public Long size(String ...keys) { + return this.stringHyperLogLogOperations.size(keys); + } + + /** + * 合并对象 + * @see Redis Documentation: PFMERGE + * @since redis 2.8.9 + * @param key 键 + * @param otherKeys 其他键 + * @return 返回合并后的对象基数估算值 + */ + public Long unionAsObj(String key, String ...otherKeys) { + return this.hyperLogLogOperations.union(key, otherKeys); + } + + /** + * 合并字符串 + * @see Redis Documentation: PFMERGE + * @since redis 2.8.9 + * @param key 键 + * @param otherKeys 字符串 + * @return 返回合并后的字符串基数估算值 + */ + public Long union(String key, String ...otherKeys) { + return this.stringHyperLogLogOperations.union(key, otherKeys); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/KeyHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/KeyHandler.java new file mode 100644 index 0000000..d5a5783 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/KeyHandler.java @@ -0,0 +1,660 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.SortParameters; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.query.SortQuery; +import org.springframework.data.redis.core.query.SortQueryBuilder; +import org.springframework.data.redis.serializer.SerializationException; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 键助手 + * @author xsx + * @date 2019/4/25 + * @since 1.8 + */ +public final class KeyHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + + /** + * 键助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + KeyHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + } + + /** + * 键助手构造 + * @param transactionHandler 事务助手 + */ + KeyHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + } + + /** + * 是否存在key(对象) + * @see Redis Documentation: EXISTS + * @since redis 1.0.0 + * @param key 键 + * @return 返回布尔值,存在true,不存在false + */ + public Boolean hasKeyAsObj(String key) { + return this.redisTemplate.hasKey(key); + } + + /** + * 是否存在key(字符串) + * @see Redis Documentation: EXISTS + * @since redis 1.0.0 + * @param key 键 + * @return 返回布尔值,存在true,不存在false + */ + public Boolean hasKey(String key) { + return this.stringRedisTemplate.hasKey(key); + } + + /** + * 移除对象key + * @see Redis Documentation: DEL + * @since redis 1.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long removeAsObj(String ...keys) { + return this.redisTemplate.delete(Arrays.asList(keys)); + } + + /** + * 移除字符串key + * @see Redis Documentation: DEL + * @since redis 1.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long remove(String ...keys) { + return this.stringRedisTemplate.delete(Arrays.asList(keys)); + } + + /** + * 移除存在的对象key + * @see Redis Documentation: UNLINK + * @since redis 4.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long unlinkAsObj(String ...keys) { + return this.redisTemplate.unlink(Arrays.asList(keys)); + } + + /** + * 移除存在的字符串key + * @see Redis Documentation: UNLINK + * @since redis 4.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long unlink(String ...keys) { + return this.stringRedisTemplate.unlink(Arrays.asList(keys)); + } + + /** + * 设置对象过期时间 + * @see Redis Documentation: EXPIRE + * @see Redis Documentation: PEXPIRE + * @since redis 1.0.0 + * @param key 键 + * @param timeout 过期时间 + * @param timeUnit 时间单位 + * @return 返回布尔值,成功true,失败false + */ + public Boolean expireAsObj(String key, long timeout, TimeUnit timeUnit) { + return this.redisTemplate.expire(key, timeout, timeUnit); + } + + /** + * 设置字符串过期时间 + * @see Redis Documentation: EXPIRE + * @see Redis Documentation: PEXPIRE + * @since redis 1.0.0 + * @param key 键 + * @param timeout 过期时间 + * @param timeUnit 时间单位 + * @return 返回布尔值,成功true,失败false + */ + public Boolean expire(String key, long timeout, TimeUnit timeUnit) { + return this.stringRedisTemplate.expire(key, timeout, timeUnit); + } + + /** + * 设置对象过期时间 + * @see Redis Documentation: EXPIREAT + * @see Redis Documentation: PEXPIREAT + * @since redis 1.2.0 + * @param key 键 + * @param date 过期时间 + * @return 返回布尔值,成功true,失败false + */ + public Boolean expireAtAsObj(String key, Date date) { + return this.redisTemplate.expireAt(key, date); + } + + /** + * 设置字符串过期时间 + * @see Redis Documentation: EXPIREAT + * @see Redis Documentation: PEXPIREAT + * @since redis 1.2.0 + * @param key 键 + * @param date 过期时间 + * @return 返回布尔值,成功true,失败false + */ + public Boolean expireAt(String key, Date date) { + return this.stringRedisTemplate.expireAt(key, date); + } + + /** + * 获取对象过期时间 + * @see Redis Documentation: TTL + * @since redis 1.0.0 + * @param key 键 + * @param timeUnit 时间单位 + * @return 返回对象过期时间 + */ + public Long getExpireAsObj(String key, TimeUnit timeUnit) { + return this.redisTemplate.getExpire(key, timeUnit); + } + + /** + * 获取字符串过期时间 + * @see Redis Documentation: TTL + * @since redis 1.0.0 + * @param key 键 + * @param timeUnit 时间单位 + * @return 返回字符串过期时间 + */ + public Long getExpire(String key, TimeUnit timeUnit) { + return this.stringRedisTemplate.getExpire(key, timeUnit); + } + + /** + * 获取对象存储数据类型 + * @see Redis Documentation: TYPE + * @since redis 1.0.0 + * @param key 键 + * @return 返回对象存储数据类型 + */ + public DataType getTypeAsObj(String key) { + return this.redisTemplate.type(key); + } + + /** + * 获取字符串存储数据类型 + * @see Redis Documentation: TYPE + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串存储数据类型 + */ + public DataType getType(String key) { + return this.stringRedisTemplate.type(key); + } + + /** + * 对象的键集合 + * @see Redis Documentation: KEYS + * @since redis 1.0.0 + * @param pattern 键规则 + * @return 返回对象键的集合 + */ + public Set keysAsObj(String pattern) { + return this.redisTemplate.keys(pattern); + } + + /** + * 字符串的键集合 + * @see Redis Documentation: KEYS + * @since redis 1.0.0 + * @param pattern 键规则 + * @return 返回字符串键的集合 + */ + public Set keys(String pattern) { + return this.stringRedisTemplate.keys(pattern); + } + + /** + * 对象的键存在的数量 + * @see Redis Documentation: EXISTS + * @since redis 1.0.0 + * @param keys 键 + * @return 返回对象键的数量 + */ + public Long keysCountAsObj(String ...keys) { + return this.redisTemplate.countExistingKeys(Arrays.asList(keys)); + } + + /** + * 字符串的键存在的数量 + * @see Redis Documentation: EXISTS + * @since redis 1.0.0 + * @param keys 键 + * @return 返回字符串键的数量 + */ + public Long keysCount(String ...keys) { + return this.stringRedisTemplate.countExistingKeys(Arrays.asList(keys)); + } + + /** + * 获取对象随机key + * @see Redis Documentation: RANDOMKEY + * @since redis 1.0.0 + * @return 返回对象随机的键 + */ + public String randomKeyAsObj() { + String o; + try { + o = this.redisTemplate.randomKey(); + }catch(SerializationException e){ + o = null; + } + return o; + } + + /** + * 获取字符串随机key + * @see Redis Documentation: RANDOMKEY + * @since redis 1.0.0 + * @return 返回字符串随机的键 + */ + public String randomKey() { + return this.stringRedisTemplate.randomKey(); + } + + /** + * 重命名对象key + * @see Redis Documentation: RENAME + * @since redis 1.0.0 + * @param oldKey 旧key + * @param newKey 新key + */ + public void renameAsObj(String oldKey, String newKey) { + this.redisTemplate.rename(oldKey, newKey); + } + + /** + * 重命名字符串key + * @see Redis Documentation: RENAME + * @since redis 1.0.0 + * @param oldKey 旧key + * @param newKey 新key + */ + public void rename(String oldKey, String newKey) { + this.stringRedisTemplate.rename(oldKey, newKey); + } + + /** + * 重命名对象key如果存在 + * @see Redis Documentation: RENAMENX + * @since redis 1.0.0 + * @param oldKey 旧key + * @param newKey 新key + * @return 返回布尔值,成功true,失败false + */ + public Boolean renameAsObjIfAbsent(String oldKey, String newKey) { + return this.redisTemplate.renameIfAbsent(oldKey, newKey); + } + + /** + * 重命名字符串key如果存在 + * @see Redis Documentation: RENAMENX + * @since redis 1.0.0 + * @param oldKey 旧key + * @param newKey 新key + * @return 返回布尔值,成功true,失败false + */ + public Boolean renameIfAbsent(String oldKey, String newKey) { + return this.stringRedisTemplate.renameIfAbsent(oldKey, newKey); + } + + /** + * 持久化对象 + * @see Redis Documentation: PERSIST + * @since redis 2.2.0 + * @param key 键 + * @return 返回布尔值,成功true,失败false + */ + public Boolean persistAsObj(String key){ + return this.redisTemplate.persist(key); + } + + /** + * 持久化字符串 + * @see Redis Documentation: PERSIST + * @since redis 2.2.0 + * @param key 键 + * @return 返回布尔值,成功true,失败false + */ + public Boolean persist(String key){ + return this.stringRedisTemplate.persist(key); + } + + /** + * 移动对象到指定数据库 + * @see Redis Documentation: MOVE + * @since redis 1.0.0 + * @param dbIndex 数据库索引 + * @param key 键 + * @return 返回布尔值,成功true,失败false + */ + public Boolean moveAsObj(int dbIndex, String key){ + return this.redisTemplate.move(key, dbIndex); + } + + /** + * 移动字符串到指定数据库 + * @see Redis Documentation: MOVE + * @since redis 1.0.0 + * @param dbIndex 数据库索引 + * @param key 键 + * @return 返回布尔值,成功true,失败false + */ + public Boolean move(int dbIndex, String key) { + return this.stringRedisTemplate.move(key, dbIndex); + } + + /** + * 当前数据库中键的数量 + * @see Redis Documentation: DBSIZE + * @since redis 1.0.0 + * @return 返回键的数量 + */ + public Long count() { + Long count; + try { + count = this.redisTemplate.getRequiredConnectionFactory().getConnection().dbSize(); + }catch (IllegalStateException ex) { + count = this.stringRedisTemplate.getRequiredConnectionFactory().getConnection().dbSize(); + } + return count; + } + + /** + * 获取序列化对象 + * @see Redis Documentation: DUMP + * @since redis 2.6.0 + * @param key 键 + * @return 返回字节数组 + */ + public byte[] dumpAsObj(String key) { + return this.redisTemplate.dump(key); + } + + /** + * 获取序列化字符串 + * @see Redis Documentation: DUMP + * @since redis 2.6.0 + * @param key 键 + * @return 返回字节数组 + */ + public byte[] dump(String key) { + return this.stringRedisTemplate.dump(key); + } + + /** + * 序列化存储对象 + * @see Redis Documentation: RESTORE + * @since redis 2.6.0 + * @param key 键 + * @param value 对象字节 + * @param timeout 过期时间 + * @param unit 单位 + * @param replace 是否替换 + */ + public void restoreAsObj(String key, byte[] value, Long timeout, TimeUnit unit, boolean replace) { + this.redisTemplate.restore(key, value, timeout, unit, replace); + } + + /** + * 序列化存储字符串 + * @see Redis Documentation: RESTORE + * @since redis 2.6.0 + * @param key 键 + * @param value 字符串字节 + * @param timeout 过期时间 + * @param unit 单位 + * @param replace 是否替换 + */ + public void restore(String key, byte[] value, Long timeout, TimeUnit unit, boolean replace) { + this.stringRedisTemplate.restore(key, value, timeout, unit, replace); + } + + /** + * 对象最后访问时间更新 + * @see Redis Documentation: TOUCH + * @since redis 3.2.1 + * @param keys 键 + * @return 返回更新数量 + */ + public Long touchAsObj(String ...keys) { + return this.redisTemplate + .getRequiredConnectionFactory() + .getConnection() + .keyCommands() + .touch(ConvertUtil.toByteArray(this.redisTemplate.getKeySerializer(), keys)); + } + + /** + * 字符串最后访问时间更新 + * @see Redis Documentation: TOUCH + * @since redis 3.2.1 + * @param keys 键 + * @return 返回更新数量 + */ + public Long touch(String ...keys) { + return this.stringRedisTemplate + .getRequiredConnectionFactory() + .getConnection() + .keyCommands() + .touch(ConvertUtil.toByteArray(this.stringRedisTemplate.getKeySerializer(), keys)); + } + + /** + * 排序(对象) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param key 键 + * @return 返回排序后的列表 + */ + public List sortAsObj(String key) { + return this.redisTemplate.sort( + SortQueryBuilder.sort(key) + .by("") + .order(SortParameters.Order.ASC) + .alphabetical(true) + .limit(0L, Long.MAX_VALUE) + .build() + ); + } + + /** + * 排序(字符串) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param key 键 + * @return 返回排序后的列表 + */ + public List sort(String key) { + return this.stringRedisTemplate.sort( + SortQueryBuilder.sort(key) + .by("") + .order(SortParameters.Order.ASC) + .alphabetical(true) + .limit(0L, Long.MAX_VALUE) + .build() + ); + } + + /** + * 排序并覆盖(对象) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param key 键 + * @return 返回保存的列表长度 + */ + public Long sortAndCoverAsObj(String key) { + return this.sortAndStoreAsObj(key, key); + } + + /** + * 排序并覆盖(字符串) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param key 键 + * @return 返回保存的列表长度 + */ + public Long sortAndCover(String key) { + return this.sortAndStore(key, key); + } + + /** + * 排序并保存(对象) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 保存键 + * @return 返回保存的列表长度 + */ + public Long sortAndStoreAsObj(String key, String storeKey) { + return this.redisTemplate.sort( + SortQueryBuilder.sort(key) + .by("") + .order(SortParameters.Order.ASC) + .alphabetical(true) + .limit(0L, Long.MAX_VALUE) + .build(), + storeKey + ); + } + + /** + * 排序并保存(字符串) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 保存键 + * @return 返回保存的列表长度 + */ + public Long sortAndStore(String key, String storeKey) { + return this.stringRedisTemplate.sort( + SortQueryBuilder.sort(key) + .by("") + .order(SortParameters.Order.ASC) + .alphabetical(true) + .limit(0L, Long.MAX_VALUE) + .build(), + storeKey + ); + } + + /** + * 排序(对象) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param query 排序对象 + * @return 返回排序后的列表 + */ + public List sortAsObj(SortQuery query) { + return this.redisTemplate.sort(query); + } + + /** + * 排序(字符串) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param query 排序对象 + * @return 返回排序后的列表 + */ + public List sort(SortQuery query) { + return this.stringRedisTemplate.sort(query); + } + + /** + * 排序并覆盖(对象) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param query 排序对象 + * @return 返回保存的列表长度 + */ + public Long sortAndCoverAsObj(SortQuery query) { + return this.sortAndStoreAsObj(query, query.getKey()); + } + + /** + * 排序并覆盖(字符串) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param query 排序对象 + * @return 返回保存的列表长度 + */ + public Long sortAndCover(SortQuery query) { + return this.sortAndStore(query, query.getKey()); + } + + /** + * 排序并保存(对象) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param query 排序对象 + * @param storeKey 保存键 + * @return 返回保存的列表长度 + */ + public Long sortAndStoreAsObj(SortQuery query, String storeKey) { + return this.redisTemplate.sort(query, storeKey); + } + + /** + * 排序并保存(字符串) + * @see Redis Documentation: SORT + * @since redis 1.0.0 + * @param query 排序对象 + * @param storeKey 保存键 + * @return 返回保存的列表长度 + */ + public Long sortAndStore(SortQuery query, String storeKey) { + return this.stringRedisTemplate.sort(query, storeKey); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ListHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ListHandler.java new file mode 100644 index 0000000..5c7cd0f --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ListHandler.java @@ -0,0 +1,923 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 列表助手 + * @author xsx + * @date 2019/4/12 + * @since 1.8 + */ +public final class ListHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private ListOperations listOperations; + /** + * 字符串模板 + */ + private ListOperations stringListOperations; + + /** + * 列表助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + ListHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.listOperations = redisTemplate.opsForList(); + this.stringListOperations = stringRedisTemplate.opsForList(); + } + + /** + * 列表助手构造 + * @param transactionHandler 事务助手 + */ + ListHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.listOperations = this.redisTemplate.opsForList(); + this.stringListOperations = this.stringRedisTemplate.opsForList(); + } + + /** + * 获取对象列表数量 + * @see Redis Documentation: LLEN + * @since redis 1.0.0 + * @param key 键 + * @return 返回列表数量 + */ + public Long sizeAsObj(String key) { + return this.listOperations.size(key); + } + + /** + * 获取列表数量 + * @see Redis Documentation: LLEN + * @since redis 1.0.0 + * @param key 键 + * @return 返回列表数量 + */ + public Long size(String key) { + return this.stringListOperations.size(key); + } + + /** + * 获取所有对象 + * @see Redis Documentation: LRANGE + * @since redis 1.0.0 + * @param key 键 + * @return 返回对象列表 + */ + public List getAllAsObj(String key) { + return this.lrangeAsObj(key, 0L, -1L); + } + + /** + * 获取所有字符串 + * @see Redis Documentation: LRANGE + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串列表 + */ + public List getAll(String key) { + return this.lrange(key, 0L, -1L); + } + + /** + * 从左获取范围内的对象 + * @see Redis Documentation: LRANGE + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回对象列表 + */ + public List lrangeAsObj(String key, Long startIndex, Long endIndex) { + return this.listOperations.range(key, startIndex, endIndex); + } + + /** + * 从左获取范围内的字符串 + * @see Redis Documentation: LRANGE + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回字符串列表 + */ + public List lrange(String key, Long startIndex, Long endIndex) { + return this.stringListOperations.range(key, startIndex, endIndex); + } + + /** + * 从右获取范围内的对象 + * @see Redis Documentation: LRANGE + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回对象列表 + */ + public List rrangeAsObj(String key, Long startIndex, Long endIndex) { + List list = this.lrangeAsObj(key, -endIndex-1, -startIndex-1); + Collections.reverse(list); + return list; + } + + /** + * 从右获取范围内的字符串 + * @see Redis Documentation: LRANGE + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回字符串列表 + */ + public List rrange(String key, Long startIndex, Long endIndex) { + List list = this.lrange(key, -endIndex-1, -startIndex-1); + Collections.reverse(list); + return list; + } + + /** + * 从左移除对象 + * @see Redis Documentation: LREM + * @since redis 1.0.0 + * @param key 键 + * @param count 个数 + * @param value 对象 + * @return 返回移除数量 + */ + public Long lremoveAsObj(String key, Long count, Object value) { + return this.listOperations.remove(key, count, value); + } + + /** + * 从左移除字符串 + * @see Redis Documentation: LREM + * @since redis 1.0.0 + * @param key 键 + * @param count 个数 + * @param value 字符串 + * @return 返回移除数量 + */ + public Long lremove(String key, Long count, String value) { + return this.stringListOperations.remove(key, count, value); + } + + /** + * 从右移除对象 + * @see Redis Documentation: LREM + * @since redis 1.0.0 + * @param key 键 + * @param count 个数 + * @param value 对象 + * @return 返回移除数量 + */ + public Long rremoveAsObj(String key, Long count, Object value) { + return this.lremoveAsObj(key, -count, value); + } + + /** + * 从右移除字符串 + * @see Redis Documentation: LREM + * @since redis 1.0.0 + * @param key 键 + * @param count 个数 + * @param value 字符串 + * @return 返回移除数量 + */ + public Long rremove(String key, Long count, String value) { + return this.lremove(key, -count, value); + } + + /** + * 从左截取对象(会修改redis中列表) + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回截取的对象列表 + */ + public List lsubListAsObj(String key, Long startIndex, Long endIndex) { + this.listOperations.trim(key, startIndex, endIndex); + return this.lrangeAsObj(key, startIndex, this.sizeAsObj(key)); + } + + /** + * 从左截取字符串(会修改redis中列表) + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回截取的字符串列表 + */ + public List lsubList(String key, Long startIndex, Long endIndex) { + this.stringListOperations.trim(key, startIndex, endIndex); + return this.lrange(key, startIndex, this.size(key)); + } + + /** + * 从右截取对象(会修改redis中列表) + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回截取的对象列表 + */ + public List rsubListAsObj(String key, Long startIndex, Long endIndex) { + this.listOperations.trim(key, -endIndex-1, -startIndex-1); + int length = this.sizeAsObj(key).intValue(); + List list = new ArrayList<>(length); + String temp = String.format("%s_temp", key); + for (int i = 0; i < length; i++) { + list.add(this.rpopAndrpushAsObj(key, temp)); + } + this.redisTemplate.rename(temp, key); + return list; + } + + /** + * 从右截取字符串(会修改redis中列表) + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param startIndex 起始索引 + * @param endIndex 结束索引 + * @return 返回截取的字符串列表 + */ + public List rsubList(String key, Long startIndex, Long endIndex) { + this.stringListOperations.trim(key, -endIndex-1, -startIndex-1); + int length = this.size(key).intValue(); + List list = new ArrayList<>(length); + String temp = String.format("%s_temp", key); + for (int i = 0; i < length; i++) { + list.add(this.rpopAndrpush(key, temp)); + } + this.stringRedisTemplate.rename(temp, key); + return list; + } + + /** + * 从左修改指定索引的对象 + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @param value 对象 + */ + public void lsetAsObj(String key, Long index, Object value) { + this.listOperations.set(key, index, value); + } + + /** + * 从左修改指定索引的字符串 + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @param value 字符串 + */ + public void lset(String key, Long index, String value) { + this.stringListOperations.set(key, index, value); + } + + /** + * 从右修改指定索引的对象 + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @param value 对象 + */ + public void rsetAsObj(String key, Long index, Object value) { + this.listOperations.set(key, -index-1, value); + } + + /** + * 从右修改指定索引的字符串 + * @see Redis Documentation: LTRIM + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @param value 字符串 + */ + public void rset(String key, Long index, String value) { + this.stringListOperations.set(key, -index-1, value); + } + + /** + * 从左获取对象 + * @see Redis Documentation: LINDEX + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T lgetAsObj(String key, Long index) { + return (T) ConvertUtil.toJavaType(this.listOperations.index(key, index), Object.class); + } + + /** + * 从左获取对象 + * @see Redis Documentation: LINDEX + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param index 索引 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T lgetAsObj(Class type, String key, Long index) { + return (T) ConvertUtil.toJavaType(this.listOperations.index(key, index), type); + } + + /** + * 从左获取字符串 + * @see Redis Documentation: LINDEX + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @return 返回字符串 + */ + public String lget(String key, Long index) { + return this.stringListOperations.index(key, index); + } + + /** + * 从右获取对象 + * @see Redis Documentation: LINDEX + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T rgetAsObj(String key, Long index) { + return (T) ConvertUtil.toJavaType(this.listOperations.index(key, -index-1), Object.class); + } + + /** + * 从右获取对象 + * @see Redis Documentation: LINDEX + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param index 索引 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T rgetAsObj(Class type, String key, Long index) { + return (T) ConvertUtil.toJavaType(this.listOperations.index(key, -index - 1), type); + } + + /** + * 从右获取字符串 + * @see Redis Documentation: LINDEX + * @since redis 1.0.0 + * @param key 键 + * @param index 索引 + * @return 返回字符串 + */ + public String rget(String key, Long index) { + return this.stringListOperations.index(key, -index-1); + } + + /** + * 从左插入对象 + * @see Redis Documentation: LPUSH + * @since redis 1.0.0 + * @param key 键 + * @param value 对象 + * @return 返回列表数量 + */ + public Long lpushAsObj(String key, Object value) { + return this.listOperations.leftPush(key, value); + } + + /** + * 按照中心点从左插入对象 + * @see Redis Documentation: LPUSH + * @since redis 1.0.0 + * @param key 键 + * @param pivot 中心点对象 + * @param value 对象 + * @return 返回列表数量 + */ + public Long lpushAsObj(String key, Object pivot, Object value) { + return this.listOperations.leftPush(key, pivot, value); + } + + /** + * 从左插入字符串 + * @see Redis Documentation: LPUSH + * @since redis 1.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long lpush(String key, String value) { + return this.stringListOperations.leftPush(key, value); + } + + /** + * 按照中心点从左插入字符串 + * @see Redis Documentation: LPUSH + * @since redis 1.0.0 + * @param key 键 + * @param pivot 中心点字符串 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long lpush(String key, String pivot, String value) { + return this.stringListOperations.leftPush(key, pivot, value); + } + + /** + * 从左插入多个对象 + * @see Redis Documentation: LPUSH + * @since redis 1.0.0 + * @param key 键 + * @param values 对象 + * @return 返回列表数量 + */ + public Long lpushAllAsObj(String key, Object ...values) { + return this.listOperations.leftPushAll(key, values); + } + + /** + * 从左插入多个字符串 + * @see Redis Documentation: LPUSH + * @since redis 1.0.0 + * @param key 键 + * @param values 字符串 + * @return 返回列表数量 + */ + public Long lpushAll(String key, String ...values) { + return this.stringListOperations.leftPushAll(key, values); + } + + /** + * 从左插入对象如果列表存在 + * @see Redis Documentation: LPUSHX + * @since redis 2.2.0 + * @param key 键 + * @param value 对象 + * @return 返回列表数量 + */ + public Long lpushIfPresentAsObj(String key, Object value) { + return this.listOperations.leftPushIfPresent(key, value); + } + + /** + * 从左插入字符串如果列表存在 + * @see Redis Documentation: LPUSHX + * @since redis 2.2.0 + * @param key 键 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long lpushIfPresent(String key, String value) { + return this.stringListOperations.leftPushIfPresent(key, value); + } + + /** + * 从左弹出对象 + * @see Redis Documentation: LPOP + * @since redis 1.0.0 + * @param key 键 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T lpopAsObj(String key) { + return (T) ConvertUtil.toJavaType(this.listOperations.leftPop(key), Object.class); + } + + /** + * 从左弹出对象 + * @see Redis Documentation: LPOP + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T lpopAsObj(Class type, String key) { + return (T) ConvertUtil.toJavaType(this.listOperations.leftPop(key), type); + } + + /** + * 从左弹出字符串 + * @see Redis Documentation: LPOP + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串 + */ + public String lpop(String key) { + return this.stringListOperations.leftPop(key); + } + + /** + * 从左弹出对象(阻塞) + * @see Redis Documentation: BLPOP + * @since redis 2.0.0 + * @param key 键 + * @param timeout 超时时间 + * @param unit 单位 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T blpopAsObj(String key, Long timeout, TimeUnit unit) { + return (T) this.listOperations.leftPop(key, timeout, unit); + } + + /** + * 从左弹出对象(阻塞) + * @see Redis Documentation: BLPOP + * @since redis 2.0.0 + * @param type 返回值类型 + * @param key 键 + * @param timeout 超时时间 + * @param unit 单位 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T blpopAsObj(Class type, String key, Long timeout, TimeUnit unit) { + return (T) ConvertUtil.toJavaType(this.listOperations.leftPop(key, timeout, unit), type); + } + + /** + * 从左弹出字符串(阻塞) + * @see Redis Documentation: BLPOP + * @since redis 2.0.0 + * @param key 键 + * @param timeout 超时时间 + * @param unit 单位 + * @return 返回字符串 + */ + public String blpop(String key, Long timeout, TimeUnit unit) { + return this.stringListOperations.leftPop(key, timeout, unit); + } + + /** + * 从右插入对象 + * @see Redis Documentation: RPUSH + * @since redis 1.0.0 + * @param key 键 + * @param value 对象 + * @return 返回列表数量 + */ + public Long rpushAsObj(String key, Object value) { + return this.listOperations.rightPush(key, value); + } + + /** + * 从右插入字符串 + * @see Redis Documentation: RPUSH + * @since redis 1.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long rpush(String key, String value) { + return this.stringListOperations.rightPush(key, value); + } + + /** + * 从右插入对象 + * @see Redis Documentation: RPUSH + * @since redis 1.0.0 + * @param key 键 + * @param pivot 中心点对象 + * @param value 对象 + * @return 返回列表数量 + */ + public Long rpushAsObj(String key, Object pivot, Object value) { + return this.listOperations.rightPush(key, pivot, value); + } + + /** + * 从右插入字符串 + * @see Redis Documentation: RPUSH + * @since redis 1.0.0 + * @param key 键 + * @param pivot 中心点字符串 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long rpush(String key, String pivot, String value) { + return this.stringListOperations.rightPush(key, pivot, value); + } + + /** + * 从右插入对象如果列表存在 + * @see Redis Documentation: RPUSHX + * @since redis 2.2.0 + * @param key 键 + * @param value 对象 + * @return 返回列表数量 + */ + public Long rpushIfPresentAsObj(String key, Object value) { + return this.listOperations.rightPushIfPresent(key, value); + } + + /** + * 从右插入字符串如果列表存在 + * @see Redis Documentation: RPUSHX + * @since redis 2.2.0 + * @param key 键 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long rpushIfPresent(String key, String value) { + return this.stringListOperations.rightPushIfPresent(key, value); + } + + /** + * 从右插入对象 + * @see Redis Documentation: RPUSH + * @since redis 1.0.0 + * @param key 键 + * @param value 对象 + * @return 返回列表数量 + */ + public Long rpushAllAsObj(String key, Object ...value) { + return this.listOperations.rightPushAll(key, value); + } + + /** + * 从右插入字符串 + * @see Redis Documentation: RPUSH + * @since redis 1.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回列表数量 + */ + public Long rpushAll(String key, String ...value) { + return this.stringListOperations.rightPushAll(key, value); + } + + /** + * 从右弹出对象 + * @see Redis Documentation: RPOP + * @since redis 1.0.0 + * @param key 键 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T rpopAsObj(String key) { + return (T) this.listOperations.rightPop(key); + } + + /** + * 从右弹出对象 + * @see Redis Documentation: RPOP + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T rpopAsObj(Class type, String key) { + return (T) ConvertUtil.toJavaType(this.listOperations.rightPop(key), type); + } + + /** + * 从右弹出字符串 + * @see Redis Documentation: RPOP + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串 + */ + public String rpop(String key) { + return this.stringListOperations.rightPop(key); + } + + /** + * 从右弹出对象(阻塞) + * @see Redis Documentation: BRPOP + * @since redis 2.0.0 + * @param key 键 + * @param timeout 超时时间 + * @param unit 单位 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T brpopAsObj(String key, Long timeout, TimeUnit unit) { + return (T) this.listOperations.rightPop(key, timeout, unit); + } + + /** + * 从右弹出对象(阻塞) + * @see Redis Documentation: BRPOP + * @since redis 2.0.0 + * @param type 返回值类型 + * @param key 键 + * @param timeout 超时时间 + * @param unit 单位 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T brpopAsObj(Class type, String key, Long timeout, TimeUnit unit) { + return (T) ConvertUtil.toJavaType(this.listOperations.rightPop(key, timeout, unit), type); + } + + /** + * 从右弹出字符串(阻塞) + * @see Redis Documentation: BRPOP + * @since redis 2.0.0 + * @param key 键 + * @param timeout 超时时间 + * @param unit 单位 + * @return 返回字符串 + */ + public String brpop(String key, Long timeout, TimeUnit unit) { + return this.stringListOperations.rightPop(key, timeout, unit); + } + + /** + * 从左弹出对象并从左插入到另一个列表 + * @see Redis Documentation: LPOP + * @see Redis Documentation: LPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @param 对象类型 + * @return 返回对象 + */ + public T lpopAndlpushAsObj(String key, String otherKey) { + T t = this.lpopAsObj(key); + this.lpushAsObj(otherKey, t); + return t; + } + + /** + * 从左弹出字符串并从左插入到另一个列表 + * @see Redis Documentation: LPOP + * @see Redis Documentation: LPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @return 返回字符串 + */ + public String lpopAndlpush(String key, String otherKey) { + String v = this.lpop(key); + this.lpush(otherKey, v); + return v; + } + + /** + * 从右弹出对象并从左插入到另一个列表 + * @see Redis Documentation: RPOPLPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T rpopAndlpushAsObj(String key, String otherKey) { + return (T) this.listOperations.rightPopAndLeftPush(key, otherKey); + } + + /** + * 从右弹出对象并从左插入到另一个列表 + * @see Redis Documentation: RPOPLPUSH + * @since redis 1.2.0 + * @param type 返回值类型 + * @param key 键 + * @param otherKey 键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T rpopAndlpushAsObj(Class type, String key, String otherKey) { + return (T) ConvertUtil.toJavaType(this.listOperations.rightPopAndLeftPush(key, otherKey), type); + } + + /** + * 从右弹出字符串并从左插入到另一个列表 + * @see Redis Documentation: RPOPLPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @return 返回字符串 + */ + public String rpopAndlpush(String key, String otherKey) { + return this.stringListOperations.rightPopAndLeftPush(key, otherKey); + } + + /** + * 从右弹出对象并从右插入到另一个列表 + * @see Redis Documentation: RPOP + * @see Redis Documentation: RPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @param 对象类型 + * @return 返回对象 + */ + public T rpopAndrpushAsObj(String key, String otherKey) { + T t = this.rpopAsObj(key); + this.rpushAsObj(otherKey, t); + return t; + } + + /** + * 从右弹出字符串并从右插入到另一个列表 + * @see Redis Documentation: RPOP + * @see Redis Documentation: RPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @return 返回字符串 + */ + public String rpopAndrpush(String key, String otherKey) { + String v = this.rpop(key); + this.rpush(otherKey, v); + return v; + } + + /** + * 从左弹出对象并从右插入到另一个列表 + * @see Redis Documentation: LPOP + * @see Redis Documentation: RPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @param 对象类型 + * @return 返回对象 + */ + public T lpopAndrpushAsObj(String key, String otherKey) { + T t = this.lpopAsObj(key); + this.rpushAsObj(otherKey, t); + return t; + } + + /** + * 从左弹出字符串并从右插入到另一个列表 + * @see Redis Documentation: LPOP + * @see Redis Documentation: RPUSH + * @since redis 1.2.0 + * @param key 键 + * @param otherKey 键 + * @return 返回字符串 + */ + public String lpopAndrpush(String key, String otherKey) { + String v = this.lpop(key); + this.rpush(otherKey, v); + return v; + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/NumberHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/NumberHandler.java new file mode 100644 index 0000000..3db092f --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/NumberHandler.java @@ -0,0 +1,793 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.support.atomic.RedisAtomicDouble; +import org.springframework.data.redis.support.atomic.RedisAtomicInteger; +import org.springframework.data.redis.support.atomic.RedisAtomicLong; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +/** + * 数字助手 + * @author xsx + * @date 2019/6/3 + * @since 1.8 + */ +public final class NumberHandler implements RedisHandler { + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 字符串模板 + */ + private ValueOperations stringOperations; + /** + * 字符串哈希模板 + */ + private HashOperations stringHashOperations; + /** + * 数据库索引 + */ + private int dbIndex; + + /** + * 数字助手构造 + * @param dbIndex 数据库索引 + */ + NumberHandler(Integer dbIndex) { + this.dbIndex = dbIndex; + this.stringRedisTemplate = HandlerManager.createStringRedisTemplate(dbIndex); + this.stringOperations = this.stringRedisTemplate.opsForValue(); + this.stringHashOperations = this.stringRedisTemplate.opsForHash(); + } + + /** + * 数字助手构造 + * @param transactionHandler 事务助手 + */ + NumberHandler(TransactionHandler transactionHandler) { + this.dbIndex = transactionHandler.getDbIndex(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.stringOperations = this.stringRedisTemplate.opsForValue(); + this.stringHashOperations = this.stringRedisTemplate.opsForHash(); + } + + /** + * 获取原子浮点数实例 + * @param key 键 + * @return 返回原子浮点数实例 + */ + public RedisAtomicDouble getAtomicDouble(String key) { + return new RedisAtomicDouble(key, HandlerManager.getConnectionFactory(this.dbIndex)); + } + + /** + * 获取原子长整数实例 + * @param key 键 + * @return 返回原子长整数实例 + */ + public RedisAtomicLong getAtomicLong(String key) { + return new RedisAtomicLong(key, HandlerManager.getConnectionFactory(this.dbIndex)); + } + + /** + * 获取原子整数实例 + * @param key 键 + * @return 返回原子整数实例 + */ + public RedisAtomicInteger getAtomicInteger(String key) { + return new RedisAtomicInteger(key, HandlerManager.getConnectionFactory(this.dbIndex)); + } + + /** + * 设置浮点数 + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param value 值 + */ + public void setDouble(String key, double value) { + this.stringOperations.set(key, String.valueOf(value)); + } + + /** + * 设置浮点数 + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 值 + */ + public void setDouble(String key, String hashKey, double value) { + this.stringHashOperations.put(key, hashKey, String.valueOf(value)); + } + + /** + * 设置浮点数(若存在则更新过期时间) + * @see Redis Documentation: SETEX + * @since redis 2.0.0 + * @param key 键 + * @param value 值 + * @param timeout 过期时间 + * @param unit 时间单位 + */ + public void setDouble(String key, double value, long timeout, TimeUnit unit) { + this.stringOperations.set(key, String.valueOf(value), timeout, unit); + } + + /** + * 设置浮点数如果不存在 + * @see Redis Documentation: SETNX + * @since redis 1.0.0 + * @param key 键 + * @param value 浮点数 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setDoubleIfAbsent(String key, double value) { + return this.stringOperations.setIfAbsent(key, String.valueOf(value)); + } + + /** + * 设置浮点数如果不存在 + * @see Redis Documentation: HSETNX + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 浮点数 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setDoubleIfAbsent(String key, String hashKey, double value) { + return this.stringHashOperations.putIfAbsent(key, hashKey, String.valueOf(value)); + } + + /** + * 设置浮点数并设置过期时间如果不存在 + * @see Redis Documentation: SETNX + * @since redis 2.6.12 + * @param key 键 + * @param value 浮点数 + * @param timeout 过期时间 + * @param unit 时间单位 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setDoubleIfAbsent(String key, double value, long timeout, TimeUnit unit) { + return this.stringOperations.setIfAbsent(key, String.valueOf(value), timeout, unit); + } + + /** + * 获取浮点数 + * @see Redis Documentation: GET + * @since redis 1.0.0 + * @param key 键 + * @return 返回浮点数 + */ + public Double getDouble(String key) { + String value = this.stringOperations.get(key); + if (value!=null) { + return Double.valueOf(value); + } + return null; + } + + /** + * 获取浮点数 + * @see Redis Documentation: HGET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回浮点数 + */ + public Double getDouble(String key, String hashKey) { + String value = this.stringHashOperations.get(key, hashKey); + if (value!=null) { + return Double.valueOf(value); + } + return null; + } + + /** + * 获取并设置浮点数 + * @see Redis Documentation: GETSET + * @since redis 1.0.0 + * @param key 键 + * @param newValue 新值 + * @return 返回原值 + */ + public Double getAndSetDouble(String key, double newValue) { + String value = this.stringOperations.getAndSet(key, String.valueOf(newValue)); + return value!=null?Double.valueOf(value):null; + } + + /** + * 获取并设置浮点数 + * @see Redis Documentation: HGET + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param newValue 新值 + * @return 返回原值 + */ + public Double getAndSetDouble(String key, String hashKey, double newValue) { + Double value = this.getDouble(key, hashKey); + this.setDouble(key, hashKey, newValue); + return value; + } + + /** + * 增加浮点数 + * @see Redis Documentation: INCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param data 步长 + * @return 返回增加后的值 + */ + public Double addDouble(String key, double data) { + return this.stringOperations.increment(key, data); + } + + /** + * 增加浮点数 + * @see Redis Documentation: GET + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param data 步长 + * @return 返回增加后的值 + */ + public synchronized Double addDoubleBySync(String key, double data) { + Double old = this.getDouble(key); + double value = new BigDecimal(old==null?"0":Double.toString(old)).add(new BigDecimal(Double.toString(data))).doubleValue(); + this.setDouble(key, value); + return value; + } + + /** + * 增加浮点数 + * @see Redis Documentation: HINCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回增加后的值 + */ + public Double addDouble(String key, String hashKey, double data) { + return this.stringHashOperations.increment(key, hashKey, data); + } + + /** + * 增加浮点数 + * @see Redis Documentation: HGET + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回增加后的值 + */ + public synchronized Double addDoubleBySync(String key, String hashKey, double data) { + Double old = this.getDouble(key, hashKey); + double value = new BigDecimal(old==null?"0":Double.toString(old)).add(new BigDecimal(Double.toString(data))).doubleValue(); + this.setDouble(key, hashKey, value); + return value; + } + + /** + * 获取并增加浮点数 + * @see Redis Documentation: INCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param data 步长 + * @return 返回原值 + */ + public Double getAndAddDouble(String key, double data) { + return new BigDecimal(Double.toString(this.addDouble(key, data))).subtract(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 获取并增加浮点数 + * @see Redis Documentation: GET + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param data 步长 + * @return 返回原值 + */ + public synchronized Double getAndAddDoubleBySync(String key, double data) { + return new BigDecimal(Double.toString(this.addDoubleBySync(key, data))).subtract(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 获取并增加浮点数 + * @see Redis Documentation: HINCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回原值 + */ + public Double getAndAddDouble(String key, String hashKey, double data) { + return new BigDecimal(Double.toString(this.addDouble(key, hashKey, data))).subtract(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 获取并增加浮点数 + * @see Redis Documentation: HGET + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回原值 + */ + public synchronized Double getAndAddDoubleBySync(String key, String hashKey, double data) { + return new BigDecimal(Double.toString(this.addDoubleBySync(key, hashKey, data))).subtract(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 浮点数减小 + * @see Redis Documentation: INCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param data 步长 + * @return 返回相减后的值 + */ + public Double subtractDouble(String key, double data) { + return this.addDouble(key, -data); + } + + /** + * 浮点数减小 + * @see Redis Documentation: GET + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param data 步长 + * @return 返回相减后的值 + */ + public synchronized Double subtractDoubleBySync(String key, double data) { + return this.addDoubleBySync(key, -data); + } + + /** + * 浮点数减小 + * @see Redis Documentation: HINCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回相减后的值 + */ + public Double subtractDouble(String key, String hashKey, double data) { + return this.addDouble(key, hashKey, -data); + } + + /** + * 浮点数减小 + * @see Redis Documentation: HGET + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回相减后的值 + */ + public synchronized Double subtractDoubleBySync(String key, String hashKey, double data) { + return this.addDoubleBySync(key, hashKey, -data); + } + + /** + * 获取并减小浮点数 + * @see Redis Documentation: INCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param data 步长 + * @return 返回原值 + */ + public Double getAndSubtractDouble(String key, double data) { + return new BigDecimal(Double.toString(this.subtractDouble(key, data))).add(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 获取并减小浮点数 + * @see Redis Documentation: GET + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param data 步长 + * @return 返回原值 + */ + public synchronized Double getAndSubtractDoubleBySync(String key, double data) { + return new BigDecimal(Double.toString(this.subtractDoubleBySync(key, data))).add(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 获取并减小浮点数 + * @see Redis Documentation: HINCRBYFLOAT + * @since redis 2.6.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回原值 + */ + public Double getAndSubtractDouble(String key, String hashKey, double data) { + return new BigDecimal(Double.toString(this.subtractDouble(key, hashKey, data))).add(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 获取并减小浮点数 + * @see Redis Documentation: HGET + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回原值 + */ + public synchronized Double getAndSubtractDoubleBySync(String key, String hashKey, double data) { + return new BigDecimal(Double.toString(this.subtractDoubleBySync(key, hashKey, data))).add(new BigDecimal(Double.toString(data))).doubleValue(); + } + + /** + * 设置长整数 + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param value 值 + */ + public void setLong(String key, long value) { + this.stringOperations.set(key, String.valueOf(value)); + } + + /** + * 设置长整数 + * @see Redis Documentation: HSET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 值 + */ + public void setLong(String key, String hashKey, long value) { + this.stringHashOperations.put(key, hashKey, String.valueOf(value)); + } + + /** + * 设置长整数(若存在则更新过期时间) + * @see Redis Documentation: SETEX + * @since redis 2.0.0 + * @param key 键 + * @param value 值 + * @param timeout 过期时间 + * @param unit 时间单位 + */ + public void setLong(String key, long value, long timeout, TimeUnit unit) { + this.stringOperations.set(key, String.valueOf(value), timeout, unit); + } + + /** + * 设置长整数如果不存在 + * @see Redis Documentation: SETNX + * @since redis 1.0.0 + * @param key 键 + * @param value 长整数 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setLongIfAbsent(String key, long value) { + return this.stringOperations.setIfAbsent(key, String.valueOf(value)); + } + + /** + * 设置长整数如果不存在 + * @see Redis Documentation: HSETNX + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param value 长整数 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setLongIfAbsent(String key, String hashKey, long value) { + return this.stringHashOperations.putIfAbsent(key, hashKey, String.valueOf(value)); + } + + /** + * 设置长整数并设置过期时间如果不存在 + * @see Redis Documentation: SETNX + * @since redis 2.6.12 + * @param key 键 + * @param value 长整数 + * @param timeout 过期时间 + * @param unit 时间单位 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setLongIfAbsent(String key, long value, long timeout, TimeUnit unit) { + return this.stringOperations.setIfAbsent(key, String.valueOf(value), timeout, unit); + } + + /** + * 获取长整数 + * @see Redis Documentation: GET + * @since redis 1.0.0 + * @param key 键 + * @return 返回长整数 + */ + public Long getLong(String key) { + String value = this.stringOperations.get(key); + if (value!=null) { + return Long.valueOf(value); + } + return null; + } + + /** + * 获取长整数 + * @see Redis Documentation: HGET + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回长整数 + */ + public Long getLong(String key, String hashKey) { + String value = this.stringHashOperations.get(key, hashKey); + if (value!=null) { + return Long.valueOf(value); + } + return null; + } + + /** + * 获取并设置长整数 + * @see Redis Documentation: GETSET + * @since redis 1.0.0 + * @param key 键 + * @param newValue 新值 + * @return 返回原值 + */ + public Long getAndSetLong(String key, long newValue) { + String value = this.stringOperations.getAndSet(key, String.valueOf(newValue)); + return value!=null?Long.valueOf(value):null; + } + + /** + * 获取并设置长整数 + * @see Redis Documentation: HGET + * @see Redis Documentation: HSET + * @since redis 1.0.0 + * @param key 键 + * @param hashKey hash键 + * @param newValue 新值 + * @return 返回原值 + */ + public Long getAndSetLong(String key, String hashKey, long newValue) { + Long value = this.getLong(key, hashKey); + this.setLong(key, hashKey, newValue); + return value; + } + + /** + * 增加长整数 + * @see Redis Documentation: INCRBY + * @since redis 1.0.0 + * @param key 键 + * @param data 步长 + * @return 返回增加后的值 + */ + public Long addLong(String key, long data) { + return this.stringOperations.increment(key, data); + } + + /** + * 增加长整数 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回增加后的值 + */ + public Long addLong(String key, String hashKey, long data) { + return this.stringHashOperations.increment(key, hashKey, data); + } + + /** + * 获取并增加长整数 + * @see Redis Documentation: INCRBY + * @since redis 1.0.0 + * @param key 键 + * @param data 步长 + * @return 返回原值 + */ + public Long getAndAddLong(String key, long data) { + return this.addLong(key, data) - data; + } + + /** + * 获取并增加长整数 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回原值 + */ + public Long getAndAddLong(String key, String hashKey, long data) { + return this.addLong(key, hashKey, data) - data; + } + + /** + * 长整数自增 + * @see Redis Documentation: INCR + * @since redis 1.0.0 + * @param key 键 + * @return 返回自增后的值 + */ + public Long incrementLong(String key) { + return this.stringOperations.increment(key); + } + + /** + * 长整数自增 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回自增后的值 + */ + public Long incrementLong(String key, String hashKey) { + return this.addLong(key, hashKey, 1L); + } + + /** + * 获取并自增长整数 + * @see Redis Documentation: INCR + * @since redis 1.0.0 + * @param key 键 + * @return 返回原值 + */ + public Long getAndIncrementLong(String key) { + return this.incrementLong(key) - 1L; + } + + /** + * 获取并自增长整数 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回原值 + */ + public Long getAndIncrementLong(String key, String hashKey) { + return this.incrementLong(key, hashKey) - 1L; + } + + /** + * 长整数减小 + * @see Redis Documentation: DECRBY + * @since redis 1.0.0 + * @param key 键 + * @param data 步长 + * @return 返回减小后的值 + */ + public Long subtractLong(String key, long data) { + return this.stringOperations.decrement(key, data); + } + + /** + * 长整数减小 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回减小后的值 + */ + public Long subtractLong(String key, String hashKey, long data) { + return this.stringHashOperations.increment(key, hashKey, -data); + } + + /** + * 获取并减小长整数 + * @see Redis Documentation: DECRBY + * @since redis 1.0.0 + * @param key 键 + * @param data 步长 + * @return 返回原值 + */ + public Long getAndSubtractLong(String key, long data) { + return this.subtractLong(key, data) + data; + } + + /** + * 获取并减小长整数 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @param data 步长 + * @return 返回原值 + */ + public Long getAndSubtractLong(String key, String hashKey, long data) { + return this.subtractLong(key, hashKey, data) + data; + } + + /** + * 长整数递减 + * @see Redis Documentation: DECR + * @since redis 1.0.0 + * @param key 键 + * @return 返回递减后的值 + */ + public Long decrementLong(String key) { + return this.stringOperations.decrement(key); + } + + /** + * 长整数递减 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回递减后的值 + */ + public Long decrementLong(String key, String hashKey) { + return this.subtractLong(key, hashKey, 1L); + } + + /** + * 获取并递减长整数 + * @see Redis Documentation: DECR + * @since redis 1.0.0 + * @param key 键 + * @return 返回原值 + */ + public Long getAndDecrementLong(String key) { + return this.decrementLong(key) + 1L; + } + + /** + * 获取并递减长整数 + * @see Redis Documentation: HINCRBY + * @since redis 2.0.0 + * @param key 键 + * @param hashKey hash键 + * @return 返回原值 + */ + public Long getAndDecrementLong(String key, String hashKey) { + return this.decrementLong(key, hashKey) + 1L; + } + + /** + * 移除 + * @see Redis Documentation: DEL + * @since redis 1.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long removeForValue(String ...keys) { + return this.stringOperations.getOperations().delete(Arrays.asList(keys)); + } + + /** + * 移除 + * @see Redis Documentation: HDEL + * @since redis 2.0.0 + * @param key 键 + * @param hashKeys hash键 + * @return 返回移除数量 + */ + public Long removeForHash(String key, String ...hashKeys) { + return this.stringHashOperations.delete(key, (Object[]) hashKeys); + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/PubSubHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/PubSubHandler.java new file mode 100644 index 0000000..a89fda4 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/PubSubHandler.java @@ -0,0 +1,213 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.Subscription; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 发布与订阅助手 + * @author xsx + * @date 2019/5/21 + * @since 1.8 + */ +public final class PubSubHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * redis连接 + */ + private RedisConnection connection; + + /** + * 发布与订阅助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + PubSubHandler(Integer dbIndex) { + this.redisTemplate = HandlerManager.createRedisTemplate(dbIndex); + this.connection = this.redisTemplate.getRequiredConnectionFactory().getConnection(); + } + + /** + * 发布与订阅助手构造 + * @param transactionHandler 事务助手 + */ + PubSubHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.connection = this.redisTemplate.getRequiredConnectionFactory().getConnection(); + } + + /** + * 发布消息 + * @see Redis Documentation: PUBLISH + * @since redis 2.0.0 + * @param channel 频道 + * @param message 消息 + */ + public void publish(String channel, Object message) { + this.redisTemplate.convertAndSend(channel, message); + } + + /** + * 订阅频道 + * @see Redis Documentation: SUBSCRIBE + * @since redis 2.0.0 + * @param listener 监听器 + * @param channels 频道 + */ + public void subscribe(MessageListener listener, String ...channels) { + this.connection.subscribe(listener, ConvertUtil.toByteArray(RedisSerializer.string(), channels)); + } + + /** + * 订阅给定模式的频道 + * @see Redis Documentation: PSUBSCRIBE + * @since redis 2.0.0 + * @param listener 监听器 + * @param patterns 模式 + */ + public void pSubscribe(MessageListener listener, String ...patterns) { + this.connection.pSubscribe(listener, ConvertUtil.toByteArray(RedisSerializer.string(), patterns)); + } + + /** + * 添加字符串订阅频道 + * @since redis 2.0.0 + * @param channels 频道 + */ + public void addSubChannels(String ...channels) { + Subscription subscription = this.connection.getSubscription(); + if ((subscription != null && subscription.isAlive())) { + subscription.subscribe(ConvertUtil.toByteArray(RedisSerializer.string(), channels)); + } + } + + /** + * 添加给定模式字符串订阅频道 + * @since redis 2.0.0 + * @param patterns 模式 + */ + public void addPSubChannels(String ...patterns) { + Subscription subscription = this.connection.getSubscription(); + if ((subscription != null && subscription.isAlive())) { + subscription.pSubscribe(ConvertUtil.toByteArray(RedisSerializer.string(), patterns)); + } + } + + /** + * 退订频道 + * @see Redis Documentation: UNSUBSCRIBE + * @since redis 2.0.0 + * @param channels 频道 + */ + public void unsubscribe(String ...channels) { + Subscription subscription = this.connection.getSubscription(); + if ((subscription != null && subscription.isAlive())) { + if (channels==null || channels.length==0) { + subscription.unsubscribe(); + }else { + subscription.unsubscribe(ConvertUtil.toByteArray(RedisSerializer.string(), channels)); + } + } + } + + /** + * 退订给定模式频道 + * @see Redis Documentation: PUNSUBSCRIBE + * @since redis 2.0.0 + * @param patterns 模式 + */ + public void pUnsubscribe(String ...patterns) { + Subscription subscription = this.connection.getSubscription(); + if ((subscription != null && subscription.isAlive())) { + if (patterns==null || patterns.length==0) { + subscription.pUnsubscribe(); + }else { + subscription.pUnsubscribe(ConvertUtil.toByteArray(RedisSerializer.string(), patterns)); + } + } + } + + /** + * 获取订阅频道 + * @since redis 2.0.0 + * @return 返回频道列表 + */ + public List getChannels() { + return this.getChannelOrPatterns(true); + } + + /** + * 获取订阅模式 + * @since redis 2.0.0 + * @return 返回模式列表 + */ + public List getPatterns() { + return this.getChannelOrPatterns(false); + } + + /** + * 反序列化 + * @param bytes 字节数组 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T deserialize(byte[] bytes) { + return (T) ConvertUtil.toJavaType(this.redisTemplate.getValueSerializer().deserialize(bytes), Object.class); + } + + /** + * 反序列化 + * @param type 返回值类型 + * @param bytes 字节数组 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T deserialize(Class type, byte[] bytes) { + return (T) ConvertUtil.toJavaType(this.redisTemplate.getValueSerializer().deserialize(bytes), type); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取频道或模式 + * @param isChannels 是否频道 + * @return 返回列表 + */ + private List getChannelOrPatterns(boolean isChannels) { + Subscription subscription = this.connection.getSubscription(); + if ((subscription != null && subscription.isAlive())) { + Collection channels; + if (isChannels) { + channels = subscription.getChannels(); + }else { + channels = subscription.getPatterns(); + } + List list = new ArrayList<>(channels.size()); + RedisSerializer serializer = RedisSerializer.string(); + for (byte[] channel : channels) { + list.add(serializer.deserialize(channel)); + } + return list; + } + return new ArrayList<>(); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisHandler.java new file mode 100644 index 0000000..2534a2b --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisHandler.java @@ -0,0 +1,11 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +/** + * redis助手 + * @author xsx + * @date 2019/6/8 + * @since 1.8 + */ +public interface RedisHandler { + +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisLockHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisLockHandler.java new file mode 100644 index 0000000..af07fcf --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/RedisLockHandler.java @@ -0,0 +1,112 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.redisson.api.RCountDownLatch; +import org.redisson.api.RLock; +import org.redisson.api.RPermitExpirableSemaphore; +import org.redisson.api.RReadWriteLock; +import org.redisson.api.RSemaphore; +import org.redisson.api.RedissonClient; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.config.redisson.RedissonClientHelper; + +/** + * 分布式锁助手(需添加redisson依赖) + * @author xsx + * @date 2019/5/9 + * @since 1.8 + */ +public final class RedisLockHandler implements RedisHandler { + + /** + * redisson客户端 + */ + private RedissonClient redissonClient; + + /** + * 分布式锁助手构造 + * @param dbIndex 数据库索引 + */ + RedisLockHandler(Integer dbIndex) { + this.redissonClient = RedissonClientHelper.createClient(dbIndex); + } + + /** + * 获取可重入锁 + * @param name 名称 + * @return 返回可重入锁 + */ + public RLock getLock(String name) { + return this.redissonClient.getLock(name); + } + + /** + * 获取公平锁 + * @param name 名称 + * @return 返回公平锁 + */ + public RLock getFairLock(String name) { + return this.redissonClient.getFairLock(name); + } + + /** + * 获取读写锁 + * @param name 名称 + * @return 返回读写锁 + */ + public RReadWriteLock getReadWriteLock(String name) { + return this.redissonClient.getReadWriteLock(name); + } + + /** + * 获取闭锁 + * @param name 名称 + * @return 返回闭锁 + */ + public RCountDownLatch getCountDownLatch(String name) { + return this.redissonClient.getCountDownLatch(name); + } + + /** + * 获取联锁 + * @param locks 锁列表 + * @return 返回联锁 + */ + public RLock getMultiLock(RLock ...locks) { + return this.redissonClient.getMultiLock(locks); + } + + /** + * 获取红锁 + * @param locks 锁列表 + * @return 返回红锁 + */ + public RLock getRedLock(RLock ...locks) { + return this.redissonClient.getRedLock(locks); + } + + /** + * 获取信号量 + * @param name 名称 + * @return 返回信号量 + */ + public RSemaphore getSemaphore(String name) { + return this.redissonClient.getSemaphore(name); + } + + /** + * 获取可过期信号量 + * @param name 名称 + * @return 返回可过期信号量 + */ + public RPermitExpirableSemaphore getExpirableSemaphore(String name) { + return this.redissonClient.getPermitExpirableSemaphore(name); + } + + /** + * 获取redisson客户端 + * @return 返回redisson客户端 + */ + public RedissonClient getRedissonClient() { + return this.redissonClient; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ScriptHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ScriptHandler.java new file mode 100644 index 0000000..eb59cad --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ScriptHandler.java @@ -0,0 +1,357 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.redis.connection.RedisScriptingCommands; +import org.springframework.data.redis.connection.ReturnType; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.data.redis.serializer.RedisSerializer; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * lua脚本助手 + * @author xsx + * @date 2019/5/9 + * @since 1.8 + */ +public final class ScriptHandler implements RedisHandler { + + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象脚本命令 + */ + private RedisScriptingCommands commands; + /** + * 字符串脚本命令 + */ + private RedisScriptingCommands stringCommands; + + /** + * lua脚本助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + ScriptHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.commands = this.redisTemplate.getRequiredConnectionFactory().getConnection().scriptingCommands(); + this.stringCommands = this.stringRedisTemplate.getRequiredConnectionFactory().getConnection().scriptingCommands(); + } + + /** + * lua脚本助手构造 + * @param transactionHandler 事务助手 + */ + ScriptHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.commands = this.redisTemplate.getRequiredConnectionFactory().getConnection().scriptingCommands(); + this.stringCommands = this.stringRedisTemplate.getRequiredConnectionFactory().getConnection().scriptingCommands(); + } + + /** + * 执行对象脚本 + * @see Redis Documentation: EVAL + * @since redis 2.6.0 + * @param scriptText lua脚本 + * @param resultType 返回类型 + * @param keys 键列表 + * @param args 参数列表 + * @param 返回类型 + * @return 返回脚本类型对象 + */ + public T excuteAsObj(String scriptText, Class resultType, List keys, Object... args) { + return this.redisTemplate.execute(this.buildScriptWithText(scriptText, resultType), keys, args); + } + + /** + * 执行字符串脚本 + * @see Redis Documentation: EVAL + * @since redis 2.6.0 + * @param scriptText lua脚本 + * @param resultType 返回类型 + * @param keys 键列表 + * @param args 参数列表 + * @param 返回类型 + * @return 返回脚本类型对象 + */ + public T excute(String scriptText, Class resultType, List keys, Object... args) { + return this.stringRedisTemplate.execute(this.buildScriptWithText(scriptText, resultType), keys, args); + } + + /** + * 执行对象脚本 + * @see Redis Documentation: EVAL + * @since redis 2.6.0 + * @param scriptLocation lua脚本路径 + * @param resultType 返回类型 + * @param argsSerializer 参数序列化类型 + * @param resultSerializer 结果序列化类型 + * @param keys 键列表 + * @param args 参数列表 + * @param 返回类型 + * @return 返回脚本类型对象 + */ + public T excuteAsObj( + String scriptLocation, + Class resultType, + RedisSerializer argsSerializer, + RedisSerializer resultSerializer, + List keys, + Object... args + ) { + return this.redisTemplate.execute( + this.buildScriptWithLocation(scriptLocation, resultType), + argsSerializer, + resultSerializer, + keys, + args + ); + } + + /** + * 执行字符串脚本 + * @see Redis Documentation: EVAL + * @since redis 2.6.0 + * @param scriptLocation lua脚本路径 + * @param resultType 返回类型 + * @param argsSerializer 参数序列化类型 + * @param resultSerializer 结果序列化类型 + * @param keys 键列表 + * @param args 参数列表 + * @param 返回类型 + * @return 返回脚本类型对象 + */ + public T excute( + String scriptLocation, + Class resultType, + RedisSerializer argsSerializer, + RedisSerializer resultSerializer, + List keys, + Object... args + ) { + return this.stringRedisTemplate.execute( + this.buildScriptWithLocation(scriptLocation, resultType), + argsSerializer, + resultSerializer, + keys, + args + ); + } + + /** + * 执行对象缓存脚本 + * @see Redis Documentation: EVALSHA + * @since redis 2.6.0 + * @param scriptSHA 脚本缓存SHA码 + * @param resultType 返回类型 + * @param keys 键列表 + * @param args 参数列表 + * @param 返回类型 + * @return 返回脚本类型对象 + */ + public T excuteWithSHAAsObj(String scriptSHA, Class resultType, List keys, Object... args) { + return this.commands.evalSha( + scriptSHA, + ReturnType.fromJavaType(resultType), + keys.size(), + ConvertUtil.toByteArray( + this.redisTemplate.getKeySerializer(), + this.redisTemplate.getValueSerializer(), + keys, + args + ) + ); + } + + /** + * 执行字符串缓存脚本 + * @see Redis Documentation: EVALSHA + * @since redis 2.6.0 + * @param scriptSHA 脚本缓存SHA码 + * @param resultType 返回类型 + * @param keys 键列表 + * @param args 参数列表 + * @param 返回类型 + * @return 返回脚本类型对象 + */ + public T excuteWithSHA(String scriptSHA, Class resultType, List keys, Object... args) { + return this.stringCommands.evalSha( + scriptSHA, + ReturnType.fromJavaType(resultType), + keys.size(), + ConvertUtil.toByteArray( + this.stringRedisTemplate.getKeySerializer(), + this.stringRedisTemplate.getValueSerializer(), + keys, + args + ) + ); + } + + /** + * 加载对象脚本到缓存 + * @see Redis Documentation: SCRIPT LOAD + * @since redis 2.6.0 + * @param scriptText lua脚本 + * @return 返回SHA1校验码 + */ + public String loadAsObj(String scriptText) { + return this.commands.scriptLoad(RedisSerializer.string().serialize(scriptText)); + } + + /** + * 加载字符串脚本到缓存 + * @see Redis Documentation: SCRIPT LOAD + * @since redis 2.6.0 + * @param scriptText lua脚本 + * @return 返回SHA1校验码 + */ + public String load(String scriptText) { + return this.stringCommands.scriptLoad(RedisSerializer.string().serialize(scriptText)); + } + + /** + * 加载对象脚本到缓存 + * @see Redis Documentation: SCRIPT LOAD + * @since redis 2.6.0 + * @param scriptLocation lua脚本路径 + * @return 返回SHA1校验码 + */ + public String loadByLocationAsObj(String scriptLocation) { + return this.commands.scriptLoad( + this.buildScriptWithLocation(scriptLocation, null) + .getScriptAsString() + .getBytes(StandardCharsets.UTF_8) + ); + } + + /** + * 加载字符串脚本到缓存 + * @see Redis Documentation: SCRIPT LOAD + * @since redis 2.6.0 + * @param scriptLocation lua脚本路径 + * @return 返回SHA1校验码 + */ + public String loadByLocation(String scriptLocation) { + return this.stringCommands.scriptLoad( + this.buildScriptWithLocation(scriptLocation, null) + .getScriptAsString() + .getBytes(StandardCharsets.UTF_8) + ); + } + + /** + * 是否存在对象脚本 + * @see Redis Documentation: SCRIPT EXISTS + * @since redis 2.6.0 + * @param scriptSHAs 脚本sha1验证码 + * @return 返回布尔值列表 + */ + public List existsAsObj(String ...scriptSHAs) { + return this.commands.scriptExists(scriptSHAs); + } + + /** + * 是否存在字符串脚本 + * @see Redis Documentation: SCRIPT EXISTS + * @since redis 2.6.0 + * @param scriptSHAs 脚本sha1验证码 + * @return 返回布尔值列表 + */ + public List exists(String ...scriptSHAs) { + return this.stringCommands.scriptExists(scriptSHAs); + } + + /** + * 清除对象脚本缓存 + * @see Redis Documentation: SCRIPT FLUSH + * @since redis 2.6.0 + */ + public void clearAsObj() { + this.commands.scriptFlush(); + } + + /** + * 清除字符串脚本缓存 + * @see Redis Documentation: SCRIPT FLUSH + * @since redis 2.6.0 + */ + public void clear() { + this.stringCommands.scriptFlush(); + } + + /** + * 停止对象脚本 + * @see Redis Documentation: SCRIPT KILL + * @since redis 2.6.0 + */ + public void stopAsObj() { + this.commands.scriptKill(); + } + + /** + * 停止字符串脚本 + * @see Redis Documentation: SCRIPT KILL + * @since redis 2.6.0 + */ + public void stop() { + this.stringCommands.scriptKill(); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } + + /** + * 通过路径创建脚本 + * @param scriptLocation 脚本路径 + * @param resultType 返回类型 + * @param 类型 + * @return 返回脚本 + */ + private RedisScript buildScriptWithLocation(String scriptLocation, Class resultType) { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setLocation(new ClassPathResource(scriptLocation)); + redisScript.setResultType(resultType); + return redisScript; + } + + /** + * 通过字符串创建脚本 + * @param scriptText 脚本字符串 + * @param resultType 返回类型 + * @param 类型 + * @return 返回脚本 + */ + @SuppressWarnings("unchecked") + private RedisScript buildScriptWithText(String scriptText, Class resultType) { + return RedisScript.of(scriptText, resultType); + } +} \ No newline at end of file diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SentinelHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SentinelHandler.java new file mode 100644 index 0000000..5fa0591 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SentinelHandler.java @@ -0,0 +1,143 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisNode; +import org.springframework.data.redis.connection.RedisServer; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.Collection; +import java.util.Properties; + +/** + * 哨兵助手 + * @author xsx + * @date 2019/5/23 + * @since 1.8 + */ +public final class SentinelHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 连接工厂 + */ + private RedisConnectionFactory connectionFactory; + + /** + * 哨兵助手构造 + * @param dbIndex 数据库索引 + */ + SentinelHandler(Integer dbIndex) { + this.redisTemplate = HandlerManager.createRedisTemplate(dbIndex); + this.connectionFactory = this.redisTemplate.getRequiredConnectionFactory(); + } + + /** + * 哨兵助手构造 + * @param transactionHandler 事务助手 + */ + SentinelHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.connectionFactory = this.redisTemplate.getRequiredConnectionFactory(); + } + + /** + * 是否连接 + */ + public void isOpen() { + this.connectionFactory.getSentinelConnection().isOpen(); + } + + /** + * 故障转移 + * @see Redis Sentinel Documentation + * @since redis 2.8 + * @param masterName 主服务名称 + */ + public void failover(String masterName) { + this.connectionFactory.getSentinelConnection().failover( + RedisNode.newRedisNode() + .withName(masterName) + .promotedAs(RedisNode.NodeType.MASTER) + .build() + ); + } + + /** + * 主服务器列表 + * @see Redis Sentinel Documentation + * @since redis 2.8 + * @return 返回主服务器列表 + */ + public Collection masters() { + return this.connectionFactory.getSentinelConnection().masters(); + } + + /** + * 从服务器列表 + * @see Redis Sentinel Documentation + * @since redis 2.8 + * @param masterName 主服务器名称 + * @return 返回从服务器列表 + */ + public Collection slaves(String masterName) { + return this.connectionFactory.getSentinelConnection().slaves( + RedisNode.newRedisNode() + .withName(masterName) + .promotedAs(RedisNode.NodeType.MASTER) + .build() + ); + } + + /** + * 监控主服务器 + * @see Redis Sentinel Documentation + * @since redis 2.8 + * @param master 主服务器对象 + */ + public void monitor(RedisServer master) { + this.connectionFactory.getSentinelConnection().monitor(master); + } + + /** + * 监控主服务器 + * @see Redis Sentinel Documentation + * @since redis 2.8 + * @param name 主服务器名称 + * @param ip 主服务器IP + * @param port 主服务器端口 + * @param quorum 确认故障的最少哨兵数量 + */ + public void monitor(String name, String ip, String port, String quorum) { + Properties properties = new Properties(); + properties.setProperty("name", name); + properties.setProperty("ip", ip); + properties.setProperty("port", port); + properties.setProperty("quorum", quorum); + this.monitor(RedisServer.newServerFrom(properties)); + } + + /** + * 移除主服务器 + * @see Redis Sentinel Documentation + * @since redis 2.8 + * @param masterName 主服务器名称 + */ + public void remove(String masterName) { + this.connectionFactory.getSentinelConnection().remove( + RedisNode.newRedisNode() + .withName(masterName) + .promotedAs(RedisNode.NodeType.MASTER) + .build() + ); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SetHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SetHandler.java new file mode 100644 index 0000000..4e562b2 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/SetHandler.java @@ -0,0 +1,544 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.data.redis.core.StringRedisTemplate; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 无序集合助手 + * @author xsx + * @date 2019/4/15 + * @since 1.8 + */ +public final class SetHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private SetOperations setOperations; + /** + * 字符串模板 + */ + private SetOperations stringSetOperations; + + /** + * 无序集合助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + SetHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.setOperations = redisTemplate.opsForSet(); + this.stringSetOperations = stringRedisTemplate.opsForSet(); + } + + /** + * 无序集合助手构造 + * @param transactionHandler 事务助手 + */ + SetHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.setOperations = this.redisTemplate.opsForSet(); + this.stringSetOperations = this.stringRedisTemplate.opsForSet(); + } + + /** + * 新增对象 + * @see Redis Documentation: SADD + * @param key 键 + * @since redis 1.0.0 + * @param values 对象 + * @return 返回成功个数 + */ + public Long addAsObj(String key, Object ...values) { + return this.setOperations.add(key, values); + } + + /** + * 新增字符串 + * @see Redis Documentation: SADD + * @since redis 1.0.0 + * @param key 键 + * @param values 字符串 + * @return 返回成功个数 + */ + public Long add(String key, String ...values) { + return this.stringSetOperations.add(key, values); + } + + /** + * 弹出对象 + * @see Redis Documentation: SPOP + * @since redis 1.0.0 + * @param key 键 + * @param 对象类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T popAsObj(String key) { + return (T) ConvertUtil.toJavaType(this.setOperations.pop(key), Object.class); + } + + /** + * 弹出对象 + * @see Redis Documentation: SPOP + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T popAsObj(Class type, String key) { + return (T) ConvertUtil.toJavaType(this.setOperations.pop(key), type); + } + + /** + * 弹出字符串 + * @see Redis Documentation: SPOP + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串 + */ + public String pop(String key) { + return this.stringSetOperations.pop(key); + } + + /** + * 弹出对象 + * @see Redis Documentation: SPOP + * @since redis 3.2.0 + * @param key 键 + * @param count 对象个数 + * @return 返回对象列表 + */ + public List popAsObj(String key, Long count) { + return this.setOperations.pop(key, count); + } + + /** + * 弹出字符串 + * @see Redis Documentation: SPOP + * @since redis 3.2.0 + * @param key 键 + * @param count 字符串个数 + * @return 返回字符串列表 + */ + public List pop(String key, Long count) { + return this.stringSetOperations.pop(key, count); + } + + /** + * 移除对象 + * @see Redis Documentation: SREM + * @since redis 1.0.0 + * @param key 键 + * @param values 对象 + * @return 返回移除对象数量 + */ + public Long removeAsObj(String key, Object ...values) { + return this.setOperations.remove(key, values); + } + + /** + * 移除字符串 + * @see Redis Documentation: SREM + * @since redis 1.0.0 + * @param key 键 + * @param values 字符串 + * @return 返回移除字符串数量 + */ + public Long remove(String key, String ...values) { + return this.stringSetOperations.remove(key, (Object[]) values); + } + + /** + * 移动对象 + * @see Redis Documentation: SMOVE + * @since redis 1.0.0 + * @param key 键 + * @param destKey 目标键 + * @param value 对象 + * @return 返回布尔值,成功true,失败false + */ + public Boolean moveAsObj(String key, String destKey, Object value) { + return this.setOperations.move(key, value, destKey); + } + + /** + * 移动字符串 + * @see Redis Documentation: SMOVE + * @since redis 1.0.0 + * @param key 键 + * @param destKey 目标键 + * @param value 字符串 + * @return 返回布尔值,成功true,失败false + */ + public Boolean move(String key, String destKey, String value) { + return this.stringSetOperations.move(key, value, destKey); + } + + /** + * 获取对象数量 + * @see Redis Documentation: SCARD + * @since redis 1.0.0 + * @param key 键 + * @return 返回对象数量 + */ + public Long sizeAsObj(String key) { + return this.setOperations.size(key); + } + + /** + * 获取字符串数量 + * @see Redis Documentation: SCARD + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串数量 + */ + public Long size(String key) { + return this.stringSetOperations.size(key); + } + + /** + * 是否包含对象 + * @see Redis Documentation: SISMEMBER + * @since redis 1.0.0 + * @param key 键 + * @param value 对象 + * @return 返回布尔值,存在true,不存在false + */ + public Boolean containsAsObj(String key, Object value) { + return this.setOperations.isMember(key, value); + } + + /** + * 是否包含字符串 + * @see Redis Documentation: SISMEMBER + * @since redis 1.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回布尔值,存在true,不存在false + */ + public Boolean contains(String key, String value) { + return this.stringSetOperations.isMember(key, value); + } + + /** + * 获取不重复的随机对象 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param key 键 + * @param count 数量 + * @return 返回不重复的随机对象集合 + */ + public Set distinctRandomMembersAsObj(String key, Long count) { + return this.setOperations.distinctRandomMembers(key, count); + } + + /** + * 获取不重复的随机字符串 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param key 键 + * @param count 数量 + * @return 返回不重复的随机字符串集合 + */ + public Set distinctRandomMembers(String key, Long count) { + return this.stringSetOperations.distinctRandomMembers(key, count); + } + + /** + * 获取可重复的随机对象 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param key 键 + * @param count 数量 + * @return 返回不重复的随机对象集合 + */ + public List randomMembersAsObj(String key, Long count) { + return this.setOperations.randomMembers(key, count); + } + + /** + * 获取可重复的随机字符串 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param key 键 + * @param count 数量 + * @return 返回不重复的随机字符串集合 + */ + public List randomMembers(String key, Long count) { + return this.stringSetOperations.randomMembers(key, count); + } + + /** + * 获取可重复的随机对象 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param key 键 + * @param 对象类型 + * @return 返回可重复的随机对象 + */ + @SuppressWarnings("unchecked") + public T randomMemberAsObj(String key) { + return (T) ConvertUtil.toJavaType(this.setOperations.randomMember(key), Object.class); + } + + /** + * 获取可重复的随机对象 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param type 返回值类型 + * @param key 键 + * @param 返回类型 + * @return 返回可重复的随机对象 + */ + @SuppressWarnings("unchecked") + public T randomMemberAsObj(Class type, String key) { + return (T) ConvertUtil.toJavaType(this.setOperations.randomMember(key), type); + } + + /** + * 获取可重复的随机字符串 + * @see Redis Documentation: SRANDMEMBER + * @since redis 2.6.0 + * @param key 键 + * @return 返回可重复的随机字符串 + */ + public String randomMember(String key) { + return this.stringSetOperations.randomMember(key); + } + + /** + * 获取对象集合 + * @see Redis Documentation: SMEMBERS + * @since redis 1.0.0 + * @param key 键 + * @return 返回对象集合 + */ + public Set membersAsObj(String key) { + return this.setOperations.members(key); + } + + /** + * 获取字符串集合 + * @see Redis Documentation: SMEMBERS + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串集合 + */ + public Set members(String key) { + return this.stringSetOperations.members(key); + } + + /** + * 取对象差集 + * @see Redis Documentation: SDIFF + * @since redis 1.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回与其他集合的对象差集 + */ + public Set differenceAsObj(String key, String ...otherKys) { + return this.setOperations.difference(key, Arrays.asList(otherKys)); + } + + /** + * 取字符串差集 + * @see Redis Documentation: SDIFF + * @since redis 1.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回与其他集合的字符串差集 + */ + public Set difference(String key, String ...otherKys) { + return this.stringSetOperations.difference(key, Arrays.asList(otherKys)); + } + + /** + * 取对象差集并存储到新的集合 + * @see Redis Documentation: SDIFFSTORE + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回差集对象个数 + */ + public Long differenceAndStoreAsObj(String key, String storeKey, String ...otherKys) { + return this.setOperations.differenceAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取字符串差集并存储到新的集合 + * @see Redis Documentation: SDIFFSTORE + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回差集字符串个数 + */ + public Long differenceAndStore(String key, String storeKey, String ...otherKys) { + return this.stringSetOperations.differenceAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取对象交集 + * @see Redis Documentation: SINTER + * @since redis 1.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回与其他集合的对象交集 + */ + public Set intersectAsObj(String key, String ...otherKys) { + return this.setOperations.intersect(key, Arrays.asList(otherKys)); + } + + /** + * 取字符串交集 + * @see Redis Documentation: SINTER + * @since redis 1.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回与其他集合的字符串交集 + */ + public Set intersect(String key, String ...otherKys) { + return this.stringSetOperations.intersect(key, Arrays.asList(otherKys)); + } + + /** + * 取对象交集并存储到新的集合 + * @see Redis Documentation: SINTERSTORE + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long intersectAndStoreAsObj(String key, String storeKey, String ...otherKys) { + return this.setOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取字符串交集并存储到新的集合 + * @see Redis Documentation: SINTERSTORE + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long intersectAndStore(String key, String storeKey, String ...otherKys) { + return this.stringSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取对象并集 + * @see Redis Documentation: SUNION + * @since redis 1.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回与其他集合的对象交集 + */ + public Set unionAsObj(String key, String ...otherKys) { + return this.setOperations.union(key, Arrays.asList(otherKys)); + } + + /** + * 取字符串并集 + * @see Redis Documentation: SUNION + * @since redis 1.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回与其他集合的字符串交集 + */ + public Set union(String key, String ...otherKys) { + return this.stringSetOperations.union(key, Arrays.asList(otherKys)); + } + + /** + * 取对象并集并存储到新的集合 + * @see Redis Documentation: SUNIONSTORE + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回并集对象个数 + */ + public Long unionAndStoreAsObj(String key, String storeKey, String ...otherKys) { + return this.setOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取字符串并集并存储到新的集合 + * @see Redis Documentation: SUNIONSTORE + * @since redis 1.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回并集字符串个数 + */ + public Long unionAndStore(String key, String storeKey, String ...otherKys) { + return this.stringSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 匹配对象 + * @see Redis Documentation: SSCAN + * @since redis 2.8.0 + * @param key 键 + * @param count 数量 + * @param pattern 规则 + * @return 返回匹配对象 + */ + public Cursor scanAsObj(String key, Long count, String pattern) { + return this.setOperations.scan(key, ScanOptions.scanOptions().count(count).match(pattern).build()); + } + + /** + * 匹配字符串 + * @see Redis Documentation: SSCAN + * @since redis 2.8.0 + * @param key 键 + * @param count 数量 + * @param pattern 规则 + * @return 返回匹配字符串 + */ + public Cursor scan(String key, Long count, String pattern) { + return this.stringSetOperations.scan(key, ScanOptions.scanOptions().count(count).match(pattern).build()); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StreamHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StreamHandler.java new file mode 100644 index 0000000..96055bc --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StreamHandler.java @@ -0,0 +1,1305 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.data.domain.Range; +import org.springframework.data.redis.connection.RedisZSetCommands; +import org.springframework.data.redis.connection.stream.Consumer; +import org.springframework.data.redis.connection.stream.ReadOffset; +import org.springframework.data.redis.connection.stream.Record; +import org.springframework.data.redis.connection.stream.RecordId; +import org.springframework.data.redis.connection.stream.StreamOffset; +import org.springframework.data.redis.connection.stream.StreamReadOptions; +import org.springframework.data.redis.connection.stream.StreamRecords; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StreamOperations; +import org.springframework.data.redis.hash.HashMapper; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.RedisUtil; + +/** + * 流助手 + * @author xsx + * @date 2019/6/25 + * @since 1.8 + */ +public final class StreamHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 对象模板 + */ + private StreamOperations streamOperations; + /** + * 数据库索引 + */ + private int dbIndex; + + /** + * 流助手构造 + * @param dbIndex 数据库索引 + */ + StreamHandler(Integer dbIndex) { + this.dbIndex = dbIndex; + this.redisTemplate = HandlerManager.createRedisTemplate(dbIndex); + this.streamOperations = this.redisTemplate.opsForStream(); + } + + /** + * 流助手构造 + * @param dbIndex 数据库索引 + * @param hashMapper 哈希映射 + */ + StreamHandler(Integer dbIndex, HashMapper hashMapper) { + this.dbIndex = dbIndex; + this.redisTemplate = HandlerManager.createRedisTemplate(dbIndex); + this.streamOperations = this.redisTemplate.opsForStream(hashMapper); + } + + /** + * 流助手构造 + * @param transactionHandler 事务助手 + */ + StreamHandler(TransactionHandler transactionHandler) { + this.dbIndex = transactionHandler.getDbIndex(); + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.streamOperations = this.redisTemplate.opsForStream(); + } + + /** + * 流助手构造 + * @param transactionHandler 事务助手 + * @param hashMapper 哈希映射 + */ + StreamHandler(TransactionHandler transactionHandler, HashMapper hashMapper) { + this.dbIndex = transactionHandler.getDbIndex(); + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.streamOperations = this.redisTemplate.opsForStream(hashMapper); + } + + /** + * 条目数量 + * @see Redis Documentation: XLEN + * @since redis 5.0.0 + * @param key 键 + * @return 返回条目数量 + */ + public Long size(String key) { + return this.streamOperations.size(key); + } + + /** + * 添加条目 + * @see Redis Documentation: XADD + * @since redis 5.0.0 + * @param key 键 + * @param value 元素字典 + * @return 返回 RecordId 对象 + */ + public RecordId add(String key, Map value) { + return this.streamOperations.add(key, value); + } + + /** + * 添加条目 + * @see Redis Documentation: XADD + * @since redis 5.0.0 + * @param key 键 + * @param value 元素 + * @return 返回 RecordId 对象 + */ + public RecordId add(String key, Object value) { + return this.streamOperations.add(StreamRecords.newRecord().in(key).ofObject(value)); + } + + /** + * 添加条目 + * @see Redis Documentation: XADD + * @since redis 5.0.0 + * @param record 条目 + * @return 返回 RecordId 对象 + */ + @SuppressWarnings("unchecked") + public RecordId add(Record record) { + return this.streamOperations.add(record); + } + + /** + * 裁剪条目(保留最新) + * @see Redis Documentation: XTRIM + * @since redis 5.0.0 + * @param key 键 + * @param count 保留数量 + * @return 返回被裁剪的数量 + */ + public Long trim(String key, long count) { + return this.streamOperations.trim(key, count); + } + + /** + * 移除条目 + * @see Redis Documentation: XDEL + * @since redis 5.0.0 + * @param key 键 + * @param recordIds 条目id列表 + * @return 返回被删除的数量 + */ + public Long remove(String key, String ...recordIds) { + return this.streamOperations.delete(key, recordIds); + } + + /** + * 创建消费者组 + * @see Redis Documentation: XGROUP CREATE + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + */ + public void createGroup(String key, String groupName) { + this.streamOperations.createGroup(key, groupName); + } + + /** + * 创建消费者组 + * @see Redis Documentation: XGROUP CREATE + * @since redis 5.0.0 + * @param key 键 + * @param readOffset 偏移量 + * @param groupName 消费者组名称 + */ + public void createGroup(String key, ReadOffset readOffset, String groupName) { + this.streamOperations.createGroup(key, readOffset, groupName); + } + + /** + * 移除消费者组 + * @see Redis Documentation: XGROUP DESTROY + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + * @return 返回布尔值,成功true,失败false + */ + public Boolean removeGroup(String key, String groupName) { + return this.streamOperations.destroyGroup(key, groupName); + } + + /** + * 移除消费者 + * @see Redis Documentation: XGROUP DELCONSUMER + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + * @param consumerName 消费者名称 + * @return 返回布尔值,成功true,失败false + */ + public Boolean removeConsumer(String key, String groupName, String consumerName) { + return this.streamOperations.deleteConsumer(key, Consumer.from(groupName, consumerName)); + } + + /** + * 确认条目 + * @see Redis Documentation: XACK + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + * @param recordIds 条目id列表 + * @return 返回成功确认的消息数 + */ + public Long ack(String key, String groupName, String... recordIds) { + return this.streamOperations.acknowledge(key, groupName, recordIds); + } + + /** + * 获取所有权 + * @param key 键 + * @param groupName 消费者组名称 + * @param consumerName 消费者名称 + * @param timeout 消息空闲时间 + * @param recordIds 条目id列表 + * @return 返回条目 + */ + public Object claim(String key, String groupName, String consumerName, long timeout, String... recordIds) { + return RedisUtil.getCustomCommandHandler(this.dbIndex).execute( + "XCLAIM", + ConvertUtil.toByteArray( + this.redisTemplate.getKeySerializer(), + recordIds, + key, + groupName, + consumerName, + String.valueOf(timeout) + ) + ); + } + + /** + * 待处理条目 + * @see Redis Documentation: XPENDING + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map pending(String key, String groupName) { + List list = (List) ConvertUtil.toJavaType( + this.redisTemplate.getKeySerializer(), + RedisUtil.getCustomCommandHandler(this.dbIndex).execute( + "XPENDING", + ConvertUtil.toByteArray(this.redisTemplate.getKeySerializer(), key, groupName) + ) + ); + Map data = new HashMap<>(4); + if (list==null) { + data.put("count", 0); + data.put("minId", null); + data.put("maxId", null); + data.put("consumers", new ArrayList<>(0)); + }else { + List dataList = (List) list.get(0); + data.put("count", dataList.get(0)); + data.put("minId", dataList.get(1)); + data.put("maxId", dataList.get(2)); + data.put("consumers", dataList.get(3)); + } + return data; + } + + /** + * 待处理条目 + * @see Redis Documentation: XPENDING + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + * @param count 返回数量 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public List> pending(String key, String groupName, int count) { + return this.toPendingResult( + (List) ConvertUtil.toJavaType( + this.redisTemplate.getKeySerializer(), + RedisUtil.getCustomCommandHandler(this.dbIndex).execute( + "XPENDING", + ConvertUtil.toByteArray( + this.redisTemplate.getKeySerializer(), + key, + groupName, + "-", + "+", + String.valueOf(count) + ) + ) + ) + ); + } + + /** + * 待处理条目 + * @see Redis Documentation: XPENDING + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名称 + * @param consumerName 消费者名称 + * @param count 返回数量 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public List> pending(String key, String groupName, String consumerName, int count) { + return this.toPendingResult( + (List) ConvertUtil.toJavaType( + this.redisTemplate.getKeySerializer(), + RedisUtil.getCustomCommandHandler(this.dbIndex).execute( + "XPENDING", + ConvertUtil.toByteArray( + this.redisTemplate.getKeySerializer(), + key, + groupName, + "-", + "+", + String.valueOf(count), + consumerName + ) + ) + ) + ); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param keys 键 + * @return 返回条目字典 + */ + public Map readEarliest(String... keys) { + return this.readEarliest(StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map readEarliest(Class resultType, String... keys) { + return this.readEarliest(resultType, StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param readOptions 读取选项 + * @param keys 键 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readEarliest(StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + readOptions.count(1), + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.EARLIEST + ); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param readOptions 读取选项 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readEarliest(Class resultType, StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + resultType, + readOptions.count(1), + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.EARLIEST + ); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param keys 键 + * @return 返回条目字典 + */ + public Map readLatest(String... keys) { + return this.readLatest(StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map readLatest(Class resultType, String... keys) { + return this.readLatest(resultType, StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param readOptions 读取选项 + * @param keys 键 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readLatest(StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + readOptions, + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.LATEST + ); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param readOptions 读取选项 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readLatest(Class resultType, StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + resultType, + readOptions, + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.LATEST + ); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param key 键 + * @param recordIds 条目id列表 + * @return 返回条目字典 + */ + public Map read(String key, String... recordIds) { + return this.read(StreamReadOptions.empty(), key, recordIds); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param recordIds 条目id列表 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map read(Class resultType, String key, String... recordIds) { + return this.read(resultType, StreamReadOptions.empty(), key, recordIds); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param readOptions 读取选项 + * @param key 键 + * @param recordIds 条目id列表 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map read(StreamReadOptions readOptions, String key, String... recordIds) { + return ConvertUtil.toMap( + this.streamOperations.read( + readOptions, + this.createStreamOffsetByRecordIds(key, recordIds) + ), + StreamDataType.ALL + ); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param readOptions 读取选项 + * @param key 键 + * @param recordIds 条目id列表 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map read(Class resultType, StreamReadOptions readOptions, String key, String... recordIds) { + return ConvertUtil.toMap( + this.streamOperations.read( + resultType, + readOptions, + this.createStreamOffsetByRecordIds(key, recordIds) + ), + StreamDataType.ALL + ); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param keyRecordIdMap 键与条目id字典 + * @return 返回条目字典 + */ + public Map read(Map keyRecordIdMap) { + return this.read(StreamReadOptions.empty(), keyRecordIdMap); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param keyRecordIdMap 键与条目id字典 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map read(Class resultType, Map keyRecordIdMap) { + return this.read(resultType, StreamReadOptions.empty(), keyRecordIdMap); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param readOptions 读取选项 + * @param keyRecordIdMap 键与条目id字典 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map read(StreamReadOptions readOptions, Map keyRecordIdMap) { + return ConvertUtil.toMap( + this.streamOperations.read( + readOptions, + this.createStreamOffset(keyRecordIdMap) + ), + StreamDataType.ALL + ); + } + + /** + * 读取条目 + * @see Redis Documentation: XREAD + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param readOptions 读取选项 + * @param keyRecordIdMap 键与条目id字典 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map read(Class resultType, StreamReadOptions readOptions, Map keyRecordIdMap) { + return ConvertUtil.toMap( + this.streamOperations.read( + resultType, + readOptions, + this.createStreamOffset(keyRecordIdMap) + ), + StreamDataType.ALL + ); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param keys 键 + * @return 返回条目字典 + */ + public Map readEarliestByConsumer(Consumer consumer, String... keys) { + return this.readEarliestByConsumer(consumer, StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map readEarliestByConsumer(Class resultType, Consumer consumer, String... keys) { + return this.readEarliestByConsumer(resultType, consumer, StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param readOptions 读取选项 + * @param keys 键 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readEarliestByConsumer(Consumer consumer, StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + consumer, + readOptions.count(1), + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.EARLIEST + ); + } + + /** + * 读取条目(最早) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param readOptions 读取选项 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readEarliestByConsumer(Class resultType, Consumer consumer, StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + resultType, + consumer, + readOptions.count(1), + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.EARLIEST + ); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param keys 键 + * @return 返回条目字典 + */ + public Map readLatestByConsumer(Consumer consumer, String... keys) { + return this.readLatestByConsumer(consumer, StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map readLatestByConsumer(Class resultType, Consumer consumer, String... keys) { + return this.readLatestByConsumer(resultType, consumer, StreamReadOptions.empty(), keys); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param readOptions 读取选项 + * @param keys 键 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readLatestByConsumer(Consumer consumer, StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + consumer, + readOptions, + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.LATEST + ); + } + + /** + * 读取条目(最新) + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param readOptions 读取选项 + * @param keys 键 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readLatestByConsumer(Class resultType, Consumer consumer, StreamReadOptions readOptions, String... keys) { + return ConvertUtil.toMap( + this.streamOperations.read( + resultType, + consumer, + readOptions, + this.createStreamOffsetByKeys(keys) + ), + StreamDataType.LATEST + ); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param key 键 + * @param recordIds 条目id列表 + * @return 返回条目字典 + */ + public Map readByConsumer(Consumer consumer, String key, String... recordIds) { + return this.readByConsumer(consumer, StreamReadOptions.empty(), key, recordIds); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param key 键 + * @param recordIds 条目id列表 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map readByConsumer(Class resultType, Consumer consumer, String key, String... recordIds) { + return this.readByConsumer(resultType, consumer, StreamReadOptions.empty(), key, recordIds); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param readOptions 读取选项 + * @param key 键 + * @param recordIds 条目id列表 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readByConsumer(Consumer consumer, StreamReadOptions readOptions, String key, String... recordIds) { + return ConvertUtil.toMap(this.streamOperations.read(consumer, readOptions, this.createStreamOffsetByRecordIds(key, recordIds)), StreamDataType.ALL); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param readOptions 读取选项 + * @param key 键 + * @param recordIds 条目id列表 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readByConsumer(Class resultType, Consumer consumer, StreamReadOptions readOptions, String key, String... recordIds) { + return ConvertUtil.toMap(this.streamOperations.read(resultType, consumer, readOptions, this.createStreamOffsetByRecordIds(key, recordIds)), StreamDataType.ALL); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param keyRecordIdMap 键与条目id字典 + * @return 返回条目字典 + */ + public Map readByConsumer(Consumer consumer, Map keyRecordIdMap) { + return this.readByConsumer(consumer, StreamReadOptions.empty(), keyRecordIdMap); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param keyRecordIdMap 键与条目id字典 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map readByConsumer(Class resultType, Consumer consumer, Map keyRecordIdMap) { + return this.readByConsumer(resultType, consumer, StreamReadOptions.empty(), keyRecordIdMap); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param consumer 消费者对象 + * @param keyRecordIdMap 键与条目id字典 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readByConsumer(Consumer consumer, StreamReadOptions readOptions, Map keyRecordIdMap) { + return ConvertUtil.toMap(this.streamOperations.read(consumer, readOptions, this.createStreamOffset(keyRecordIdMap)), StreamDataType.ALL); + } + + /** + * 读取条目 + * @see Redis Documentation: XREADGROUP + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param consumer 消费者对象 + * @param keyRecordIdMap 键与条目id字典 + * @param 返回类型 + * @return 返回条目字典 + */ + @SuppressWarnings("unchecked") + public Map readByConsumer(Class resultType, Consumer consumer, StreamReadOptions readOptions, Map keyRecordIdMap) { + return ConvertUtil.toMap(this.streamOperations.read(resultType, consumer, readOptions, this.createStreamOffset(keyRecordIdMap)), StreamDataType.ALL); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param key 键 + * @param recordId 条目id + * @return 返回条目字典 + */ + public Map get(String key, String recordId) { + return this.range(key, recordId, recordId).get(recordId); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param recordId 条目id + * @param 返回类型 + * @return 返回条目字典 + */ + public T get(Class resultType, String key, String recordId) { + return this.range(resultType, key, recordId, recordId).get(recordId); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param key 键 + * @return 返回条目字典 + */ + public Map> range(String key) { + return this.range(key, "-", "+"); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map range(Class resultType, String key) { + return this.range(resultType, key, "-", "+"); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param key 键 + * @param count 返回数量 + * @return 返回条目字典 + */ + public Map> range(String key, int count) { + return this.range(key, "-", "+", count); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param count 返回数量 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map range(Class resultType, String key, int count) { + return this.range(resultType, key, "-", "+", count); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param key 键 + * @param minRecordId 最小条目id + * @param maxRecordId 最大条目id + * @return 返回条目字典 + */ + public Map> range(String key, String minRecordId, String maxRecordId) { + return ConvertUtil.toMap( + this.streamOperations.range( + key, + Range.of(Range.Bound.inclusive(minRecordId), Range.Bound.inclusive(maxRecordId)) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param minRecordId 最小条目id + * @param maxRecordId 最大条目id + * @param 返回类型 + * @return 返回条目字典 + */ + public Map range(Class resultType, String key, String minRecordId, String maxRecordId) { + return ConvertUtil.toMap( + this.streamOperations.range( + resultType, + key, + Range.of(Range.Bound.inclusive(minRecordId), Range.Bound.inclusive(maxRecordId)) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param key 键 + * @param minRecordId 最小条目id + * @param maxRecordId 最大条目id + * @param count 返回数量 + * @return 返回条目字典 + */ + public Map> range(String key, String minRecordId, String maxRecordId, int count) { + return ConvertUtil.toMap( + this.streamOperations.range( + key, + Range.of(Range.Bound.inclusive(minRecordId), Range.Bound.inclusive(maxRecordId)), + RedisZSetCommands.Limit.limit().count(count) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目 + * @see Redis Documentation: XRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param minRecordId 最小条目id + * @param maxRecordId 最大条目id + * @param count 返回数量 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map range(Class resultType, String key, String minRecordId, String maxRecordId, int count) { + return ConvertUtil.toMap( + this.streamOperations.range( + resultType, + key, + Range.of(Range.Bound.inclusive(minRecordId), Range.Bound.inclusive(maxRecordId)), + RedisZSetCommands.Limit.limit().count(count) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param key 键 + * @return 返回条目字典 + */ + public Map> reverseRange(String key) { + return this.reverseRange(key, "-", "+"); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map reverseRange(Class resultType, String key) { + return this.reverseRange(resultType, key, "-", "+"); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param key 键 + * @param count 返回数量 + * @return 返回条目字典 + */ + public Map> reverseRange(String key, int count) { + return this.reverseRange(key, "-", "+", count); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param count 返回数量 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map reverseRange(Class resultType, String key, int count) { + return this.reverseRange(resultType, key, "-", "+", count); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param key 键 + * @param maxRecordId 最大条目id + * @param minRecordId 最小条目id + * @return 返回条目字典 + */ + public Map> reverseRange(String key, String maxRecordId, String minRecordId) { + return ConvertUtil.toMap( + this.streamOperations.reverseRange( + key, + Range.of(Range.Bound.inclusive(maxRecordId), Range.Bound.inclusive(minRecordId)) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param maxRecordId 最大条目id + * @param minRecordId 最小条目id + * @param 返回类型 + * @return 返回条目字典 + */ + public Map reverseRange(Class resultType, String key, String maxRecordId, String minRecordId) { + return ConvertUtil.toMap( + this.streamOperations.reverseRange( + resultType, + key, + Range.of(Range.Bound.inclusive(maxRecordId), Range.Bound.inclusive(minRecordId)) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param key 键 + * @param maxRecordId 最大条目id + * @param minRecordId 最小条目id + * @param count 返回数量 + * @return 返回条目字典 + */ + public Map> reverseRange(String key, String maxRecordId, String minRecordId, int count) { + return ConvertUtil.toMap( + this.streamOperations.reverseRange( + key, + Range.of(Range.Bound.inclusive(maxRecordId), Range.Bound.inclusive(minRecordId)), + RedisZSetCommands.Limit.limit().count(count) + ), + StreamDataType.ALL + ); + } + + /** + * 获取条目(反向) + * @see Redis Documentation: XREVRANGE + * @since redis 5.0.0 + * @param resultType 返回类型 + * @param key 键 + * @param maxRecordId 最大条目id + * @param minRecordId 最小条目id + * @param count 返回数量 + * @param 返回类型 + * @return 返回条目字典 + */ + public Map reverseRange(Class resultType, String key, String maxRecordId, String minRecordId, int count) { + return ConvertUtil.toMap( + this.streamOperations.reverseRange( + resultType, + key, + Range.of(Range.Bound.inclusive(maxRecordId), Range.Bound.inclusive(minRecordId)), + RedisZSetCommands.Limit.limit().count(count) + ), + StreamDataType.ALL + ); + } + + /** + * 流信息(客户端暂不支持) + * @see Redis Documentation: XINFO STREAM + * @since redis 5.0.0 + * @param key 键 + * @return 返回流信息 + */ + private Object streamInfo(String key) { + CustomCommandHandler customCommandHandler = RedisUtil.getCustomCommandHandler(this.dbIndex); + return RedisUtil.getCustomCommandHandler(this.dbIndex).execute( + "XINFO", + customCommandHandler.serialize("STREAM"), + customCommandHandler.serialize(key) + ); + } + + /** + * 消费者组信息(客户端暂不支持) + * @see Redis Documentation: XINFO GROUPS + * @since redis 5.0.0 + * @param key 键 + * @return 组信息 + */ + private Object groupInfo(String key) { + CustomCommandHandler customCommandHandler = RedisUtil.getCustomCommandHandler(this.dbIndex); + return customCommandHandler.execute( + "XINFO", + customCommandHandler.serialize("GROUPS"), + customCommandHandler.serialize(key) + ); + } + + /** + * 消费者信息(客户端暂不支持) + * @see Redis Documentation: XINFO CONSUMERS + * @since redis 5.0.0 + * @param key 键 + * @param groupName 消费者组名 + * @return 消费者信息 + */ + private Object consumerInfo(String key, String groupName) { + CustomCommandHandler customCommandHandler = RedisUtil.getCustomCommandHandler(this.dbIndex); + return customCommandHandler.execute( + "XINFO", + customCommandHandler.serialize("CONSUMERS"), + customCommandHandler.serialize(key), + customCommandHandler.serialize(groupName) + ); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 创建流偏移对象 + * @param keyRecordIdMap 键与条目id字典 + * @return 返回流偏移对象数组 + */ + private StreamOffset[] createStreamOffset(Map keyRecordIdMap) { + StreamOffset[] streamOffsets = new StreamOffset[keyRecordIdMap.size()]; + int i = 0; + for (Map.Entry entry : keyRecordIdMap.entrySet()) { + streamOffsets[i] = StreamOffset.create(entry.getKey(), ReadOffset.from(entry.getValue())); + i++; + } + return streamOffsets; + } + + /** + * 创建流偏移对象 + * @param key 键 + * @param recordIds 条目id + * @return 返回流偏移对象数组 + */ + private StreamOffset[] createStreamOffsetByRecordIds(String key, String... recordIds) { + int len = recordIds.length; + StreamOffset[] streamOffsets = new StreamOffset[len]; + for (int i = 0; i < len; i++) { + streamOffsets[i] = StreamOffset.create(key, ReadOffset.from(recordIds[i])); + } + return streamOffsets; + } + + /** + * 创建流偏移对象 + * @param keys 键 + * @return 返回流偏移对象数组 + */ + private StreamOffset[] createStreamOffsetByKeys(String... keys) { + int len = keys.length; + StreamOffset[] streamOffsets = new StreamOffset[len]; + for (int i = 0; i < len; i++) { + streamOffsets[i] = StreamOffset.fromStart(keys[i]); + } + return streamOffsets; + } + + /** + * 转换待处理条目结果 + * @param list 条目列表 + * @return 返回待处理条目结果列表 + */ + @SuppressWarnings("unchecked") + private List> toPendingResult(List list) { + List> dataList; + Map data; + if (list==null) { + dataList = new ArrayList<>(1); + data = new HashMap<>(4); + data.put("recordId", null); + data.put("consumer", null); + data.put("time", null); + data.put("count", 0); + dataList.add(data); + }else { + List oList = (List) list.get(0); + dataList = new ArrayList<>(oList.size()); + List $dataList; + for (Object o : oList) { + $dataList = (List) o; + data = new HashMap<>(4); + data.put("recordId", $dataList.get(0)); + data.put("consumer", $dataList.get(1)); + data.put("time", $dataList.get(2)); + data.put("count", $dataList.get(3)); + dataList.add(data); + } + } + return dataList; + } + + /** + * 流数据类型 + */ + public enum StreamDataType { + /** + * 全部 + */ + ALL, + /** + * 最新 + */ + LATEST, + /** + * 最早 + */ + EARLIEST + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StringHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StringHandler.java new file mode 100644 index 0000000..a4f548b --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/StringHandler.java @@ -0,0 +1,364 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; + +/** + * 字符串助手 + * @author xsx + * @date 2019/4/8 + * @since 1.8 + */ +public final class StringHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private ValueOperations operations; + /** + * 字符串模板 + */ + private ValueOperations stringOperations; + + /** + * 字符串助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + StringHandler(Integer dbIndex) { + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.operations = redisTemplate.opsForValue(); + this.stringOperations = stringRedisTemplate.opsForValue(); + } + + /** + * 字符串助手构造 + * @param transactionHandler 事务助手 + */ + StringHandler(TransactionHandler transactionHandler) { + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.operations = this.redisTemplate.opsForValue(); + this.stringOperations = this.stringRedisTemplate.opsForValue(); + } + + /** + * 移除对象 + * @see Redis Documentation: DEL + * @since redis 1.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long removeAsObj(String ...keys) { + return this.operations.getOperations().delete(Arrays.asList(keys)); + } + + /** + * 移除字符串 + * @see Redis Documentation: DEL + * @since redis 1.0.0 + * @param keys 键 + * @return 返回移除数量 + */ + public Long remove(String ...keys) { + return this.stringOperations.getOperations().delete(Arrays.asList(keys)); + } + + /** + * 设置对象 + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param value 对象 + */ + public void setAsObj(String key, Object value) { + this.operations.set(key, value); + } + + /** + * 设置字符串 + * @see Redis Documentation: SET + * @since redis 2.0.0 + * @param key 键 + * @param value 字符串 + */ + public void set(String key, String value) { + this.stringOperations.set(key, value); + } + + /** + * 设置对象(若存在则更新过期时间) + * @see Redis Documentation: SETEX + * @since redis 2.0.0 + * @param key 键 + * @param value 对象 + * @param timeout 过期时间 + * @param unit 时间单位 + */ + public void setAsObj(String key, Object value, long timeout, TimeUnit unit) { + this.operations.set(key, value, timeout, unit); + } + + /** + * 设置字符串(若存在则更新过期时间) + * @see Redis Documentation: SETEX + * @since redis 2.0.0 + * @param key 键 + * @param value 字符串 + * @param timeout 过期时间 + * @param unit 时间单位 + */ + public void set(String key, String value, long timeout, TimeUnit unit) { + this.stringOperations.set(key, value, timeout, unit); + } + + /** + * 批量设置对象 + * @see Redis Documentation: MSET + * @since redis 1.0.1 + * @param map 对象集合 + */ + public void msetAsObj(Map map) { + this.operations.multiSet(map); + } + + /** + * 批量设置字符串 + * @see Redis Documentation: MSET + * @since redis 1.0.1 + * @param map 字符串集合 + */ + public void mset(Map map) { + this.stringOperations.multiSet(map); + } + + /** + * 追加新字符串 + * @see Redis Documentation: APPEND + * @since redis 2.0.0 + * @param key 键 + * @param value 字符串 + */ + public void append(String key, String value) { + this.stringOperations.append(key, value); + } + + /** + * 设置对象如果不存在 + * @see Redis Documentation: SETNX + * @since redis 2.6.12 + * @param key 键 + * @param value 对象 + * @param timeout 过期时间 + * @param unit 时间单位 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setIfAbsentAsObj(String key, Object value, long timeout, TimeUnit unit) { + return this.operations.setIfAbsent(key, value, timeout, unit); + } + + /** + * 设置字符串如果不存在 + * @see Redis Documentation: SETNX + * @since redis 2.6.12 + * @param key 键 + * @param value 字符串 + * @param timeout 过期时间 + * @param unit 时间单位 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) { + return this.stringOperations.setIfAbsent(key, value, timeout, unit); + } + + /** + * 设置对象如果不存在 + * @see Redis Documentation: SETNX + * @since redis 1.0.0 + * @param key 键 + * @param value 对象 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setIfAbsentAsObj(String key, Object value) { + return this.operations.setIfAbsent(key, value); + } + + /** + * 设置字符串如果不存在 + * @see Redis Documentation: SETNX + * @since redis 1.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回布尔值,成功true,失败false + */ + public Boolean setIfAbsent(String key, String value) { + return this.stringOperations.setIfAbsent(key, value); + } + + /** + * 批量设置对象如果不存在 + * @see Redis Documentation: MSETNX + * @since redis 1.0.1 + * @param map 对象集合 + * @return 返回布尔值,成功true,失败false + */ + public Boolean msetIfAbsentAsObj(Map map) { + return this.operations.multiSetIfAbsent(map); + } + + /** + * 批量设置字符串如果不存在 + * @see Redis Documentation: MSETNX + * @since redis 1.0.1 + * @param map 字符串集合 + * @return 返回布尔值,成功true,失败false + */ + public Boolean msetIfAbsent(Map map) { + return this.stringOperations.multiSetIfAbsent(map); + } + + /** + * 获取对象 + * @see Redis Documentation: GET + * @since redis 1.0.0 + * @param key 键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T getAsObj(String key) { + return (T) ConvertUtil.toJavaType(this.operations.get(key), Object.class); + } + + /** + * 获取对象 + * @see Redis Documentation: GET + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T getAsObj(Class type, String key) { + return (T) ConvertUtil.toJavaType(this.operations.get(key), type); + } + + /** + * 获取字符串 + * @see Redis Documentation: GET + * @since redis 1.0.0 + * @param key 键 + * @return 返回字符串 + */ + public String get(String key) { + return this.stringOperations.get(key); + } + + /** + * 获取并设置新对象 + * @see Redis Documentation: GETSET + * @since redis 1.0.0 + * @param key 键 + * @param value 对象 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T getAndSetAsObj(String key, Object value) { + return (T) ConvertUtil.toJavaType(this.operations.getAndSet(key, value), Object.class); + } + + /** + * 获取并设置新对象 + * @see Redis Documentation: GETSET + * @since redis 1.0.0 + * @param type 返回值类型 + * @param key 键 + * @param value 对象 + * @param 返回类型 + * @return 返回对象 + */ + @SuppressWarnings("unchecked") + public T getAndSetAsObj(Class type, String key, Object value) { + return (T) ConvertUtil.toJavaType(this.operations.getAndSet(key, value), type); + } + + /** + * 获取并设置新字符串 + * @see Redis Documentation: GETSET + * @since redis 1.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回字符串 + */ + public String getAndSet(String key, String value) { + return this.stringOperations.getAndSet(key, value); + } + + /** + * 批量获取对象 + * @see Redis Documentation: MGET + * @since redis 1.0.0 + * @param keys 键 + * @return 返回对象列表 + */ + public List mgetAsObj(String ...keys) { + return this.operations.multiGet(Arrays.asList(keys)); + } + + /** + * 批量获取字符串 + * @see Redis Documentation: MGET + * @since redis 1.0.0 + * @param keys 键 + * @return 返回字符串列表 + */ + public List mget(String ...keys) { + return this.stringOperations.multiGet(Arrays.asList(keys)); + } + + /** + * 获取字符串的长度 + * @see Redis Documentation: STRLEN + * @since redis 2.2.0 + * @param key 键 + * @return 返回字符串长度 + */ + public Long length(String key) { + return this.stringOperations.size(key); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/TransactionHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/TransactionHandler.java new file mode 100644 index 0000000..d86a3b8 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/TransactionHandler.java @@ -0,0 +1,345 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisConnectionUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.hash.HashMapper; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +/** + * 事务助手 + * @author xsx + * @date 2019/7/17 + * @since 1.8 + */ +public final class TransactionHandler implements RedisHandler{ + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 数据库索引 + */ + private int dbIndex; + + /** + * 事务助手构造 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + TransactionHandler(Integer dbIndex) { + this.dbIndex = dbIndex; + List templateList = HandlerManager.createTemplate(this.dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + } + + /** + * 执行对象事务 + * @param executor 执行器 + * @return 返回结果列表 + */ + public List executeAsObj(Function executor) { + return this.execute(executor, this.redisTemplate); + } + + /** + * 执行字符串事务 + * @param executor 执行器 + * @return 返回结果列表 + */ + public List execute(Function executor) { + return this.execute(executor, this.stringRedisTemplate); + } + + /** + * 监控对象键 + * @see Redis Documentation: WATCH + * @since redis 2.2.0 + * @param keys 键 + */ + public void watchAsObj(String ...keys) { + this.redisTemplate.watch(Arrays.asList(keys)); + } + + /** + * 监控字符串键 + * @see Redis Documentation: WATCH + * @since redis 2.2.0 + * @param keys 键 + */ + public void watch(String ...keys) { + this.stringRedisTemplate.watch(Arrays.asList(keys)); + } + + /** + * 取消监控对象键 + * @see Redis Documentation: UNWATCH + * @since redis 2.2.0 + */ + public void unwatchAsObj() { + this.redisTemplate.unwatch(); + } + + /** + * 取消监控字符串键 + * @see Redis Documentation: UNWATCH + * @since redis 2.2.0 + */ + public void unwatch() { + this.stringRedisTemplate.unwatch(); + } + + /** + * 开始对象事务 + * @since redis 1.2.0 + * @see Redis Documentation: MULTI + */ + public void beginTransactionAsObj() { + this.redisTemplate.multi(); + } + + /** + * 开始字符串事务 + * @since redis 1.2.0 + * @see Redis Documentation: MULTI + */ + public void beginTransaction() { + this.stringRedisTemplate.multi(); + } + + /** + * 提交对象事务 + * @since redis 1.2.0 + * @see Redis Documentation: EXEC + * @return 返回执行命令列表 + */ + public List commitAsObj() { + return this.redisTemplate.exec(); + } + + /** + * 提交字符串事务 + * @since redis 1.2.0 + * @see Redis Documentation: EXEC + * @return 返回执行命令列表 + */ + public List commit() { + return this.stringRedisTemplate.exec(); + } + + /** + * 取消对象事务 + * @see Redis Documentation: DISCARD + * @since redis 2.0.0 + */ + public void cancelTransactionAsObj() { + this.redisTemplate.discard(); + } + + /** + * 取消字符串事务 + * @see Redis Documentation: DISCARD + * @since redis 2.0.0 + */ + public void cancelTransaction() { + this.stringRedisTemplate.discard(); + } + + /** + * 获取数据库助手 + * @return 返回数据库助手 + */ + public DBHandler getDBHandler() { + return new DBHandler(this); + } + + /** + * 获取键助手 + * @return 返回键助手 + */ + public KeyHandler getKeyHandler() { + return new KeyHandler(this); + } + + /** + * 获取数字助手 + * @return 返回数字助手 + */ + public NumberHandler getNumberHandler() { + return new NumberHandler(this); + } + + /** + * 获取字符串助手 + * @return 返回字符串助手 + */ + public StringHandler getStringHandler() { + return new StringHandler(this); + } + + /** + * 获取哈希助手 + * @return 返回哈希助手 + */ + public HashHandler getHashHandler() { + return new HashHandler(this); + } + + /** + * 获取列表助手 + * @return 返回列表助手 + */ + public ListHandler getListHandler() { + return new ListHandler(this); + } + + /** + * 获取无序集合助手 + * @return 返回无序集合助手 + */ + public SetHandler getSetHandler() { + return new SetHandler(this); + } + + /** + * 获取有序集合助手 + * @return 返回有序集合助手 + */ + public ZsetHandler getZsetHandler() { + return new ZsetHandler(this); + } + + /** + * 获取基数助手 + * @return 返回基数助手 + */ + public HyperLogLogHandler getHyperLogLogHandler() { + return new HyperLogLogHandler(this); + } + + /** + * 获取位图助手 + * @return 返回位图助手 + */ + public BitmapHandler getBitmapHandler() { + return new BitmapHandler(this); + } + + /** + * 获取地理位置助手 + * @return 返回地理位置助手 + */ + public GeoHandler getGeoHandler() { + return new GeoHandler(this); + } + + /** + * 获取lua脚本助手 + * @return 返回lua脚本助手 + */ + public ScriptHandler getScriptHandler() { + return new ScriptHandler(this); + } + + /** + * 获取发布订阅助手 + * @return 返回发布订阅助手 + */ + public PubSubHandler getPubSubHandler() { + return new PubSubHandler(this); + } + + /** + * 获取流助手 + * @return 返回流助手 + */ + public StreamHandler getStreamHandler() { + return new StreamHandler(this); + } + + /** + * 获取流助手 + * @param hashMapper 哈希映射 + * @return 返回流助手 + */ + public StreamHandler getStreamHandler(HashMapper hashMapper) { + return new StreamHandler(this, hashMapper); + } + + /** + * 获取哨兵助手 + * @return 返回哨兵助手 + */ + public SentinelHandler getSentinelHandler() { + return new SentinelHandler(this); + } + + /** + * 获取集群助手 + * @return 返回集群助手 + */ + public ClusterHandler getClusterHandler() { + return new ClusterHandler(this); + } + + /** + * 获取自定义命令助手 + * @return 返回自定义命令助手 + */ + public CustomCommandHandler getCustomCommandHandler() { + return new CustomCommandHandler(this); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } + + /** + * 获取数据库索引 + * @return 返回数据库索引 + */ + public int getDbIndex() { + return this.dbIndex; + } + + /** + * 执行事务 + * @param executor 执行器 + * @param redisTemplate redis模板 + * @return 返回结果列表 + */ + private List execute(Function executor, RedisTemplate redisTemplate) { + RedisConnectionFactory factory = redisTemplate.getRequiredConnectionFactory(); + // 绑定连接 + RedisConnectionUtils.bindConnection(factory, true); + try { + return executor.apply(this); + } finally { + // 解绑连接 + RedisConnectionUtils.unbindConnection(factory); + } + } +} + + diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ZsetHandler.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ZsetHandler.java new file mode 100644 index 0000000..9703585 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/handler/ZsetHandler.java @@ -0,0 +1,1398 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.handler; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.springframework.data.redis.connection.RedisZSetCommands; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ZSetOperations; +import org.springframework.data.redis.serializer.RedisSerializer; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.ConvertUtil; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.util.RedisUtil; + +/** + * 有序集合助手 + * @author xsx + * @date 2019/4/15 + * @since 1.8 + */ +public final class ZsetHandler implements RedisHandler { + /** + * 对象模板 + */ + private RedisTemplate redisTemplate; + /** + * 字符串模板 + */ + private StringRedisTemplate stringRedisTemplate; + /** + * 对象模板 + */ + private ZSetOperations zSetOperations; + /** + * 字符串模板 + */ + private ZSetOperations stringZSetOperations; + /** + * 数据库索引 + */ + private int dbIndex; + + /** + * 有序集合助手 + * @param dbIndex 数据库索引 + */ + @SuppressWarnings("unchecked") + ZsetHandler(Integer dbIndex) { + this.dbIndex = dbIndex; + List templateList = HandlerManager.createTemplate(dbIndex); + this.redisTemplate = templateList.get(0); + this.stringRedisTemplate = (StringRedisTemplate) templateList.get(1); + this.zSetOperations = redisTemplate.opsForZSet(); + this.stringZSetOperations = stringRedisTemplate.opsForZSet(); + } + + /** + * 有序集合助手 + * @param transactionHandler 事务助手 + */ + ZsetHandler(TransactionHandler transactionHandler) { + this.dbIndex = transactionHandler.getDbIndex(); + this.redisTemplate = transactionHandler.getRedisTemplate(); + this.stringRedisTemplate = transactionHandler.getStringRedisTemplate(); + this.zSetOperations = this.redisTemplate.opsForZSet(); + this.stringZSetOperations = this.stringRedisTemplate.opsForZSet(); + } + + /** + * 新增对象 + * @see Redis Documentation: ZADD + * @since redis 1.2.0 + * @param key 键 + * @param value 对象 + * @param score 排序 + * @return 返回布尔值,成功true,失败false + */ + public Boolean addAsObj(String key, Object value, double score) { + return this.zSetOperations.add(key, value, score); + } + + /** + * 新增字符串 + * @see Redis Documentation: ZADD + * @since redis 1.2.0 + * @param key 键 + * @param value 字符串 + * @param score 排序 + * @return 返回布尔值,成功true,失败false + */ + public Boolean add(String key, String value, double score) { + return this.stringZSetOperations.add(key, value, score); + } + + /** + * 新增对象存在则更新 + * @see Redis Documentation: ZADD + * @since redis 1.2.0 + * @param key 键 + * @param map 对象字典 + * @return 返回成功个数 + */ + public Long addAsObj(String key, Map map) { + return this.zSetOperations.add(key, ConvertUtil.toTypedTupleSet(map)); + } + + /** + * 新增字符串存在则更新 + * @see Redis Documentation: ZADD + * @since redis 1.2.0 + * @param key 键 + * @param map 字符串字典 + * @return 返回成功个数 + */ + public Long add(String key, Map map) { + return this.stringZSetOperations.add(key, ConvertUtil.toTypedTupleSet(map)); + } + + /** + * 新增对象存在则更新 + * @see Redis Documentation: ZADD + * @since redis 1.2.0 + * @param key 键 + * @param values 对象 + * @return 返回成功个数 + */ + public Long addAsObj(String key, Object ...values) { + return this.addAsObj(key, ConvertUtil.toMap(values)); + } + + /** + * 新增字符串存在则更新 + * @see Redis Documentation: ZADD + * @since redis 1.2.0 + * @param key 键 + * @param values 字符串 + * @return 返回成功个数 + */ + public Long add(String key, String ...values) { + return this.add(key, ConvertUtil.toMap(values)); + } + + /** + * 获取对象数量 + * @see Redis Documentation: ZCARD + * @since redis 1.2.0 + * @param key 键 + * @return 返回对象数量 + */ + public Long sizeAsObj(String key) { + return this.zSetOperations.zCard(key); + } + + /** + * 获取字符串数量 + * @see Redis Documentation: ZCARD + * @since redis 1.2.0 + * @param key 键 + * @return 返回字符串数量 + */ + public Long size(String key) { + return this.stringZSetOperations.zCard(key); + } + + /** + * 获取最小-最大之间分数的对象数量 + * @see Redis Documentation: ZCOUNT + * @since redis 1.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回对象数量 + */ + public Long countAsObj(String key, Double min, Double max) { + return this.zSetOperations.count(key, min, max); + } + + /** + * 获取最小-最大之间分数的字符串数量 + * @see Redis Documentation: ZCOUNT + * @since redis 1.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回字符串数量 + */ + public Long count(String key, Double min, Double max) { + return this.stringZSetOperations.count(key, min, max); + } + + /** + * 正序获取范围内的对象 + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startIndex 开始索引 + * @param endIndex 结束索引 + * @return 返回对象集合 + */ + public Set ascRangeAsObj(String key, Long startIndex, Long endIndex) { + return this.zSetOperations.range(key, startIndex, endIndex); + } + + /** + * 正序获取范围内的字符串 + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startIndex 开始索引 + * @param endIndex 结束索引 + * @return 返回字符串集合 + */ + public Set ascRange(String key, Long startIndex, Long endIndex) { + return this.stringZSetOperations.range(key, startIndex, endIndex); + } + + /** + * 倒序获取范围内的对象 + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回对象集合 + */ + public Set descRangeAsObj(String key, Long startSortIndex, Long endSortIndex) { + return this.ascRangeAsObj(key, -endSortIndex-1, startSortIndex-1); + } + + /** + * 倒序获取范围内的字符串 + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回字符串集合 + */ + public Set descRange(String key, Long startSortIndex, Long endSortIndex) { + return this.ascRange(key, -endSortIndex-1, -startSortIndex-1); + } + + /** + * 正序获取范围内的对象 + * @see Redis Documentation: ZRANGEBYLEX + * @since redis 2.8.9 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param isContainsStart 是否包含起始 + * @param endSortIndex 结束排序索引 + * @param isContainsEnd 是否包含结束 + * @return 返回对象集合 + */ + public Set ascRangeByLexAsObj(String key, Long startSortIndex, boolean isContainsStart, Long endSortIndex, boolean isContainsEnd) { + return this.zSetOperations.rangeByLex( + key, + this.getRange(startSortIndex, isContainsStart, endSortIndex, isContainsEnd) + ); + } + + /** + * 正序获取范围内的字符串 + * @see Redis Documentation: ZRANGEBYLEX + * @since redis 2.8.9 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param isContainsStart 是否包含起始 + * @param endSortIndex 结束排序索引 + * @param isContainsEnd 是否包含结束 + * @return 返回字符串集合 + */ + public Set ascRangeByLex(String key, Long startSortIndex, boolean isContainsStart, Long endSortIndex, boolean isContainsEnd) { + return this.stringZSetOperations.rangeByLex( + key, + this.getRange(startSortIndex, isContainsStart, endSortIndex, isContainsEnd) + ); + } + + /** + * 正序获取范围内的对象 + * @see Redis Documentation: ZRANGEBYLEX + * @since redis 2.8.9 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param isContainsStart 是否包含起始 + * @param endSortIndex 结束排序索引 + * @param isContainsEnd 是否包含结束 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回对象集合 + */ + public Set ascRangeByLexAsObj(String key, Long startSortIndex, boolean isContainsStart, Long endSortIndex, boolean isContainsEnd, Integer count, Integer offset) { + return this.zSetOperations.rangeByLex( + key, + this.getRange(startSortIndex, isContainsStart, endSortIndex, isContainsEnd), + RedisZSetCommands.Limit.limit().count(count).offset(offset) + ); + } + + /** + * 正序获取范围内的字符串 + * @see Redis Documentation: ZRANGEBYLEX + * @since redis 2.8.9 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param isContainsStart 是否包含起始 + * @param endSortIndex 结束排序索引 + * @param isContainsEnd 是否包含结束 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回字符串集合 + */ + public Set ascRangeByLex(String key, Long startSortIndex, boolean isContainsStart, Long endSortIndex, boolean isContainsEnd, Integer count, Integer offset) { + return this.stringZSetOperations.rangeByLex( + key, + this.getRange(startSortIndex, isContainsStart, endSortIndex, isContainsEnd), + RedisZSetCommands.Limit.limit().count(count).offset(offset) + ); + } + + /** + * 获取范围内的对象 + * @see Redis Documentation: ZRANGEBYSCORE + * @since redis 1.0.5 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回对象集合 + */ + public Set rangeByScoreAsObj(String key, Double min, Double max, Long count, Long offset) { + return this.zSetOperations.rangeByScore(key, min, max, offset, count); + } + + /** + * 获取范围内的字符串 + * @see Redis Documentation: ZRANGEBYSCORE + * @since redis 1.0.5 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回字符串集合 + */ + public Set rangeByScore(String key, Double min, Double max, Long count, Long offset) { + return this.stringZSetOperations.rangeByScore(key, min, max, offset, count); + } + + /** + * 获取范围内的对象(带分数) + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回对象字典 + */ + public Map rangeByScoreAsObj(String key, Long startSortIndex, Long endSortIndex) { + return ConvertUtil.toMap(this.zSetOperations.rangeWithScores(key, startSortIndex, endSortIndex)); + } + + /** + * 获取范围内的字符串(带分数) + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回字符串字典 + */ + public Map rangeByScore(String key, Long startSortIndex, Long endSortIndex) { + return ConvertUtil.toMap(this.stringZSetOperations.rangeWithScores(key, startSortIndex, endSortIndex)); + } + + /** + * 获取范围内的对象(带分数) + * @see Redis Documentation: ZRANGEBYSCORE + * @since redis 1.0.5 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回对象字典 + */ + public Map rangeByScoreWithScoresAsObj(String key, Double min, Double max) { + return ConvertUtil.toMap(this.zSetOperations.rangeByScoreWithScores(key, min, max)); + } + + /** + * 获取范围内的字符串(带分数) + * @see Redis Documentation: ZRANGEBYSCORE + * @since redis 1.0.5 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回字符串字典 + */ + public Map rangeByScoreWithScores(String key, Double min, Double max) { + return ConvertUtil.toMap(this.stringZSetOperations.rangeByScoreWithScores(key, min, max)); + } + + /** + * 获取范围内的对象(带分数) + * @see Redis Documentation: ZRANGEBYSCORE + * @since redis 1.0.5 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回对象字典 + */ + public Map rangeByScoreWithScoresAsObj(String key, Double min, Double max, Long count, Long offset) { + return ConvertUtil.toMap(this.zSetOperations.rangeByScoreWithScores(key, min, max, offset, count)); + } + + /** + * 获取范围内的字符串(带分数) + * @see Redis Documentation: ZRANGEBYSCORE + * @since redis 1.0.5 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回字符串字典 + */ + public Map rangeByScoreWithScores(String key, Double min, Double max, Long count, Long offset) { + return ConvertUtil.toMap(this.stringZSetOperations.rangeByScoreWithScores(key, min, max, offset, count)); + } + + /** + * 获取集合对象 + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @return 返回对象字典 + */ + public Set getAllAsObj(String key) { + return this.ascRangeAsObj(key, 0L, -1L); + } + + /** + * 获取集合字符串 + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @return 返回字符串字典 + */ + public Set getAll(String key) { + return this.ascRange(key, 0L, -1L); + } + + /** + * 获取集合对象(带分数) + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @return 返回对象字典 + */ + public Map getAllByScoreAsObj(String key) { + return this.rangeByScoreAsObj(key, 0L, -1L); + } + + /** + * 获取集合字符串(带分数) + * @see Redis Documentation: ZRANGE + * @since redis 1.2.0 + * @param key 键 + * @return 返回字符串字典 + */ + public Map getAllByScore(String key) { + return this.rangeByScore(key, 0L, -1L); + } + + /** + * 获取当前对象排序索引 + * @see Redis Documentation: ZRANK + * @since redis 2.0.0 + * @param key 键 + * @param value 对象 + * @return 返回对象排序索引 + */ + public Long sortIndexAsObj(String key, Object value) { + return this.zSetOperations.rank(key, value); + } + + /** + * 获取当前字符串排序索引 + * @see Redis Documentation: ZRANK + * @since redis 2.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回字符串排序索引 + */ + public Long sortIndex(String key, String value) { + return this.stringZSetOperations.rank(key, value); + } + + /** + * 当前对象分数 + * @see Redis Documentation: ZSCORE + * @since redis 1.2.0 + * @param key 键 + * @param value 对象 + * @return 返回对象分数 + */ + public Double scoreAsObj(String key, Object value) { + return this.zSetOperations.score(key, value); + } + + /** + * 当前字符串分数 + * @see Redis Documentation: ZSCORE + * @since redis 1.2.0 + * @param key 键 + * @param value 字符串 + * @return 返回字符串分数 + */ + public Double score(String key, String value) { + return this.stringZSetOperations.score(key, value); + } + + /** + * 对象分数自增 + * @see Redis Documentation: ZINCRBY + * @since redis 1.2.0 + * @param key 键 + * @param value 对象 + * @param score 自增分数 + * @return 返回对象分数 + */ + public Double incrementScoreAsObj(String key, Object value, Double score) { + return this.zSetOperations.incrementScore(key, value, score); + } + + /** + * 字符串分数自增 + * @see Redis Documentation: ZINCRBY + * @since redis 1.2.0 + * @param key 键 + * @param value 字符串 + * @param score 自增分数 + * @return 返回字符串分数 + */ + public Double incrementScore(String key, String value, Double score) { + return this.stringZSetOperations.incrementScore(key, value, score); + } + + /** + * 移除对象 + * @see Redis Documentation: ZREM + * @since redis 1.2.0 + * @param key 键 + * @param values 对象 + * @return 返回对象移除数量 + */ + public Long removeAsObj(String key, Object ...values) { + return this.zSetOperations.remove(key, values); + } + + /** + * 移除字符串 + * @see Redis Documentation: ZREM + * @since redis 1.2.0 + * @param key 键 + * @param values 字符串 + * @return 返回字符串移除数量 + */ + public Long remove(String key, String ...values) { + return this.stringZSetOperations.remove(key, (Object[]) values); + } + + /** + * 正序移除范围内的对象 + * @see Redis Documentation: ZREMRANGEBYRANK + * @since redis 2.0.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回对象移除数量 + */ + public Long ascRemoveRangeAsObj(String key, Long startSortIndex, Long endSortIndex) { + return this.zSetOperations.removeRange(key, startSortIndex, endSortIndex); + } + + /** + * 正序移除范围内的字符串 + * @see Redis Documentation: ZREMRANGEBYRANK + * @since redis 2.0.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回字符串移除数量 + */ + public Long ascRemoveRange(String key, Long startSortIndex, Long endSortIndex) { + return this.stringZSetOperations.removeRange(key, startSortIndex, endSortIndex); + } + + /** + * 倒序移除范围内的对象 + * @see Redis Documentation: ZREMRANGEBYRANK + * @since redis 2.0.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回对象移除数量 + */ + public Long descRemoveRangeAsObj(String key, Long startSortIndex, Long endSortIndex) { + return this.ascRemoveRangeAsObj(key, -endSortIndex-1, -startSortIndex-1); + } + + /** + * 倒序移除范围内的字符串 + * @see Redis Documentation: ZREMRANGEBYRANK + * @since redis 2.0.0 + * @param key 键 + * @param startSortIndex 起始排序索引 + * @param endSortIndex 结束排序索引 + * @return 返回字符串移除数量 + */ + public Long descRemoveRange(String key, Long startSortIndex, Long endSortIndex) { + return this.ascRemoveRange(key, -endSortIndex-1, -startSortIndex-1); + } + + /** + * 移除范围内的对象 + * @see Redis Documentation: ZREMRANGEBYSCORE + * @since redis 2.0.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回对象移除数量 + */ + public Long removeRangeByScoreAsObj(String key, Double min, Double max) { + return this.zSetOperations.removeRangeByScore(key, min, max); + } + + /** + * 移除范围内的字符串 + * @see Redis Documentation: ZREMRANGEBYSCORE + * @since redis 2.0.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回字符串移除数量 + */ + public Long removeRangeByScore(String key, Double min, Double max) { + return this.stringZSetOperations.removeRangeByScore(key, min, max); + } + + /** + * 取对象交集并存储到新的集合 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long intersectAndStoreAsObj(String key, String storeKey, String ...otherKys) { + return this.zSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取字符串交集并存储到新的集合 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long intersectAndStore(String key, String storeKey, String ...otherKys) { + return this.stringZSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取对象交集并存储到新的集合 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long intersectAndStoreAsObj(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, String ...otherKys) { + return this.zSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey, aggregate); + } + + /** + * 取字符串交集并存储到新的集合 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param weights 权重选项 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long intersectAndStore(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, RedisZSetCommands.Weights weights, String ...otherKys) { + return this.stringZSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey, aggregate, weights); + } + + /** + * 取对象交集并存储到新的集合 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param weights 权重选项 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long intersectAndStoreAsObj(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, RedisZSetCommands.Weights weights, String ...otherKys) { + return this.zSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey, aggregate, weights); + } + + /** + * 取字符串交集并存储到新的集合 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long intersectAndStore(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, Double weight, String ...otherKys) { + return this.stringZSetOperations.intersectAndStore(key, Arrays.asList(otherKys), storeKey, aggregate); + } + + /** + * 取对象交集(带分数) + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Map intersectByScoreAsObj(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.intersectAndStoreAsObj(key, tempKey, otherKys); + Map map = this.getAllByScoreAsObj(tempKey); + this.redisTemplate.delete(tempKey); + return map; + } + + /** + * 取字符串交集(带分数) + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Map intersectByScore(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.intersectAndStore(key, tempKey, otherKys); + Map map = this.getAllByScore(tempKey); + this.stringRedisTemplate.delete(tempKey); + return map; + } + + /** + * 取对象交集 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Set intersectAsObj(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.intersectAndStoreAsObj(key, tempKey, otherKys); + Set set = this.getAllAsObj(tempKey); + this.redisTemplate.delete(tempKey); + return set; + } + + /** + * 取字符串交集 + * @see Redis Documentation: ZINTERSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Set intersect(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.intersectAndStore(key, tempKey, otherKys); + Set set = this.getAll(tempKey); + this.stringRedisTemplate.delete(tempKey); + return set; + } + + /** + * 取对象并集并存储到新的集合 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long unionAndStoreAsObj(String key, String storeKey, String ...otherKys) { + return this.zSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取字符串并集并存储到新的集合 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long unionAndStore(String key, String storeKey, String ...otherKys) { + return this.stringZSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey); + } + + /** + * 取对象并集并存储到新的集合 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long unionAndStoreAsObj(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, String ...otherKys) { + return this.zSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey, aggregate); + } + + /** + * 取字符串并集并存储到新的集合 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param weights 权重选项 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long unionAndStore(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, RedisZSetCommands.Weights weights, String ...otherKys) { + return this.stringZSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey, aggregate, weights); + } + + /** + * 取对象并集并存储到新的集合 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param weights 权重选项 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Long unionAndStoreAsObj(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, RedisZSetCommands.Weights weights, String ...otherKys) { + return this.zSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey, aggregate, weights); + } + + /** + * 取字符串并集并存储到新的集合 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param storeKey 存储键 + * @param aggregate 聚合选项 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Long unionAndStore(String key, String storeKey, RedisZSetCommands.Aggregate aggregate, Double weight, String ...otherKys) { + return this.stringZSetOperations.unionAndStore(key, Arrays.asList(otherKys), storeKey, aggregate); + } + + /** + * 取对象并集(带分数) + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Map unionByScoreAsObj(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.unionAndStoreAsObj(key, tempKey, otherKys); + Map map = this.getAllByScoreAsObj(tempKey); + this.redisTemplate.delete(tempKey); + return map; + } + + /** + * 取字符串并集(带分数) + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Map unionByScore(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.unionAndStore(key, tempKey, otherKys); + Map map = this.getAllByScore(tempKey); + this.stringRedisTemplate.delete(tempKey); + return map; + } + + /** + * 取对象并集 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集对象个数 + */ + public Set unionAsObj(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.unionAndStore(key, tempKey, otherKys); + Set set = this.getAllAsObj(tempKey); + this.redisTemplate.delete(tempKey); + return set; + } + + /** + * 取字符串并集 + * @see Redis Documentation: ZUNIONSTORE + * @since redis 2.0.0 + * @param key 键 + * @param otherKys 其他键 + * @return 返回交集字符串个数 + */ + public Set union(String key, String ...otherKys) { + String tempKey = UUID.randomUUID().toString(); + this.unionAndStore(key, tempKey, otherKys); + Set set = this.getAll(tempKey); + this.stringRedisTemplate.delete(tempKey); + return set; + } + + /** + * 反转当前对象排序索引 + * @see Redis Documentation: ZREVRANK + * @since redis 2.0.0 + * @param key 键 + * @param value 对象 + * @return 返回对象排序索引 + */ + public Long reverseSortIndexAsObj(String key, Object value) { + return this.zSetOperations.reverseRank(key, value); + } + + /** + * 反转当前字符串排序索引 + * @see Redis Documentation: ZREVRANK + * @since redis 2.0.0 + * @param key 键 + * @param value 字符串 + * @return 返回字符串排序索引 + */ + public Long reverseSortIndex(String key, String value) { + return this.stringZSetOperations.reverseRank(key, value); + } + + /** + * 反转范围内的对象 + * @see Redis Documentation: ZREVRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startIndex 起始排序索引 + * @param endIndex 结束排序索引 + * @return 返回对象集合 + */ + public Set reverseRangeAsObj(String key, Long startIndex, Long endIndex) { + return this.zSetOperations.reverseRange(key, startIndex, endIndex); + } + + /** + * 反转范围内的字符串 + * @see Redis Documentation: ZREVRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startIndex 起始排序索引 + * @param endIndex 结束排序索引 + * @return 返回字符串集合 + */ + public Set reverseRange(String key, Long startIndex, Long endIndex) { + return this.stringZSetOperations.reverseRange(key, startIndex, endIndex); + } + + /** + * 反转范围内的对象 + * @see Redis Documentation: ZREVRANGE + * @since redis 1.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回对象集合 + */ + public Set reverseRangeByScoreAsObj(String key, Double min, Double max) { + return this.zSetOperations.reverseRangeByScore(key, min, max); + } + + /** + * 反转范围内的字符串 + * @see Redis Documentation: ZREVRANGE + * @since redis 1.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回字符串集合 + */ + public Set reverseRangeByScore(String key, Double min, Double max) { + return this.stringZSetOperations.reverseRangeByScore(key, min, max); + } + + /** + * 反转范围内的对象(带分数) + * @see Redis Documentation: ZREVRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startIndex 起始排序索引 + * @param endIndex 结束排序索引 + * @return 返回对象集合 + */ + public Map reverseRangeByScoreAsObj(String key, Long startIndex, Long endIndex) { + return ConvertUtil.toMap(this.zSetOperations.reverseRangeWithScores(key, startIndex, endIndex)); + } + + /** + * 反转范围内的字符串(带分数) + * @see Redis Documentation: ZREVRANGE + * @since redis 1.2.0 + * @param key 键 + * @param startIndex 起始排序索引 + * @param endIndex 结束排序索引 + * @return 返回字符串集合 + */ + public Map reverseRangeByScore(String key, Long startIndex, Long endIndex) { + return ConvertUtil.toMap(this.stringZSetOperations.reverseRangeWithScores(key, startIndex, endIndex)); + } + + /** + * 反转范围内的对象(带分数) + * @see Redis Documentation: ZREVRANGEBYSCORE + * @since redis 2.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回对象集合 + */ + public Map reverseRangeByScoreWithScoresAsObj(String key, Double min, Double max) { + return ConvertUtil.toMap(this.zSetOperations.reverseRangeByScoreWithScores(key, min, max)); + } + + /** + * 反转范围内的字符串(带分数) + * @see Redis Documentation: ZREVRANGEBYSCORE + * @since redis 2.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @return 返回字符串集合 + */ + public Map reverseRangeByScoreWithScores(String key, Double min, Double max) { + return ConvertUtil.toMap(this.stringZSetOperations.reverseRangeByScoreWithScores(key, min, max)); + } + + /** + * 反转范围内的对象(带分数) + * @see Redis Documentation: ZREVRANGEBYSCORE + * @since redis 2.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回对象集合 + */ + public Map reverseRangeByScoreWithScoresAsObj(String key, Double min, Double max, Long count, Long offset) { + return ConvertUtil.toMap(this.zSetOperations.reverseRangeByScoreWithScores(key, min, max, offset, count)); + } + + /** + * 反转范围内的字符串(带分数) + * @see Redis Documentation: ZREVRANGEBYSCORE + * @since redis 2.2.0 + * @param key 键 + * @param min 最小分数 + * @param max 最大分数 + * @param count 返回数量 + * @param offset 偏移量 + * @return 返回字符串集合 + */ + public Map reverseRangeByScoreWithScores(String key, Double min, Double max, Long count, Long offset) { + return ConvertUtil.toMap(this.stringZSetOperations.reverseRangeByScoreWithScores(key, min, max, offset, count)); + } + + /** + * 匹配对象 + * @see Redis Documentation: ZSCAN + * @since redis 2.8.0 + * @param key 键 + * @param count 数量 + * @param pattern 规则 + * @return 返回匹配对象 + */ + public Cursor> scanAsObj(String key, Long count, String pattern) { + return this.zSetOperations.scan(key, ScanOptions.scanOptions().count(count).match(pattern).build()); + } + + /** + * 匹配字符串 + * @see Redis Documentation: ZSCAN + * @since redis 2.8.0 + * @param key 键 + * @param count 数量 + * @param pattern 规则 + * @return 返回匹配字符串 + */ + public Cursor> scan(String key, Long count, String pattern) { + return this.stringZSetOperations.scan(key, ScanOptions.scanOptions().count(count).match(pattern).build()); + } + + /** + * 弹出最大分数值对象 + * @see Redis Documentation: ZPOPMAX + * @since redis 5.0.0 + * @param key 键 + * @return 返回对象 + */ + public Object popMaxAsObj(String key) { + return this.popMaxAsObj(key, 1).get(0); + } + + /** + * 弹出最大分数值字符串 + * @see Redis Documentation: ZPOPMAX + * @since redis 5.0.0 + * @param key 键 + * @return 返回字符串 + */ + public String popMax(String key) { + return this.popMax(key, 1).get(0); + } + + /** + * 弹出最大分数值对象 + * @see Redis Documentation: ZPOPMAX + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回对象列表 + */ + public List popMaxAsObj(String key, int count) { + return this.getPopResult("ZPOPMAX", key, count, this.redisTemplate.getValueSerializer()).get("values"); + } + + /** + * 弹出最大分数值字符串 + * @see Redis Documentation: ZPOPMAX + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回字符串列表 + */ + public List popMax(String key, int count) { + List data = new ArrayList<>(count); + Map> popResult = this.getPopResult("ZPOPMAX", key, count, this.stringRedisTemplate.getValueSerializer()); + List valueList = popResult.get("values"); + for (int i = 0; i < count; i++) { + data.add(String.valueOf(valueList.get(i))); + } + return data; + } + + /** + * 弹出最大分数值对象(带分数) + * @see Redis Documentation: ZPOPMAX + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回对象字典 + */ + @SuppressWarnings("unchecked") + public Map popMaxByScoreAsObj(String key, int count) { + return (Map) this.getPopMap("ZPOPMAX", key, count, true); + } + + /** + * 弹出最大分数值字符串(带分数) + * @see Redis Documentation: ZPOPMAX + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回字符串字典 + */ + @SuppressWarnings("unchecked") + public Map popMaxByScore(String key, int count) { + return (Map) this.getPopMap("ZPOPMAX", key, count, false); + } + + /** + * 弹出最小分数值对象 + * @see Redis Documentation: ZPOPMIN + * @since redis 5.0.0 + * @param key 键 + * @return 返回对象 + */ + public Object popMinAsObj(String key) { + return this.popMinAsObj(key, 1).get(0); + } + + /** + * 弹出最小分数值字符串 + * @see Redis Documentation: ZPOPMIN + * @since redis 5.0.0 + * @param key 键 + * @return 返回字符串 + */ + public String popMin(String key) { + return this.popMin(key, 1).get(0); + } + + /** + * 弹出最小分数值对象 + * @see Redis Documentation: ZPOPMIN + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回对象列表 + */ + public List popMinAsObj(String key, int count) { + return this.getPopResult("ZPOPMIN", key, count, this.redisTemplate.getValueSerializer()).get("values"); + } + + /** + * 弹出最小分数值字符串 + * @see Redis Documentation: ZPOPMIN + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回字符串列表 + */ + public List popMin(String key, int count) { + List data = new ArrayList<>(count); + Map> popResult = this.getPopResult("ZPOPMIN", key, count, this.stringRedisTemplate.getValueSerializer()); + List valueList = popResult.get("values"); + for (int i = 0; i < count; i++) { + data.add(String.valueOf(valueList.get(i))); + } + return data; + } + + /** + * 弹出最小分数值对象(带分数) + * @see Redis Documentation: ZPOPMIN + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回对象字典 + */ + @SuppressWarnings("unchecked") + public Map popMinByScoreAsObj(String key, int count) { + return (Map) this.getPopMap("ZPOPMIN", key, count, true); + } + + /** + * 弹出最小分数值字符串(带分数) + * @see Redis Documentation: ZPOPMIN + * @since redis 5.0.0 + * @param key 键 + * @param count 弹出数量 + * @return 返回字符串字典 + */ + @SuppressWarnings("unchecked") + public Map popMinByScore(String key, int count) { + return (Map) this.getPopMap("ZPOPMIN", key, count, false); + } + + /** + * 获取spring redis模板 + * @return 返回对象模板 + */ + public RedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** + * 获取spring string redis模板 + * @return 返回字符串模板 + */ + public StringRedisTemplate getStringRedisTemplate() { + return this.stringRedisTemplate; + } + + /** + * 获取范围对象 + * @param startSortIndex 起始排序索引 + * @param isContainsStart 是否包含起始 + * @param endSortIndex 结束排序索引 + * @param isContainsEnd 是否包含结束 + * @return 返回范围对象 + */ + private RedisZSetCommands.Range getRange(Long startSortIndex, boolean isContainsStart, Long endSortIndex, boolean isContainsEnd) { + RedisZSetCommands.Range range = RedisZSetCommands.Range.range(); + if (isContainsStart){ + range.gte(startSortIndex); + }else{ + range.gt(startSortIndex); + } + if (isContainsEnd){ + range.lte(endSortIndex); + }else{ + range.lt(endSortIndex); + } + return range; + } + + /** + * 获取弹出结果字典 + * @param command 弹出命令 + * @param key 键 + * @param count 弹出数量 + * @param isObject 是否对象 + * @return 返回弹出字典 + */ + private Map getPopMap(String command, String key, int count, boolean isObject) { + Map> popResult = this.getPopResult(command, key, count, this.stringRedisTemplate.getValueSerializer()); + List keyList = popResult.get("keys"); + List valueList = popResult.get("values"); + if (isObject) { + Map data = new LinkedHashMap<>(count); + for (int i = 0; i < count; i++) { + data.put(Double.valueOf(String.valueOf(keyList.get(i))), String.valueOf(valueList.get(i))); + } + return data; + }else { + Map data = new HashMap<>(count); + for (int i = 0; i < count; i++) { + data.put(Double.valueOf(String.valueOf(keyList.get(i))), valueList.get(i)); + } + return data; + } + } + + /** + * 获取弹出结果 + * @param command 弹出命令 + * @param key 键 + * @param count 弹出数量 + * @param redisSerializer 序列化器 + * @return 返回弹出结果字典 + */ + @SuppressWarnings("unchecked") + private Map> getPopResult(String command, String key, int count, RedisSerializer redisSerializer) { + CustomCommandHandler commandHandler = RedisUtil.getCustomCommandHandler(this.dbIndex); + List list = (List) ConvertUtil.toJavaType( + redisSerializer, + commandHandler.execute( + command, + commandHandler.serialize(key), + commandHandler.serialize(String.valueOf(count)) + ) + ); + Map> data = new HashMap<>(2); + List keyList = new ArrayList<>(count); + List valueList = new ArrayList<>(count); + if (list!=null&&list.size()>0) { + List dataList = (List) list.get(0); + for (int i = 0; i < count; i++) { + int scoreIndex = (i+1)*2-1; + int valueIndex = i*2; + keyList.add(dataList.get(scoreIndex)); + valueList.add(dataList.get(valueIndex)); + } + } + data.put("keys", keyList); + data.put("values", valueList); + return data; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ApplicationContextUtil.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ApplicationContextUtil.java new file mode 100644 index 0000000..9ee9e03 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ApplicationContextUtil.java @@ -0,0 +1,37 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.util; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * 上下文工具 + * @author xsx + * @date 2019/4/8 + * @since 1.8 + */ +public class ApplicationContextUtil implements ApplicationContextAware { + /** + * 上下文 + */ + private static ApplicationContext applicationContext; + + /** + * 设置上下文 + * @param applicationContext 上下文实例 + * @throws BeansException + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + ApplicationContextUtil.applicationContext = applicationContext; + } + + /** + * 获取上下文 + * + * @return 返回上下文工具 + */ + public static ApplicationContext getContext() { + return ApplicationContextUtil.applicationContext; + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ConvertUtil.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ConvertUtil.java new file mode 100644 index 0000000..e124246 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/ConvertUtil.java @@ -0,0 +1,336 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.openmbean.SimpleType; + +import org.springframework.data.geo.GeoResult; +import org.springframework.data.geo.GeoResults; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.connection.stream.Record; +import org.springframework.data.redis.core.DefaultTypedTuple; +import org.springframework.data.redis.core.ZSetOperations; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.util.Assert; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.StreamHandler; + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; + +/** + * 转换工具 + * @author xsx + * @date 2019/4/28 + * @since 1.8 + */ +public class ConvertUtil { + + /** + * 转为二维字节数组 + * @param serializer 序列化器 + * @param args 参数 + * @return 返回二位字节数组 + */ + public static byte[][] toByteArray(RedisSerializer serializer, String ...args) { + byte[][] bytes = new byte[args.length][]; + for (int i = 0; i < args.length; i++) { + bytes[i] = toBytes(serializer, args[i]); + } + return bytes; + } + + /** + * 转为二维字节数组 + * @param serializer 序列化器 + * @param args2 参数列表2 + * @param args1 参数列表1 + * @return 返回二位字节数组 + */ + public static byte[][] toByteArray(RedisSerializer serializer, String[] args2, String ...args1) { + int len1 = args1.length; + int len2 = args2==null? 0 : args2.length; + byte[][] bytes = new byte[len1+len2][]; + for (int i = 0; i < len1; i++) { + bytes[i] = toBytes(serializer, args1[i]); + } + for (int i = 0; i < len2; i++) { + bytes[i+len1] = toBytes(serializer, args2[i]); + } + return bytes; + } + + /** + * 转为二维字节数组 + * @param keySerializer 键序列化器 + * @param argsSerializer 参数序列化器 + * @param keys 键列表 + * @param args 参数列表 + * @param 键类型 + * @return 返回键和参数的二维数组 + */ + @SuppressWarnings("unchecked") + public static byte[][] toByteArray(RedisSerializer keySerializer, RedisSerializer argsSerializer, List keys, Object[] args) { + Assert.notNull(keySerializer, "keySerializer must not be null"); + Assert.notNull(argsSerializer, "argsSerializer must not be null"); + + final int keySize = keys != null ? keys.size() : 0; + byte[][] keysAndArgs = new byte[args.length + keySize][]; + int i = 0; + if (keys != null) { + for (K key : keys) { + if (key instanceof byte[]) { + keysAndArgs[i++] = (byte[]) key; + } else { + keysAndArgs[i++] = keySerializer.serialize(key); + } + } + } + for (Object arg : args) { + if (arg instanceof byte[]) { + keysAndArgs[i++] = (byte[]) arg; + } else { + keysAndArgs[i++] = argsSerializer.serialize(arg); + } + } + return keysAndArgs; + } + + /** + * 将字典转为TypedTuple类型的集合 + * @param map 字典 + * @param 对象类型 + * @return 返回TypedTuple类型的集合 + */ + public static Set> toTypedTupleSet(Map map) { + if(map==null){ + return null; + } + Set> set = new HashSet<>(map.size()); + for (Map.Entry entry : map.entrySet()) { + set.add(new DefaultTypedTuple<>(entry.getValue(), entry.getKey())); + } + return set; + } + + public static List toList(GeoResults> results) { + List list; + if (results!=null) { + list = new ArrayList<>(results.getContent().size()); + for (GeoResult> result : results) { + list.add(result.getContent().getName()); + } + }else { + list = new ArrayList<>(0); + } + return list; + } + + /** + * 转换为字典 + * @param results 结果集 + * @param 类型 + * @return 返回字典 + */ + public static Map toMap(GeoResults> results) { + Map map; + if (results!=null) { + map = new HashMap<>(results.getContent().size()); + for (GeoResult> result : results) { + map.put(result.getContent().getName(), result.getContent().getPoint()); + } + }else { + map = new HashMap<>(0); + } + return map; + } + + /** + * 将TypedTuple类型的集合转为字典 + * @param set TypedTuple类型的集合 + * @param 对象类型 + * @return 返回TypedTuple类型的集合 + */ + public static Map toMap(Set> set) { + if(set==null){ + return null; + } + Map map = new LinkedHashMap<>(set.size()); + for (ZSetOperations.TypedTuple typedTuple : set) { + map.put(typedTuple.getScore(), typedTuple.getValue()); + } + return map; + } + + /** + * 将对象转为字典 + * @param values 对象 + * @param 对象类型 + * @return 返回对象字典 + */ + @SuppressWarnings("unchecked") + public static Map toMap(T ...values) { + if(values==null){ + return null; + } + Map map = new HashMap<>(values.length); + for (int i = 0; i < values.length; i++) { + map.put((double) i, values[i]); + } + return map; + } + + /** + * 将列表转为字典 + * @param list 列表 + * @param type 数据类型 + * @return 返回字典 + */ + public static Map toMap(List> list, StreamHandler.StreamDataType type) { + Map data; + if (list!=null&&list.size()>0) { + if (type== StreamHandler.StreamDataType.LATEST) { + data = new HashMap<>(1); + Record record = list.get(list.size()-1); + data.put(record.getId().getValue(), record.getValue()); + }else if (type== StreamHandler.StreamDataType.EARLIEST) { + data = new HashMap<>(1); + Record record = list.get(0); + data.put(record.getId().getValue(), record.getValue()); + }else { + data = new HashMap<>(list.size()); + for (Record records : list) { + data.put(records.getId().getValue(), records.getValue()); + } + } + }else { + data = new HashMap<>(0); + } + return data; + } + + /** + * 转为字节数组 + * @param serializer 序列化器 + * @param value 值 + * @return 返回字节数组 + */ + @SuppressWarnings("unchecked") + public static byte[] toBytes(RedisSerializer serializer, Object value) { + Assert.notNull(serializer, "serializer must not be null"); + + if (value instanceof byte[]) { + return (byte[]) value; + } + return serializer.serialize(value); + } + + /** + * 转为字符串 + * @param serializer 序列化器 + * @param bytes 字节数组 + * @return 返回字符串 + */ + public static String toStr(RedisSerializer serializer, byte[] bytes) { + Assert.notNull(serializer, "serializer must not be null"); + + Object o = serializer.deserialize(bytes); + return o==null?null:o.toString(); + } + + /** + * 转为java类型 + * @param t 对象 + * @param type 返回类型 + * @param 返回类型 + * @return 返回对应的java对象 + */ + public static Object toJavaType(Object t, Class type) { + if (t==null) { + return null; + } + if (t instanceof JSONObject) { + return JSONUtil.toBean((JSONObject) t, type); + }else if (t instanceof JSONArray) { + return JSONUtil.toList((JSONArray) t, type); + } + String str = t.toString(); + if (NumberUtil.isNumber(str)) { + String typeName = type.getName(); + if (NumberUtil.isDouble(str)) { + BigDecimal value = new BigDecimal(str); + if (SimpleType.FLOAT.getTypeName().equals(typeName)) { + return value.floatValue(); + } + return value.doubleValue(); + }else { + BigInteger value = new BigInteger(str); + if (SimpleType.INTEGER.getTypeName().equals(typeName)) { + return value.intValue(); + }else if (SimpleType.SHORT.getTypeName().equals(typeName)) { + return value.shortValue(); + } + return value.longValue(); + } + }else { + return t; + } + } + + /** + * 转为java类型 + * @param serializer 序列化器 + * @param result 对象 + * @return 返回对应的java对象 + */ + @SuppressWarnings("unchecked") + public static Object toJavaType(RedisSerializer serializer, Object result) { + if (result==null) { + return null; + } + if (result instanceof List) { + List newList = new ArrayList<>(20); + parseList(serializer, newList, result); + return newList; + }else if (result instanceof byte[]) { + return serializer.deserialize((byte[]) result); + }else { + return result; + } + } + + /** + * 解析list列表 + * @param serializer 序列化器 + * @param list 列表 + * @param result 对象 + */ + @SuppressWarnings("unchecked") + private static void parseList(RedisSerializer serializer, List list, Object result) { + if (result instanceof List) { + List resultList = (List) result; + List newList = new ArrayList<>(resultList.size()); + for (Object o : resultList) { + parseList(serializer, newList, o); + } + list.add(newList); + }else { + if (result instanceof byte[]) { + list.add(serializer.deserialize((byte[]) result)); + }else { + list.add(result); + } + } + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/RedisUtil.java b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/RedisUtil.java new file mode 100644 index 0000000..1fee892 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/redis/starter/util/RedisUtil.java @@ -0,0 +1,381 @@ +package com.chinaunicom.mall.ebtp.cloud.redis.starter.util; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.hash.HashMapper; + +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.BitmapHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.ClusterHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.CustomCommandHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.DBHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.GeoHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.HandlerManagerProxy; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.HandlerType; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.HashHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.HyperLogLogHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.KeyHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.ListHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.NumberHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.PubSubHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.RedisLockHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.ScriptHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.SentinelHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.SetHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.StreamHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.StringHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.TransactionHandler; +import com.chinaunicom.mall.ebtp.cloud.redis.starter.handler.ZsetHandler; + +/** + * redis工具 + * @author xsx + * @date 2019/4/8 + * @since 1.8 + */ +public class RedisUtil { + + /** + * 助手管理代理实例 + */ + private static final HandlerManagerProxy MANAGER = new HandlerManagerProxy(); + + /** + * 获取数据库助手 + * @return 返回数据库助手 + */ + public static DBHandler getDBHandler() { + return MANAGER.getHandler(HandlerType.DB); + } + + /** + * 获取数据库助手 + * @param dbIndex 数据库索引 + * @return 返回数据库助手 + */ + public static DBHandler getDBHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.DB); + } + + /** + * 获取键助手 + * @return 返回键助手 + */ + public static KeyHandler getKeyHandler() { + return MANAGER.getHandler(HandlerType.KEY); + } + + /** + * 获取键助手 + * @param dbIndex 数据库索引 + * @return 返回键助手 + */ + public static KeyHandler getKeyHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.KEY); + } + + /** + * 获取数字助手 + * @return 返回数字助手 + */ + public static NumberHandler getNumberHandler() { + return MANAGER.getHandler(HandlerType.NUMBER); + } + + /** + * 获取数字助手 + * @param dbIndex 数据库索引 + * @return 返回数字助手 + */ + public static NumberHandler getNumberHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.NUMBER); + } + + /** + * 获取字符串助手 + * @return 返回字符串助手 + */ + public static StringHandler getStringHandler() { + return MANAGER.getHandler(HandlerType.STRING); + } + + /** + * 获取字符串助手 + * @param dbIndex 数据库索引 + * @return 返回字符串助手 + */ + public static StringHandler getStringHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.STRING); + } + + /** + * 获取哈希助手 + * @return 返回哈希助手 + */ + public static HashHandler getHashHandler() { + return MANAGER.getHandler(HandlerType.HASH); + } + + /** + * 获取哈希助手 + * @param dbIndex 数据库索引 + * @return 返回哈希助手 + */ + public static HashHandler getHashHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.HASH); + } + + /** + * 获取列表助手 + * @return 返回列表助手 + */ + public static ListHandler getListHandler() { + return MANAGER.getHandler(HandlerType.LIST); + } + + /** + * 获取列表助手 + * @param dbIndex 数据库索引 + * @return 返回列表助手 + */ + public static ListHandler getListHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.LIST); + } + + /** + * 获取无序集合助手 + * @return 返回无序集合助手 + */ + public static SetHandler getSetHandler() { + return MANAGER.getHandler(HandlerType.SET); + } + + /** + * 获取无序集合助手 + * @param dbIndex 数据库索引 + * @return 返回无序集合助手 + */ + public static SetHandler getSetHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.SET); + } + + /** + * 获取有序集合助手 + * @return 返回有序集合助手 + */ + public static ZsetHandler getZsetHandler() { + return MANAGER.getHandler(HandlerType.ZSET); + } + + /** + * 获取有序集合助手 + * @param dbIndex 数据库索引 + * @return 返回有序集合助手 + */ + public static ZsetHandler getZsetHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.ZSET); + } + + /** + * 获取基数助手 + * @return 返回基数助手 + */ + public static HyperLogLogHandler getHyperLogLogHandler() { + return MANAGER.getHandler(HandlerType.HYPERLOGLOG); + } + + /** + * 获取基数助手 + * @param dbIndex 数据库索引 + * @return 返回基数助手 + */ + public static HyperLogLogHandler getHyperLogLogHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.HYPERLOGLOG); + } + + /** + * 获取位图助手 + * @return 返回位图助手 + */ + public static BitmapHandler getBitmapHandler() { + return MANAGER.getHandler(HandlerType.BITMAP); + } + + /** + * 获取位图助手 + * @param dbIndex 数据库索引 + * @return 返回位图助手 + */ + public static BitmapHandler getBitmapHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.BITMAP); + } + + /** + * 获取地理位置助手 + * @return 返回地理位置助手 + */ + public static GeoHandler getGeoHandler() { + return MANAGER.getHandler(HandlerType.GEO); + } + + /** + * 获取地理位置助手 + * @param dbIndex 数据库索引 + * @return 返回地理位置助手 + */ + public static GeoHandler getGeoHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.GEO); + } + + /** + * 获取lua脚本助手 + * @return 返回lua脚本助手 + */ + public static ScriptHandler getScriptHandler() { + return MANAGER.getHandler(HandlerType.SCRIPT); + } + + /** + * 获取lua脚本助手 + * @param dbIndex 数据库索引 + * @return 返回lua脚本助手 + */ + public static ScriptHandler getScriptHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.SCRIPT); + } + + /** + * 获取发布订阅助手 + * @return 返回发布订阅助手 + */ + public static PubSubHandler getPubSubHandler() { + return MANAGER.getHandler(HandlerType.PUBSUB); + } + + /** + * 获取发布订阅助手 + * @param dbIndex 数据库索引 + * @return 返回发布订阅助手 + */ + public static PubSubHandler getPubSubHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.PUBSUB); + } + + /** + * 获取流助手 + * @return 返回流助手 + */ + public static StreamHandler getStreamHandler() { + return MANAGER.getHandler(HandlerType.STREAM); + } + + /** + * 获取流助手 + * @param dbIndex 数据库索引 + * @return 返回流助手 + */ + public static StreamHandler getStreamHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.STREAM); + } + + /** + * 获取流助手 + * @param dbIndex 数据库索引 + * @param mapper 哈希映射器 + * @return 返回流助手 + */ + public static StreamHandler getStreamHandler(int dbIndex, HashMapper mapper) { + return MANAGER.getStreamHandler(dbIndex, mapper); + } + + /** + * 获取分布式锁助手(需添加redisson依赖) + * @return 返回分布式锁助手 + */ + public static RedisLockHandler getRedisLockHandler() { + return MANAGER.getHandler(HandlerType.REDISLOCK); + } + + /** + * 获取分布式锁助手(需添加redisson依赖) + * @param dbIndex 数据库索引 + * @return 返回分布式锁助手 + */ + public static RedisLockHandler getRedisLockHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.REDISLOCK); + } + + /** + * 获取哨兵助手 + * @return 返回哨兵助手 + */ + public static SentinelHandler getSentinelHandler() { + return MANAGER.getHandler(HandlerType.SENTINEL); + } + + /** + * 获取哨兵助手 + * @param dbIndex 数据库索引 + * @return 返回哨兵助手 + */ + public static SentinelHandler getSentinelHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.SENTINEL); + } + + /** + * 获取集群助手 + * @return 返回集群助手 + */ + public static ClusterHandler getClusterHandler() { + return MANAGER.getHandler(HandlerType.CLUSTER); + } + + /** + * 获取自定义命令助手 + * @return 返回自定义命令助手 + */ + public static CustomCommandHandler getCustomCommandHandler() { + return MANAGER.getHandler(HandlerType.CUSTOMCOMMAND); + } + + /** + * 获取自定义命令助手 + * @param dbIndex 数据库索引 + * @return 返回自定义命令助手 + */ + public static CustomCommandHandler getCustomCommandHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.CUSTOMCOMMAND); + } + + /** + * 获取事务助手 + * @return 返回事务助手 + */ + public static TransactionHandler getTransactionHandler() { + return MANAGER.getHandler(HandlerType.TRANSACTION); + } + + /** + * 获取事务助手 + * @param dbIndex 数据库索引 + * @return 返回事务助手 + */ + public static TransactionHandler getTransactionHandler(int dbIndex) { + return MANAGER.getHandler(String.valueOf(dbIndex), HandlerType.TRANSACTION); + } + + /** + * 获取默认的对象模板 + * @return 返回对象模板 + */ + public static RedisTemplate getDefaultRedisTemplate() { + return MANAGER.getDefaultRedisTemplate(); + } + + /** + * 获取默认的字符串模板 + * @return 返回字符串模板 + */ + public static StringRedisTemplate getDefaultStringRedisTemplate() { + return MANAGER.getDefaultStringRedisTemplate(); + } +} diff --git a/mall-ebtp-cloud-redis-starter/src/main/resources/META-INF/spring.factories b/mall-ebtp-cloud-redis-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..23b74c1 --- /dev/null +++ b/mall-ebtp-cloud-redis-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +# redis初始化 +org.springframework.context.ApplicationContextInitializer=com.chinaunicom.mall.ebtp.cloud.redis.starter.config.RedisInitializer \ No newline at end of file