StreamUtils
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的更多相关文章
- java.lang.NoSuchMethodError: org.springframework.util.StreamUtils.emptyInput()Ljava/io/InputStream;
今天写用spring的MockMvc测试controller的demo时出现了这个错误,条件反射的进行了百度,没有搜到匹配的答案,但给了一些解决问题的思路:首先NoSuchMethodError要不就 ...
- 003-Spring 中的StreamUtils
一.概述 StreamUtils是spring中用于处理流的类,是java.io包中inputStream和outputStream,不是java8中Steam.使用时仅依赖spring-core 二 ...
- Spring 中StreamUtils教程
本文我们介绍StreamUtils类使用.StreamUtils是spring中用于处理流的类,是java.io包中inputStream和outputStream,不是java8中Steam.使用时 ...
- Android之三种网络请求解析数据(最佳案例)
AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...
- CloudNotes之桌面客户端篇:笔记撰写样式的支持
最近在CloudNotes桌面客户端中新增了笔记撰写样式的功能.当用户新建笔记的时候,可以在输入笔记标题的同时,选择笔记撰写样式,由安装包默认提供的样式主要有默认样式(Default).羊皮纸样式(L ...
- 从无到有实现登录功能以及thinkphp怎么配置数据库信息
好开心,终于解决了.从学习android到现在写登录功能已经不是一次两次了,如今再写想着肯定是信手拈来,没有想到的是尽然折磨了我一天的时间才搞定它.唉...... 先来看几张截图,这次的登录跟以往的不 ...
- Android的Handler机制
Handler机制的原理 Android 的 Handler 机制(也有人叫消息机制)目的是为了跨线程通信,也就是多线程通信.之所以需 要跨线程通信是因为在 Android 中主线程通常只负责 UI ...
- 解析文件+AcitonBar展示:
//项目效果:
- Android中获取选择图片与获取拍照返回结果差异
导语: 如今的安卓应用在选择图片的处理上大多合并使用拍照和从相册中选择这两种方式 今天在写一个这样的功能时遇到一个尴尬的问题,同样是拍照获取图片功能,在不同手机上运行的效果不一样,下面是在某型手机上测 ...
- android 从服务器获取新闻数据并显示在客户端
新闻客户端案例 第一次进入新闻客户端需要请求服务器获取新闻数据,做listview的展示, 为了第二次再次打开新闻客户端时能快速显示新闻,需要将数据缓存到数据库中,下次打开可以直接去数据库中获取新闻直 ...
随机推荐
- LinearRegression线性回归
1.LinearRegression将方程分为两个部分存放,coef_存放回归系数,intercept_则存放截距,因此要查看方程,就是查看这两个变量的取值. 2.回归系数(regression co ...
- 2021年8月国产数据库排行榜:TiDB稳榜首,达梦返前三,Kingbase进十强,各厂商加速布局云生态
8月份的国产数据库流行度排行榜新鲜出炉.本月共有139个数据库参与了排名. 先来看看排行榜前五名.PingCAP的TiDB分数连续第二个月上涨,总分达到630.21,以136.48的分数差拉开了与第二 ...
- 小程序的image组件
mode属性:用来制定图片的裁剪和缩放模式:常用属性如下:
- 洛谷P1381单词背诵
单词背诵 题目描述 灵梦有 \(n\) 个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由 \(m\) 个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一 ...
- 基础控件(Button,Edittext,ImageView,ProgressBar,ToolBar,AlertDialog,PopupWindow)
Button 触发事件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns: ...
- vite 设置网络代理
参考文档:vite 官网.node-http-proxy 完整示例: export default defineConfig({ server: { proxy: { // 字符串简写写法 '/foo ...
- style="word-break: break-all;" 用于 对应 td 文本内容过长自适应换行适用
style="word-break: break-all;" 用于 对应 td 文本内容过长自适应换行适用 <td style="word-break: break ...
- 【问题解决】java.lang.SecurityException: JCE cannot authenticate the provider BC
问题复现 历史项目升级JDK(由1.7升级到8),进行加密/解密时出现报错java.lang.SecurityException: JCE cannot authenticate the provid ...
- 2023NOIP A层联测31 T4 民主投票
2023NOIP A层联测31 T4 民主投票 思维好题. 思路 首先可以设 \(s\) 每个人最多获得的票数,一开始所有点都把自己的票投给自己父亲. 如果一个点的票数超过 \(s\) 了,那么这个点 ...
- [ATCoder] Cyclic GCDs - 神圣的数学题
Cyclic GCDs 题面 [题目描述] 给定一个长为 \(N\) 的序列 \(a_1,a_2,\dots,a_N\). 设一个置换 \(p\) 的价值 \(f(p)\) 为每个轮换中最小的 \(a ...