From b7fdbba4988f2befb9f3312155947df96de2c3ee Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Thu, 2 Dec 2021 20:46:12 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=AE=9E=E7=8E=B0=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E7=BC=93=E5=AD=98=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/flyfish/framework/bean/Result.java | 36 +- .../framework/context/UserContext.java | 2 +- .../annotations/EnableAutoSecurity.java | 3 + .../domain/authorized/AuthorizedDomain.java | 25 + .../domain/authorized/AuthorizedQo.java | 53 ++ .../framework/service/DepartmentService.java | 26 + .../service/ReactiveUserService.java | 16 + .../annotations/RequestContextBody.java | 3 + .../redis/EnableReactiveRedis.java | 17 + .../configuration/redis/EnableRedis.java | 17 + .../redis/JacksonRedisSerializerFactory.java | 19 + .../redis/ReactiveRedisConfig.java | 51 ++ .../{ => redis}/RedisConfig.java | 25 +- .../resolver/PageQueryArgumentResolver.java | 3 +- .../RequestContextBodyArgumentResolver.java | 2 +- .../utils/ReactiveRedisOperations.java | 485 ++++++++++++++++++ 16 files changed, 750 insertions(+), 33 deletions(-) create mode 100644 flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java create mode 100644 flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableReactiveRedis.java create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableRedis.java create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/JacksonRedisSerializerFactory.java create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/ReactiveRedisConfig.java rename flyfish-web/src/main/java/com/flyfish/framework/configuration/{ => redis}/RedisConfig.java (55%) create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/utils/ReactiveRedisOperations.java diff --git a/flyfish-common/src/main/java/com/flyfish/framework/bean/Result.java b/flyfish-common/src/main/java/com/flyfish/framework/bean/Result.java index 5808862..54739b5 100644 --- a/flyfish-common/src/main/java/com/flyfish/framework/bean/Result.java +++ b/flyfish-common/src/main/java/com/flyfish/framework/bean/Result.java @@ -4,11 +4,11 @@ import com.flyfish.framework.constant.Frameworks; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; +import reactor.core.publisher.Mono; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.function.Consumer; import java.util.function.Function; /** @@ -54,9 +54,16 @@ public class Result { return new Result<>(SUCCESS, MSG_SUCCESS, data); } - public Result end(Runnable runnable) { - runnable.run(); - return this; + public static Mono> just(T data) { + return Mono.just(accept(data)); + } + + public static Mono>> just(Page page) { + return Mono.just(accept(page)); + } + + public static Mono> just() { + return Mono.just(ok()); } /** @@ -115,6 +122,11 @@ public class Result { return new Result<>(FAIL, errMsg, null); } + public Result end(Runnable runnable) { + runnable.run(); + return this; + } + public Result toVoid() { return (Result) this; } @@ -157,14 +169,14 @@ public class Result { return Frameworks.config.isResultStyle() ? null : data; } - public T getResult() { - return Frameworks.config.isResultStyle() ? data : null; - } - public void setData(T data) { this.data = data; } + public T getResult() { + return Frameworks.config.isResultStyle() ? data : null; + } + public String getCode() { return code; } @@ -177,11 +189,11 @@ public class Result { return Frameworks.config.isResultStyle() ? null : msg; } - public String getMessage() { - return Frameworks.config.isResultStyle() ? msg : null; - } - public void setMsg(String msg) { this.msg = msg; } + + public String getMessage() { + return Frameworks.config.isResultStyle() ? msg : null; + } } diff --git a/flyfish-data/src/main/java/com/flyfish/framework/context/UserContext.java b/flyfish-data/src/main/java/com/flyfish/framework/context/UserContext.java index 9d5f6f7..fb0716b 100644 --- a/flyfish-data/src/main/java/com/flyfish/framework/context/UserContext.java +++ b/flyfish-data/src/main/java/com/flyfish/framework/context/UserContext.java @@ -14,7 +14,7 @@ import java.util.Optional; public final class UserContext { private static UserContext instance; - private ThreadLocal userThreadLocal = new ThreadLocal<>(); + private final ThreadLocal userThreadLocal = new ThreadLocal<>(); public UserContext() { instance = this; diff --git a/flyfish-user/src/main/java/com/flyfish/framework/annotations/EnableAutoSecurity.java b/flyfish-user/src/main/java/com/flyfish/framework/annotations/EnableAutoSecurity.java index 1082007..52a20f7 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/annotations/EnableAutoSecurity.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/annotations/EnableAutoSecurity.java @@ -1,6 +1,7 @@ package com.flyfish.framework.annotations; import com.flyfish.framework.config.WebSecurityConfig; +import com.flyfish.framework.configuration.redis.EnableReactiveRedis; import org.springframework.context.annotation.Import; import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; @@ -8,6 +9,7 @@ import java.lang.annotation.*; /** * 启用自动security配置 + * * @author wangyu */ @Retention(RetentionPolicy.RUNTIME) @@ -15,5 +17,6 @@ import java.lang.annotation.*; @Documented @Import(WebSecurityConfig.class) @EnableReactiveMongoRepositories(basePackages = "com.flyfish.framework") +@EnableReactiveRedis public @interface EnableAutoSecurity { } diff --git a/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java b/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java new file mode 100644 index 0000000..aefa8fa --- /dev/null +++ b/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java @@ -0,0 +1,25 @@ +package com.flyfish.framework.domain.authorized; + +import com.flyfish.framework.domain.base.AuditDomain; +import lombok.Getter; +import lombok.Setter; + +/** + * 带鉴权的实体,主要以部门隔绝 + * @param + */ +@Getter +@Setter +public abstract class AuthorizedDomain> extends AuditDomain { + + // 作用域id,一般是部门。用户存储时插入 + private String authorizeId; + + public String getAuthorizeId() { + return + } + + public String setAuthorizeId() { + + } +} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java b/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java new file mode 100644 index 0000000..5ac1597 --- /dev/null +++ b/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java @@ -0,0 +1,53 @@ +package com.flyfish.framework.domain.authorized; + +import com.flyfish.framework.builder.CriteriaBuilder; +import com.flyfish.framework.context.SpringContext; +import com.flyfish.framework.domain.base.NameLikeQo; +import com.flyfish.framework.domain.po.Department; +import com.flyfish.framework.domain.po.User; +import com.flyfish.framework.service.DepartmentService; +import lombok.Getter; +import lombok.Setter; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 带鉴权的查询实体,主要以部门隔绝 + * + * @param + */ +@Getter +@Setter +public abstract class AuthorizedQo> extends NameLikeQo { + + // 部门服务 + private DepartmentService departmentService; + + /** + * 获取可见的权限ids + * + * @return 结果 + */ + public List getAuthorizedIds() { + return Optional.ofNullable(this.user) + .map(User::getDepartments) + .map(departs -> departs.stream().map(Department::getId).collect(Collectors.toList())) + .map(this::getSubAuthorities) + .orElse(Collections.emptyList()); + } + + @Override + public CriteriaBuilder criteriaBuilder() { + return super.criteriaBuilder().with("authorizedIds", "authorizeId", CriteriaBuilder.Builders.IN); + } + + private List getSubAuthorities(List parents) { + if (null == departmentService) { + departmentService = SpringContext.getBean(DepartmentService.class); + } + return departmentService.getSubCodes(parents); + } +} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java b/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java index ec9de03..bf5bdd6 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java @@ -2,9 +2,35 @@ package com.flyfish.framework.service; import com.flyfish.framework.domain.po.Department; import com.flyfish.framework.service.impl.BaseServiceImpl; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 部门服务 + * + * @author wangyu + */ @Service public class DepartmentService extends BaseServiceImpl { + @Resource + private MongoOperations mongoOperations; + + /** + * 获取子部门列表 + * + * @return 结果 + */ + public List getSubCodes(List parents) { + Query query = Query.query(Criteria.where("parentId").in(parents)); + query.fields().include("_id"); + return mongoOperations.find(query, Department.class).stream().map(Department::getId) + .collect(Collectors.toList()); + } } diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java b/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java index 0ae3814..354dffb 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java @@ -3,9 +3,14 @@ package com.flyfish.framework.service; import com.flyfish.framework.domain.po.User; import com.flyfish.framework.repository.ReactiveUserRepository; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl; +import com.flyfish.framework.utils.RedisOperations; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; +import javax.annotation.Resource; + /** * 异步用户service * @@ -14,14 +19,25 @@ import reactor.core.publisher.Mono; @Service public class ReactiveUserService extends BaseReactiveServiceImpl { + @Resource + private RedisOperations redisOperations; + /** * 获取用户数据 * * @param username 用户 * @return 结果 */ + @Cacheable public Mono findByUsername(String username) { + if (redisOperations.hasKey(getCacheKey(username))) { + return + } return ((ReactiveUserRepository) repository).findByUsername(username); } + private String getCacheKey(String username) { + return "user-" + username; + } + } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/RequestContextBody.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/RequestContextBody.java index f07544f..20ba596 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/RequestContextBody.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/RequestContextBody.java @@ -13,4 +13,7 @@ import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface RequestContextBody { + + boolean required() default true; + } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableReactiveRedis.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableReactiveRedis.java new file mode 100644 index 0000000..f1d0ad0 --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableReactiveRedis.java @@ -0,0 +1,17 @@ +package com.flyfish.framework.configuration.redis; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.*; + +/** + * 启用自动security配置 + * + * @author wangyu + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +@Import(ReactiveRedisConfig.class) +public @interface EnableReactiveRedis { +} diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableRedis.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableRedis.java new file mode 100644 index 0000000..0142110 --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/EnableRedis.java @@ -0,0 +1,17 @@ +package com.flyfish.framework.configuration.redis; + +import org.springframework.context.annotation.Import; +import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; + +import java.lang.annotation.*; + +/** + * 启用自动security配置 + * @author wangyu + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +@Import(RedisConfig.class) +public @interface EnableRedis { +} diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/JacksonRedisSerializerFactory.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/JacksonRedisSerializerFactory.java new file mode 100644 index 0000000..bf48bc3 --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/JacksonRedisSerializerFactory.java @@ -0,0 +1,19 @@ +package com.flyfish.framework.configuration.redis; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; + +public class JacksonRedisSerializerFactory { + + public static Jackson2JsonRedisSerializer produce() { + // 设置序列化 + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); + ObjectMapper om = new ObjectMapper(); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + jackson2JsonRedisSerializer.setObjectMapper(om); + return jackson2JsonRedisSerializer; + } +} diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/ReactiveRedisConfig.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/ReactiveRedisConfig.java new file mode 100644 index 0000000..db9444e --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/ReactiveRedisConfig.java @@ -0,0 +1,51 @@ +package com.flyfish.framework.configuration.redis; + +import com.flyfish.framework.utils.ReactiveRedisOperations; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.ReactiveRedisTemplate; +import org.springframework.data.redis.core.ReactiveStringRedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +public class ReactiveRedisConfig { + + @Bean + public ReactiveStringRedisTemplate reactiveStringRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { + return new ReactiveStringRedisTemplate(lettuceConnectionFactory); + } + + /** + * RedisTemplate配置 + * + * @param lettuceConnectionFactory 支持异步的连接池 + * @return 结果 + */ + @Bean + public ReactiveRedisTemplate reactiveRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { + Jackson2JsonRedisSerializer jacksonSerializer = JacksonRedisSerializerFactory.produce(); + RedisSerializer stringSerializer = new StringRedisSerializer(); + RedisSerializationContext serializationContext = RedisSerializationContext + .newSerializationContext() + // key序列化 + .key(stringSerializer) + // value序列化 + .value(jacksonSerializer) + // Hash key序列化 + .hashKey(stringSerializer) + // Hash value序列化 + .hashValue(jacksonSerializer) + .build(); + // 配置redisTemplate + return new ReactiveRedisTemplate<>(lettuceConnectionFactory, serializationContext); + } + + @Bean + public ReactiveRedisOperations redisOperations(ReactiveStringRedisTemplate reactiveStringRedisTemplate, + ReactiveRedisTemplate reactiveRedisTemplate) { + return new ReactiveRedisOperations(reactiveRedisTemplate, reactiveStringRedisTemplate); + } + +} diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/RedisConfig.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/RedisConfig.java similarity index 55% rename from flyfish-web/src/main/java/com/flyfish/framework/configuration/RedisConfig.java rename to flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/RedisConfig.java index 08ed67e..faf5ff8 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/configuration/RedisConfig.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/redis/RedisConfig.java @@ -1,11 +1,7 @@ -package com.flyfish.framework.configuration; +package com.flyfish.framework.configuration.redis; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.databind.ObjectMapper; import com.flyfish.framework.utils.RedisOperations; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; @@ -13,7 +9,6 @@ import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; -@Configuration public class RedisConfig { @Bean @@ -24,32 +19,28 @@ public class RedisConfig { /** * RedisTemplate配置 * - * @param lettuceConnectionFactory - * @return + * @param lettuceConnectionFactory 连接池 + * @return 结果 */ @Bean public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { // 设置序列化 - Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); - ObjectMapper om = new ObjectMapper(); - om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); - om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); - jackson2JsonRedisSerializer.setObjectMapper(om); + Jackson2JsonRedisSerializer jacksonSerializer = JacksonRedisSerializerFactory.produce(); // 配置redisTemplate RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); RedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer);// key序列化 - redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化 + redisTemplate.setValueSerializer(jacksonSerializer);// value序列化 redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化 - redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化 + redisTemplate.setHashValueSerializer(jacksonSerializer);// Hash value序列化 redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean - public RedisOperations redisOperations(LettuceConnectionFactory lettuceConnectionFactory, StringRedisTemplate stringRedisTemplate) { - return new RedisOperations(redisTemplate(lettuceConnectionFactory), stringRedisTemplate); + public RedisOperations redisOperations(RedisTemplate redisTemplate, StringRedisTemplate stringRedisTemplate) { + return new RedisOperations(redisTemplate, stringRedisTemplate); } } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java index 6bf9324..a504ff2 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java @@ -54,8 +54,7 @@ public class PageQueryArgumentResolver extends HandlerMethodArgumentResolverSupp // 使用spring的hack来解析pageable Pageable pageable = pageableParameterFilter.filter(parameter, bindingContext, exchange); // 使用spring的默认解析器解析所有变量 - return modelAttributeFilter.filter(parameter, - bindingContext, exchange).flatMap(qo -> { + return modelAttributeFilter.filter(parameter, bindingContext, exchange).flatMap(qo -> { if (qo instanceof Qo) { Qo query = (Qo) qo; query.setPageable(pageable); diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/RequestContextBodyArgumentResolver.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/RequestContextBodyArgumentResolver.java index 8a2389f..5e2c9bf 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/RequestContextBodyArgumentResolver.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/RequestContextBodyArgumentResolver.java @@ -37,7 +37,7 @@ public class RequestContextBodyArgumentResolver extends AbstractMessageReaderArg @Override public Mono resolveArgument( MethodParameter param, BindingContext bindingContext, ServerWebExchange exchange) { - RequestBody ann = param.getParameterAnnotation(RequestBody.class); + RequestContextBody ann = param.getParameterAnnotation(RequestContextBody.class); Assert.state(ann != null, "No RequestBody annotation"); return readBody(param, ann.required(), bindingContext, exchange) .flatMap(object -> { diff --git a/flyfish-web/src/main/java/com/flyfish/framework/utils/ReactiveRedisOperations.java b/flyfish-web/src/main/java/com/flyfish/framework/utils/ReactiveRedisOperations.java new file mode 100644 index 0000000..35dea57 --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/utils/ReactiveRedisOperations.java @@ -0,0 +1,485 @@ +package com.flyfish.framework.utils; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.ReactiveRedisTemplate; +import org.springframework.data.redis.core.ReactiveStringRedisTemplate; +import org.springframework.data.util.CastUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; + +/** + * redis 工具类 + * + * @author wangyu + */ +@RequiredArgsConstructor +public class ReactiveRedisOperations { + + private final ReactiveRedisTemplate redisTemplate; + + private final ReactiveStringRedisTemplate stringRedisTemplate; + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @return 是否成功指定 + */ + public Mono expire(String key, long time) { + return redisTemplate.expire(key, Duration.of(time, ChronoUnit.SECONDS)) + .doOnError(Throwable::printStackTrace) + .onErrorReturn(false); + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public Mono getExpire(String key) { + return redisTemplate.getExpire(key).map(Duration::getSeconds); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public Mono hasKey(String key) { + return redisTemplate.hasKey(key).doOnError(Throwable::printStackTrace).onErrorReturn(false); + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + public Mono del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + return redisTemplate.delete(key[0]); + } else { + return redisTemplate.delete(key); + } + } + return Mono.just(0L); + } + + // ============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Mono get(String key) { + if (key == null) { + return null; + } + try { + return redisTemplate.opsForValue().get(key).map(CastUtils::cast); + } catch (Exception e) { + return stringRedisTemplate.opsForValue().get(key).map(CastUtils::cast); + } + } + + /** + * 获取string + * + * @param key 键 + * @return 结果 + */ + public Mono getString(String key) { + return null == key ? Mono.empty() : stringRedisTemplate.opsForValue().get(key); + } + + /** + * 获取多个key值 + * + * @param key 键 + * @return 结果 + */ + public Flux getKeys(String key) { + return null == key ? Flux.empty() : redisTemplate.keys(key); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public Mono set(String key, Object value) { + return redisTemplate.opsForValue().set(key, value) + .doOnError(Throwable::printStackTrace).onErrorReturn(false); + } + + public Mono set(String key, String value) { + return stringRedisTemplate.opsForValue().set(key, value) + .doOnError(Throwable::printStackTrace).onErrorReturn(false); + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public Mono set(String key, Object value, long time) { + if (time > 0) { + return redisTemplate.opsForValue().set(key, value, Duration.of(time, ChronoUnit.SECONDS)) + .doOnError(Throwable::printStackTrace).onErrorReturn(false); + } else { + return set(key, value); + } + } + + /** + * 递增 + * + * @param key 键 + * @param delta 要增加几(大于0) + * @return 结果 + */ + public Mono incr(String key, long delta) { + if (delta < 0) { + return Mono.error(new RuntimeException("递增因子必须大于0")); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @param delta 要减少几(小于0) + * @return + */ + public Mono decr(String key, long delta) { + if (delta < 0) { + return Mono.error(new RuntimeException("递减因子必须大于0")); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + + // ================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Mono hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Flux> hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public Mono hmset(String key, Map map) { + return redisTemplate.opsForHash().putAll(key, map).doOnError(Throwable::printStackTrace).onErrorReturn(false); + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public Mono hmset(String key, Map map, long time) { + return redisTemplate.opsForHash().putAll(key, map).doOnError(Throwable::printStackTrace) + .flatMap(e -> time > 0 ? expire(key, time).thenReturn(true) : Mono.just(true)) + .onErrorReturn(false); + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public Mono hset(String key, String item, Object value) { + return redisTemplate.opsForHash().put(key, item, value).doOnError(Throwable::printStackTrace).onErrorReturn(false); + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public Mono hset(String key, String item, Object value, long time) { + return redisTemplate.opsForHash().put(key, item, value) + .doOnError(Throwable::printStackTrace) + .flatMap(e -> time > 0 ? expire(key, time).thenReturn(true) : Mono.just(true)) + .onErrorReturn(false); + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + */ + public Mono hdel(String key) { + return redisTemplate.opsForHash().delete(key); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public Mono hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public Mono hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public Mono hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return 所有值 + */ + public Flux sGet(String key) { + return redisTemplate.opsForSet().members(key).doOnError(Throwable::printStackTrace) + .onErrorResume(e -> Flux.empty()); + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public Mono sHasKey(String key, Object value) { + return redisTemplate.opsForSet().isMember(key, value).doOnError(Throwable::printStackTrace).onErrorReturn(false); + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public Mono sSet(String key, Object... values) { + return redisTemplate.opsForSet().add(key, values).doOnError(Throwable::printStackTrace).onErrorReturn(0L); + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public Mono sSetAndTime(String key, long time, Object... values) { + return redisTemplate.opsForSet().add(key, values).doOnError(Throwable::printStackTrace) + .flatMap(count -> time > 0 ? expire(key, time).thenReturn(count) : Mono.just(count)) + .onErrorReturn(0L); + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public Mono sGetSetSize(String key) { + return redisTemplate.opsForSet().size(key).doOnError(Throwable::printStackTrace).onErrorReturn(0L); + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public Mono setRemove(String key, Object... values) { + return redisTemplate.opsForSet().remove(key, values).doOnError(Throwable::printStackTrace).onErrorReturn(0L); + } + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public Flux lGet(String key, long start, long end) { + return redisTemplate.opsForList().range(key, start, end).doOnError(Throwable::printStackTrace) + .onErrorResume(e -> Flux.empty()); + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public Mono lGetListSize(String key) { + return redisTemplate.opsForList().size(key).doOnError(Throwable::printStackTrace).onErrorReturn(0L); + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Mono lGetIndex(String key, long index) { + return redisTemplate.opsForList().index(key, index).doOnError(Throwable::printStackTrace) + .onErrorResume(e -> Mono.empty()); + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public Mono lSet(String key, Object value) { + return redisTemplate.opsForList().rightPush(key, value).doOnError(Throwable::printStackTrace) + .map(r -> true) + .onErrorReturn(false); + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public Mono lSet(String key, Object value, long time) { + return redisTemplate.opsForList().rightPush(key, value) + .doOnError(Throwable::printStackTrace) + .flatMap(e -> time > 0 ? expire(key, time).thenReturn(true) : Mono.just(true)) + .onErrorReturn(false); + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public Mono lSet(String key, List value) { + return redisTemplate.opsForList().rightPushAll(key, value) + .thenReturn(true) + .doOnError(Throwable::printStackTrace) + .onErrorReturn(false); + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public Mono lSet(String key, List value, long time) { + return redisTemplate.opsForList().rightPushAll(key, value) + .doOnError(Throwable::printStackTrace) + .flatMap(e -> time > 0 ? expire(key, time).thenReturn(true) : Mono.just(true)) + .onErrorReturn(false); + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public Mono lUpdateIndex(String key, long index, Object value) { + return redisTemplate.opsForList().set(key, index, value).doOnError(Throwable::printStackTrace) + .onErrorReturn(false); + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public Mono lRemove(String key, long count, Object value) { + return redisTemplate.opsForList().remove(key, count, value).doOnError(Throwable::printStackTrace) + .onErrorReturn(0L); + } +}