package com.redis.utils;

import com.SpringUtils;
import com.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.connection.stream.Record;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StreamOperations;
import org.springframework.data.redis.core.StringRedisTemplate; import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* redis Stream类型数据操作Dao接口
* @author muzhi
* @author <a href="mailto:maming.zhong2526@nvxclouds.com">Muzhi Zhang</a>
* @version 1.0.0
* @date 2023-12-14 20:45
*/
@Slf4j
public class StreamUtils<T> {
private final StringRedisTemplate stringRedisTemplate;
private final StreamOperations<String,String, T> streamOperations; public StreamUtils() {
this.stringRedisTemplate = SpringUtils.getBean(StringRedisTemplate.class);
this.streamOperations = stringRedisTemplate.opsForStream();
stringRedisTemplate.execute((RedisCallback) RedisConnection::scriptingCommands);
} /**
* 获取当前操作 StreamOperations
* @return
*/
public StreamOperations getStreamOperations() {
return streamOperations;
} /**
*
* @return
*/
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
} /**
* 初始化stream和消费者组
* @param key
* @param group
*/
public void initStream(String key, String group) {
//判断key是否存在,如果不存在则创建
boolean hasKey = true;
if (StringUtils.isNotBlank(key)){
hasKey = stringRedisTemplate.hasKey(key);
}
if(!hasKey){
Map<String,T> map = new HashMap<>();
map.put("field", (T) "value");
String recordId = insertStreamAll(key, map);
createGroup(key,group);
//将初始化的值删除掉
remove(key,recordId); log.debug("stream:{}-group:{} initialize success",key,group);
}
} /**
* 添加消息到末尾
* @param key
* @param field
* @param value
* @return
*/
public String insertStream(String key, String field, T value) {
Map<String, T> content = new HashMap<>(1);
content.put(field, value);
return insertStreamAll(key, content);
} /**
* 批量添加消息到末尾
* @param key
* @param content
* @return
*/
public String insertStreamAll(String key, Map<String, T> content) {
return streamOperations.add(key,content).getValue();
} /**
* 删除消息,这里的删除仅仅是设置了标志位,不影响消息总长度
* 消息存储在stream的节点下,删除时仅对消息做删除标记,当一个节点下的所有条目都被标记为删除时,销毁节点
* @param key
* @param recordIds
* @return
*/
public Long remove(String key, String... recordIds) {
return streamOperations.delete(key,recordIds);
} /**
* 创建消费组
* @param key
* @param group
* @return
*/
public String createGroup(String key, String group) {
return streamOperations.createGroup(key,group);
} /**
* 确认已消费
* @param key
* @param group
* @param recordIds
* @return
*/
public Long ack(String key, String group, String... recordIds) {
return streamOperations.acknowledge(key, group, recordIds);
} /**
* 确认已消费
* @param group
* @param record
* @return
*/
public Long ack(String group, Record<String, ?> record) {
return streamOperations.acknowledge(group, record);
} /**
* 消息长度
* @param key
* @return
*/
public Long len(String key) {
return streamOperations.size(key);
} /**
* 从头开始读
* @param key
* @return
*/
public List<MapRecord<String, String, T>> readByZero(String key) {
return streamOperations.read(StreamOffset.fromStart(key));
} /**
* 从指定的ID开始读
* @param key
* @param recordId
* @return
*/
public List<MapRecord<String, String, T>> readById(String key, String recordId) {
return streamOperations.read(StreamOffset.from(MapRecord.create(key, new HashMap<>(1)).withId(RecordId.of(recordId))));
} /**
* 读取pending 中未处理的数据
* @param key
* @param consumer
* @return
*/
public PendingMessages readWithPending(String key, Consumer consumer) {
//从零到最大,10条数据
// return streamOperations.pending(key, consumer, Range.closed("0", "+"), 10L);
return streamOperations.pending(key, consumer);
} /**
* 读取pending 中未处理的数据
* @param key
* @param group
* @return
*/
public PendingMessagesSummary readWithPending(String key, String group) {
return streamOperations.pending(key, group);
} /**
* 获取消费组信息
* @param key
* @param group
* @return
*/
public StreamInfo.XInfoConsumers getConsumers(String key, String group) { return streamOperations.consumers(key, group);
} /**
* 获取消息列表,会自动过滤已经删除的消息
* @param key
* @param rightOpen
* @return
*/
public List<MapRecord<String, String, T>> getMsgList(String key, Range<String> rightOpen) {
return streamOperations.range(key, rightOpen);
} /**
* 从特定范围内的流中读取记录
* @param key
* @param startId
* @param endId
* @param count
* @return
*/
public List<MapRecord<String, String, T>> range(String key, RecordId startId, RecordId endId, Integer count) { return streamOperations .range(key,
Range.from(Range.Bound.exclusive(startId.getValue())).to(Range.Bound.exclusive(startId.getValue())),
RedisZSetCommands.Limit.limit().count(count));
}
}

StreamUtils的更多相关文章

  1. java.lang.NoSuchMethodError: org.springframework.util.StreamUtils.emptyInput()Ljava/io/InputStream;

    今天写用spring的MockMvc测试controller的demo时出现了这个错误,条件反射的进行了百度,没有搜到匹配的答案,但给了一些解决问题的思路:首先NoSuchMethodError要不就 ...

  2. 003-Spring 中的StreamUtils

    一.概述 StreamUtils是spring中用于处理流的类,是java.io包中inputStream和outputStream,不是java8中Steam.使用时仅依赖spring-core 二 ...

  3. Spring 中StreamUtils教程

    本文我们介绍StreamUtils类使用.StreamUtils是spring中用于处理流的类,是java.io包中inputStream和outputStream,不是java8中Steam.使用时 ...

  4. Android之三种网络请求解析数据(最佳案例)

    AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...

  5. CloudNotes之桌面客户端篇:笔记撰写样式的支持

    最近在CloudNotes桌面客户端中新增了笔记撰写样式的功能.当用户新建笔记的时候,可以在输入笔记标题的同时,选择笔记撰写样式,由安装包默认提供的样式主要有默认样式(Default).羊皮纸样式(L ...

  6. 从无到有实现登录功能以及thinkphp怎么配置数据库信息

    好开心,终于解决了.从学习android到现在写登录功能已经不是一次两次了,如今再写想着肯定是信手拈来,没有想到的是尽然折磨了我一天的时间才搞定它.唉...... 先来看几张截图,这次的登录跟以往的不 ...

  7. Android的Handler机制

    Handler机制的原理 Android 的 Handler 机制(也有人叫消息机制)目的是为了跨线程通信,也就是多线程通信.之所以需 要跨线程通信是因为在 Android 中主线程通常只负责 UI ...

  8. 解析文件+AcitonBar展示:

    //项目效果:

  9. Android中获取选择图片与获取拍照返回结果差异

    导语: 如今的安卓应用在选择图片的处理上大多合并使用拍照和从相册中选择这两种方式 今天在写一个这样的功能时遇到一个尴尬的问题,同样是拍照获取图片功能,在不同手机上运行的效果不一样,下面是在某型手机上测 ...

  10. android 从服务器获取新闻数据并显示在客户端

    新闻客户端案例 第一次进入新闻客户端需要请求服务器获取新闻数据,做listview的展示, 为了第二次再次打开新闻客户端时能快速显示新闻,需要将数据缓存到数据库中,下次打开可以直接去数据库中获取新闻直 ...

随机推荐

  1. 怎么封装axios

    首先,单独创建一个request的js文件,导入axios 然后,创建 axios 实例 request = axios.create 可以写基本地址,超时时间等: 后面可以添加拦截器,可以在请求拦截 ...

  2. 007 Python、Anaconda、pip、Pycharm、Jupyter都是啥?

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  3. 斜率优化DP简单总结&&“土地购买”题解

    今天刚刷完了斜率优化DP,简单从头回顾一下. \[首先,能写出DP方程应该是最重要的,毕竟斜率只是用来优化的 \] 那么一个DP方程能用斜率优化,具备一种形式: \[f[i]+s1[i]+A[i]*B ...

  4. C# 并发控制框架:单线程环境下实现每秒百万级调度

    前言 在工业自动化和机器视觉领域,对实时性.可靠性和效率的要求越来越高.为了满足这些需求,我们开发了一款专为工业自动化运动控制和机器视觉流程开发设计的 C# 并发流程控制框架. 该框架不仅适用于各种工 ...

  5. Cartographer学习——地图概率更新过程

    前言:最近一直在研究建图,对google的开源SLAM框架 Cartographer 进行了源码梳理,发现很多巧妙的算法设计,结合原论文 <Real-time Loop Closure in 2 ...

  6. 顺序表(python)

    文章目录 1.创建顺序表 2.按址查找元素的位置 3.增加元素 3.1在头部增加元素 3.2在尾部增加元素 3.3在中间任意位置增加元素 4.删除元素 4.1删除第一个元素 4.2删除指定的元素 5. ...

  7. 使用最小二乘法进行线性回归(Python)

    已知测得某块地,当温度处于15至40度之间时,数得某块草地上小花朵的数量和温度值的数据如下表所示.现在要来找出这些数据中蕴含的规律,用来预测其它未测温度时的小花朵的数量. 测得数据如下图所示: imp ...

  8. 强化学习性能指标之一:以训练的episodes数和训练所需样本数作为评价算法性能的指标

    在强化学习领域,一般都是限定训练的episodes数和训练所需样本数的,也就是说在进行算法性能对比的时候各个算法都是在相同的训练的episodes数和训练所需样本数的,但是如果我们在算法得分数保持相同 ...

  9. 侯捷C++高级面向对象编程_下_课程笔记

    friend(友元):相同Class的各个objects互为friends(友元) class complex{ public: complex (double r = 0, double I = 0 ...

  10. python 中的[:-1]和[::-1]的具体使用

    案例 a='python' b=a[::-1] print(b) #nohtyp c=a[::-2] print(c) #nhy #从后往前数的话,最后一个位置为-1 d=a[:-1] #从位置0到位 ...