工具类部分内容

package com.hwd.campus.common.redis.utils;

import com.hwd.campus.common.redis.constant.RedisKeyPrefixConst;
import com.hwd.campus.common.redis.service.RedisListSelect;
import com.hwd.campus.common.redis.service.RedisSelect;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.connection.stream.Record;
import org.springframework.data.redis.connection.stream.StreamInfo;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component; import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; /**
* @author
* @datetime 2023-01-11 09:25:52
* @description
*/
@Component
@AllArgsConstructor
public class RedisUtils { private RedisTemplate<String, Object> redisTemplate;
private StringRedisTemplate stringRedisTemplate;
private static final Long DAY_SECONDS = 60 * 60 * 24L;
private static final Long SEVEN_DAY_SECONDS = 7 * DAY_SECONDS; public StreamInfo.XInfoGroups groups(String key) {
return stringRedisTemplate.opsForStream().groups(key);
} public void addGroup(String key, String groupName) {
stringRedisTemplate.opsForStream().createGroup(key, groupName);
} /**
* 添加流
*
* @param streamKey 流关键
* @param msgContext 上下文
*/
public void addStream(String streamKey, Object msgContext) {
stringRedisTemplate.opsForStream().add(Record.of(msgContext).withStreamKey(streamKey));
}
}

此处采用Stream实现消息队列

创建监听器

package com.hwd.campus.manage.biz.listener;

import com.hwd.campus.common.redis.constant.RedisKeyPrefixConst;
import com.hwd.campus.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component; import javax.annotation.Resource;
import java.time.Duration; /**
* @author
* @datetime 2023-01-14 11:04:28
* @description 消费监听,自动ack
*/
@Slf4j
@Component
public class LogStreamConsumerRunner implements ApplicationRunner, DisposableBean {
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Resource
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Resource
private LogStreamConsumer logStreamConsumer;
@Resource
private RedisUtils redisUtils;
private StreamMessageListenerContainer<String, ObjectRecord<String, String>> streamMessageListenerContainer; @Override
public void run(ApplicationArguments args) {
addConsumeGroup(RedisKeyPrefixConst.OPERATE_LOG_STREAM_KEY, RedisKeyPrefixConst.OPERATE_LOG_CONSUME_GROUP);
addConsumeGroup(RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY, RedisKeyPrefixConst.LOGIN_LOG_CONSUME_GROUP); threadPoolTaskExecutor.setMaxPoolSize(100); // 创建配置对象
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> options =
StreamMessageListenerContainer.StreamMessageListenerContainerOptions
.builder()
// 一次性最多拉取多少条消息
.batchSize(10)
//执行消息轮询的执行器
.executor(this.threadPoolTaskExecutor)
// 消息消费异常的handler
.errorHandler(Throwable::printStackTrace)
//超时时间,设置为0,表示不超时(超时后会抛出异常)
.pollTimeout(Duration.ZERO)
// 序列化器
.serializer(new StringRedisSerializer())
.targetType(String.class)
.build();
//根据配置对象创建监听容器对象
streamMessageListenerContainer = StreamMessageListenerContainer.create(this.redisConnectionFactory, options);
//使用监听容器对象开始监听消费
receiveAutoAck(RedisKeyPrefixConst.OPERATE_LOG_CONSUME_GROUP, RedisKeyPrefixConst.OPERATE_LOG_CONSUME_NAME, RedisKeyPrefixConst.OPERATE_LOG_STREAM_KEY);
receiveAutoAck(RedisKeyPrefixConst.LOGIN_LOG_CONSUME_GROUP, RedisKeyPrefixConst.LOGIN_LOG_CONSUME_NAME, RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY);
//启动监听
streamMessageListenerContainer.start();
} private void receiveAutoAck(String consumeGroup, String consumeName, String streamKey) {
streamMessageListenerContainer.receiveAutoAck(
Consumer.from(consumeGroup, consumeName),
StreamOffset.create(streamKey, ReadOffset.lastConsumed()), this.logStreamConsumer);
} private void addConsumeGroup(String streamKey, String consumeGroup) {
if (redisUtils.hasKey(streamKey)) {
StreamInfo.XInfoGroups groups = redisUtils.groups(streamKey);
if (groups.isEmpty()) {
redisUtils.addGroup(streamKey, consumeGroup);
}
} else {
redisUtils.addGroup(streamKey, consumeGroup);
}
} @Override
public void destroy() {
this.streamMessageListenerContainer.stop();
}
}

进行消费进行日志增加

package com.hwd.campus.manage.biz.listener;

import cn.hutool.json.JSONUtil;
import com.hwd.campus.manage.biz.model.vo.LoginVo;
import com.hwd.campus.manage.biz.service.ILoginLogService;
import com.hwd.campus.manage.biz.service.IOperateLogService;
import com.hwd.campus.common.redis.constant.RedisKeyPrefixConst;
import com.hwd.campus.common.redis.utils.RedisUtils;
import com.hwd.campus.common.web.filter.model.OperateLogModel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.stream.StreamListener;
import org.springframework.stereotype.Component; import java.util.Objects; /**
* @author
*/
@Component
@Slf4j
@AllArgsConstructor
public class LogStreamConsumer implements StreamListener<String, ObjectRecord<String, String>> { private RedisUtils redisUtils;
private IOperateLogService manageOperateLogService;
private ILoginLogService manageLoginLogService; @Override
public void onMessage(ObjectRecord<String, String> message) {
log.info("接受到来自redis的消息");
log.info(("message id " + message.getId().getValue())); String stream = message.getStream();
log.info(("stream " + stream)); Object value = message.getValue();
log.info(("value " + value)); if (RedisKeyPrefixConst.OPERATE_LOG_STREAM_KEY.equals(stream)) {
OperateLogModel operateLogModel = JSONUtil.toBean(message.getValue(), OperateLogModel.class);
manageOperateLogService.addOperateLog(operateLogModel);
} else if (RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY.equals(stream)) {
LoginVo loginVo = JSONUtil.toBean(message.getValue(), LoginVo.class);
manageLoginLogService.addLoginLog(loginVo);
} //消费完毕删除该条消息
redisUtils.streamDelete(Objects.requireNonNull(stream), message.getId().getValue());
}
}

可通过接口往stream里面set值

redisUtils.addStream(RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY, JSONUtil.toJsonStr(loginVo));

Redis Stream消息队列的更多相关文章

  1. 程序员过关斩将--redis做消息队列,香吗?

    Redis消息队列 在程序员这个圈子打拼了太多年,见过太多的程序员使用redis,其中一部分喜欢把redis做缓存(cache)使用,其中最典型的当属存储用户session,除此之外,把redis作为 ...

  2. Redis 做消息队列

    一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现.定义: 生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...

  3. Redis作为消息队列服务场景应用案例

    NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例   一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更 ...

  4. redis resque消息队列

    Resque 目前正在学习使用resque .resque-scheduler来发布异步任务和定时任务,为了方便以后查阅,所以记录一下. resque和resque-scheduler其优点在于功能比 ...

  5. 【springboot】【redis】springboot+redis实现发布订阅功能,实现redis的消息队列的功能

    springboot+redis实现发布订阅功能,实现redis的消息队列的功能 参考:https://www.cnblogs.com/cx987514451/p/9529611.html 思考一个问 ...

  6. 【Redis】php+redis实现消息队列

    在项目中使用消息队列一般是有如下几个原因: 把瞬间服务器的请求处理换成异步处理,缓解服务器的压力 实现数据顺序排列获取 redis实现消息队列步骤如下: 1).redis函数rpush,lpop 2) ...

  7. Lumen开发:结合Redis实现消息队列(1)

    1.简介 Lumen队列服务为各种不同的后台队列提供了统一的API.队列允许你推迟耗时任务(例如发送邮件)的执行,从而大幅提高web请求速度. 1.1 配置 .env文件的QUEUE_DRIVER选项 ...

  8. Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流

    1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...

  9. sping+redis实现消息队列的乱码问题

    使用spring支持redis实现消息队列,参考官方样例:https://spring.io/guides/gs/messaging-redis/ 实现后在运行过程中发现消费者在接收消息时会出现乱码的 ...

  10. go+redis实现消息队列发布与订阅

    在做项目过程中,实现websocket得时候,不知道哪里写的不太合适,客户端消息收到一定程度,剩下的消息收不到,修改了缓冲区大小,还是没有解决问题,后面因为项目结束期比较紧张,没有时间调试消息的时候, ...

随机推荐

  1. 创新+1+1+1+1!筑牢算力底座,助推AI产业繁荣发展!

    近日,ICT中国·2024高层论坛-云原生发展论坛在北京国家会议中心举办.天翼云出席<城市算力互联网实践指南>编制工作启动仪式.AI Cloud人工智能云服务标准体系阶段性成果发布仪式.算 ...

  2. 3 x 2 + 1 !安 全 能 力 权 威 认 可 !

    近日,由XOps大会组委会主办的"2024第三届XOps产业创新发展论坛"在北京召开.大会主论坛公布了2024上半年XOps最新评估结果,天翼云顺利通过ITU DevOps国际标准 ...

  3. 多个tomcat启停脚本server.sh

    vi server.sh #!/bin/bash export JAVA_HOME=/u01/java_home/jdk1.8.0_181 export JRE_HOME=${JAVA_HOME}/j ...

  4. P9869 [NOIP2023] 三值逻辑 题解

    NOIP2023 T2 三值逻辑 题解 题面 思路 乍一看好像很并查集,而且不太难,但是, 注意到:按顺序运行这 \(m\) 条语句 事情并没有那么简单. 比如说如下情况: x1:=T x2:=x1 ...

  5. [Ynoi2016] 镜中的昆虫 题解

    难度在最近遇到的题里相对较高,在这里写一篇珂学题解. (以下是学校给的部分分) \(20\%\):直接暴力枚举. 另外 \(20\%\):假如我们取 \(pre\),对于 \(pre<l\) 的 ...

  6. Android app:回调方式实现Service向activity传递数据

    一.开启服务的时候,如果我们是通过bindService来绑定服务并且要向服务传递数据,可以直接在Intent中设置bundle来达到效果,但是如果是我们需要从服务中返回一些数据到Activity中的 ...

  7. 替换JSONObject某个对象的值

    有时候我们只想替换JSONObject某个对象的值,不想把所有对象的值都列出来.那就用for循环把所有的值重新赋值一遍.再单独给需要赋值的对象重新赋值 JSONObject itemObject = ...

  8. QT5笔记: 29. 文本文件读写

    例子:主要讲了 QFile .QTextStream 进行文本文件读写 MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include ...

  9. stream流中toMap()api和Duplicate key问题

    1.指定key-value,value是对象中的某个属性值. Map<Integer,String> userMap = userList.stream().collect(Collect ...

  10. 机器学习 | 强化学习(1) | 马尔科夫决策过程(MDP)概论

    最近在搞强化学习(Reinforcement Learning),打算把之前写的笔记整理一下 本文基于大卫 希尔维(David Silver)教授的强化学习概论课程,视频中所采用的样例学生马尔科夫链( ...