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的展示, 为了第二次再次打开新闻客户端时能快速显示新闻,需要将数据缓存到数据库中,下次打开可以直接去数据库中获取新闻直 ...
随机推荐
- 一个SMMU内存访问异常的问题
最近碰到棘手的问题: 以太网进行iperf测试时, 发生了SMMU (System Memory Management Unit)访问异常导致内核崩溃. 原本只是内部测试发现, 后面在试验车上也概率性 ...
- 技术分享PPT整理(三):网页渲染流程
在我刚开始学习Web开发的时候,一直有个疑问--我写出的代码究竟是在什么时候发生作用的呢?是不是每次我修改代码网页都随之变化了?当然,现在来看这肯定是一个错误的想法,经过一段时间的工作和学习后,代码到 ...
- 现在 Llama 具备视觉能力并可以在你的设备上运行 - 欢迎使用 Llama 3.2
Llama 3.2 来了!今天,我们欢迎 Llama 系列的下一个版本加入 Hugging Face.这次,我们很高兴与 Meta 合作发布多模态和小型模型.在 Hub 上提供了十个开源模型 (5 个 ...
- Web渗透_11 补充结语 必看!!
业务逻辑漏洞 在web程序编写时,可能会留下各种各样的漏洞.最常见的就是利用Burpsuit,通过对包的拦截,对内容的修改,来利用了漏洞. 典型的例子就是电商系统.购买商品时,如果在请求包里,将购买数 ...
- uni-app 监听返回按钮
前置条件: 开发环境:windows 开发框架:uni-app , H5+,nativeJS 编辑器:HbuilderX 2.8.13 4. 兼容版本:安卓,IOS已作测试 进入正题: 文档地址uni ...
- .NET 8.0 开源在线考试系统(支持移动端)
前言 推荐一款基于.NET 8.0 免费开源跨平台在线考试系统,系统不仅支持桌面端,还特别优化了移动端的用户体验. 通过本系统可以轻松搭建自己的在线考试平台,实现随时随地的测试与评估. 本文将详细介绍 ...
- 为什么我越来越喜欢用DDD — DDD架构篇(1)
Hello DDD DDD 是一种软件设计方法,DDD 是指导我们做软件工程设计的一种手段.它提供了用切割工程模型的各类技巧,如:领域.界限上下文.实体.值对象.聚合.工厂.仓储等.通过 DDD 的指 ...
- 【转载】scipy.stats.norm.ppf —— 分位点函数(CDF的逆)(也被用作“标准偏差乘数”)
原文地址: https://www.cnblogs.com/jiangkejie/p/15292260.html scipy.stats.norm.ppf() 分位点函数(CDF的逆)(也被用作&qu ...
- ubuntu系统下安装 steam 游戏平台
方法1:安装命令: sudo snap install steam 方法2:下载安装: 地址: https://store.steampowered.com/about/
- Python计算1到100偶数的加和
sum_value = 0 for i in range(1,101): if i % 2 == 1: continue sum_value += i print(sum_value) print(s ...