Springboot结合redis实现关注推送

关注推送

Feed流的模式

Timeline:不做内容筛选,简单的按照内容发布时间排序。常用于好友与关注。例如朋友圈的时间发布排序。

优点:信息全面,不会有缺失。并且实现也相对简单 缺点:信息噪音较多,用户不一定感兴趣,内容获取效率低

智能排序:利用智能算法屏蔽掉违规的、用户不感兴趣的内容。推送用户感兴趣信息来吸引用户。

优点:投喂用户感兴趣信息,用户粘度很高,容易沉迷

缺点:如果算法不精准,可能起到反作用

Timeline里面又有三种模式: 1.拉模式

2.推模式

3.推拉模式

拉模式

Timeline的拉模式(Pull Mode)通常指的是用户端主动请求更新的方式来获取最新动态的一种机制。在社交媒体、问答网站或任何有实时更新内容的应用中,拉模式的工作方式如下:

用户行为:

用户打开应用或刷新页面。 用户选择查看特定用户的动态或时间线。 用户手动下拉刷新(Pull-to-Refresh)来获取新内容。

服务器响应: 服务器接收到用户发起的请求。 根据请求,服务器查询数据库或缓存(如Redis)以获取最新动态。 如果有新的动态,服务器将这些内容发送回客户端。 如果没有新内容,服务器可能返回一个空响应或告知客户端当前无更新。

客户端显示: 客户端接收到新数据后,更新UI显示最新的动态。 如果没有新内容,UI可能会显示一条提示,告诉用户当前内容是最新的。

拉模式的优点包括: 资源效率:只在用户需要时才加载新数据,减少了不必要的网络传输和服务器负载。 控制权:用户可以选择何时获取新信息,提供了更好的用户体验。

缺点则包括: 延迟:用户必须主动操作才能获取新内容,可能会错过实时发生的事件。 频繁请求:如果用户频繁刷新,可能会增加服务器压力和网络流量。 在实际应用中,为了平衡实时性和效率,通常会结合推模式(Push Mode)来实现,比如使用WebSocket或其他长连接技术,当有新动态时服务器可以直接推送给在线用户,而离线用户则可以通过拉模式来获取信息。

推模式

推模式(Push Mode)是一种数据更新机制,其中服务器主动将新数据推送到客户端,而不是等待客户端发起请求。这种方式常用于实时性要求较高的场景,例如即时消息、股票行情、在线协作工具等。以下是推模式的详细描述: 服务器推送: 当服务器上有新的、相关或重要的数据可用时,它会主动将这些数据发送到已连接的客户端。

连接建立: 客户端通常通过持久连接(如WebSocket、Server-Sent Events (SSE) 或其他长连接技术)与服务器保持通信。

实时性: 由于数据是实时推送的,用户可以立即看到更新,无需手动刷新或等待请求响应。

数据传输: 服务器在有新数据时直接通过连接发送,客户端收到数据后立即处理并更新UI。

性能与资源: 推模式可能增加服务器的负载,因为它需要持续监控数据变化并主动推送。 对于客户端,持续的连接可能会消耗更多的电池和网络资源。

用户体验: 提供更好的实时体验,用户可以在数据发生变化时立即得到通知。 可能导致用户设备资源的持续消耗,尤其是对于移动设备。

应用场景: 即时通讯应用,如微信、Slack,服务器会将新消息直接推送给用户。 在线协作工具,如Google Docs,用户可以看到其他协作者的实时编辑。 财经应用,实时推送股票价格变动。

优化与配合: 通常与拉模式结合使用,以平衡实时性和资源消耗。例如,当连接断开时,可以切换到拉模式来获取丢失的数据。 使用推送订阅模型,允许用户仅订阅他们感兴趣的数据。 推模式适合需要实时同步和快速反馈的场景,但需要注意服务器资源和客户端性能的平衡。在设计系统时,通常需要权衡实时性、效率和用户体验。

使用推模式实现关注推送

我们在发布时,查询数据库对应的的粉丝进行推送。

  @Overridepublic Result saveBlog(Blog blog) {// 获取登录用户UserDTO user = UserHolder.getUser();blog.setUserId(user.getId());// 保存探店博文boolean isSuccess = blogService.save(blog);if (!isSuccess){return Result.fail("新增笔记失败");}//查询被关注List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();if (!follows.isEmpty()) {follows.forEach(follow -> {//推送给粉丝String key = "feed:" + follow.getUserId();stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());});}// 返回idreturn Result.ok(blog.getId());}

关注推送滚动分页

该功能主要使用sortSet里面的分数机制

ZREVRANGEBYSCORE feed:1 100000 0 WITHSCORES limit 0 3
# feed:1 为键
# 最大值 100000
# 最小值 0
# WITHSCORES 是否全部展示key和value
# 0 偏移量
# 3 条数

通过上面指令我们可分析出对应的参数:

参数
max :第一次使用当前时间戳 | 第二次上一次查询最小的时间戳
min:0
offset :第一次使用0 | 第二次在上一次结果中,与最小值一样的元素的个数
count:3

具体代码:

  @Overridepublic Result queryBlogOfFollow(Long max, Integer offset) {
//        获取用idLong userId = UserHolder.getUser().getId();
//       获取关注用户的keyString key = "feed:" + userId;
//        获取redis里面的推送数据  ZREVRANGEBYSCORE feed:1 当前时间戳 0 WITHSCORES limit 最后一次统计的值 3Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 2);//判断是否为空if (ObjectUtil.isNull(typedTuples)||typedTuples.isEmpty()){return Result.ok();}long minTime=0;int count=0;
//        创建list存储blog的idList<Long> ids = new ArrayList<>(typedTuples.size());for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {ids.add(Long.valueOf(typedTuple.getValue()));long time = typedTuple.getScore().longValue();if (time == minTime) {count++;} else {
//            应因为sortSet是有序的所以最后一个及是最小的minTime = time;count = 1;}}String strIds = StringUtil.join(ids, ",");
//        更具id查询对应的blogList<Blog> blogs = blogService.query().in("id", ids).last("ORDER BY FIELD(id," + strIds + ")").list();
//      设置博客点赞for (Blog blog : blogs) {extracted(blog);setBlogLiked(blog);}
//        返回封装数据ScrollResult scrollResult = new ScrollResult();scrollResult.setList(blogs);scrollResult.setOffset(count);scrollResult.setMinTime(minTime);return Result.ok(scrollResult);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/345968.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Transparent 且 Post-quantum zkSNARKs

1. 引言 前序博客有&#xff1a; SNARK原理示例SNARK性能及安全——Prover篇SNARK性能及安全——Verifier篇 上图摘自STARKs and STARK VM: Proofs of Computational Integrity。 上图选自&#xff1a;Dan Boneh 斯坦福大学 CS251 Fall 2023 Building a SNARK 课件。 SNARK…

如何在npm上发布自己的包

如何在npm上发布自己的包 npm创建自己的包 一、一个简单的创建 1、创建npm账号 官网&#xff1a;https://www.npmjs.com/创建账号入口&#xff1a;https://www.npmjs.com/signup 注意&#xff1a;需要进入邮箱验证 2、创建目录及初始化 $ mkdir ufrontend-test $ cd ufron…

Java程序设计————从控制台输入

向控制台输入信息可以借助Scanner扫描器类来实现 语法&#xff1a; Scanner input new Scanner(System.in); 提示 &#xff08;1&#xff09;在使用Scanner类型之前&#xff0c;需要首先指明Scanner类所在的位置&#xff0c;既通过代码 import java.util.Scanner; &…

WordPress 高级缓存插件 W3 Total Cache Pro 详细配置教程

说起来有关 WordPress 缓存插件明月已经发表过不少文章了,但有关 W3 Total Cache Pro 这个 WordPress 高级缓存插件除了早期【网站缓存插件 W3 Total Cache,适合自己的才是最好的!】一文后就很少再提及了,最近因为明月另一个网站【玉满斋】因为某些性能上的需要准备更换缓存…

OpenGauss数据库-5.数据更新

第1关&#xff1a;插入数据 gsql -d postgres -U gaussdb -W "passwd123123" create table student (id integer primary key,name char(20),age integer ); insert into student values(1,"lily",20),(2,lily,21),(3,marry,19); 第2关&#xff1a;删除数…

Nginx | 正向代理与Proxy插件整合

写在前面 &#x1f341;个人主页&#xff1a;微枫Micromaple 在企业开发环境中&#xff0c;局域网内的设备通常需要通过正向代理服务器访问互联网。正向代理服务器充当中介&#xff0c;帮助客户端请求外部资源并返回结果。局域网内也就是我们俗称的内网&#xff0c;局域网外的互…

Qt——控件

目录 概念 QWidget核心属性 enabled geometry WindowFrame的影响 windowTitle windowIcon qrc的使用 windowOpacity cursor font toolTip focusPolicy ​编辑 styleSheet 按钮类控件 PushButton RadioButton CheckBox 显示类控件 Label textFormat pixm…

Flink的简单学习四

一 有状态计算 1.1 概念 1.状态;上一次计算的结果 2.需要基于上一个结果来进行计算&#xff0c;被称为有状态计算 1.2 未使用有状态计算 1.下面这个代码将相同的key发送到同一个task任务里面计算。就是因为这个导致了&#xff0c;明明之前没有输入b&#xff0c;但是输入b之…

Linux 安装ab测试工具

yum -y install httpd-tools ab -help #10个并发连接&#xff0c;100个请求 ab -n 200 -c 100 http://www.baidu.com/

【最新鸿蒙应用开发】——总结ArkUI生命周期

鸿蒙ArkUI相关的生命周期都有哪些? 1. UIAbility生命周期 onCreate、onWindowStageCreate、onForeground、onBackground、onWindowStageDestroy、onDestroy。 onCreate&#xff1a;Create状态为在应用加载过程中&#xff0c;UIAbility实例创建完成时触发&#xff0c;系统会调…

面试官:Spring如何解析配置类

你好&#xff0c;我是柳岸花开。 大家好&#xff0c;今天我们来深入探讨一下Spring框架中的配置类解析与扫描过程的源码。Spring作为Java开发中最为广泛使用的框架之一&#xff0c;其核心机制一直是开发者关注的焦点。本文将带领大家从源码角度&#xff0c;详细剖析Spring配置类…

自动化测试-Selenium-元素定位

一.元素定位 因为使用selenium进行自动化测试&#xff0c;元素定位是必不可少的&#xff0c;所以这篇文章用于自动化测试中的selenium中的元素定位法。 1.根据id属性进行定位&#xff08;id是唯一的&#xff09; id定位要求比较高&#xff0c;要求这个元素的id必须是固定且唯…

【数据结构与算法】使用单链表实现队列:原理、步骤与应用

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 &#x1f384;队列的概念 &#x1f384;为什么要用单链表实现队列 二、单…

Wireshark TS | 应用传输丢包问题

问题背景 仍然是来自于朋友分享的一个案例&#xff0c;实际案例不难&#xff0c;原因也就是互联网线路丢包产生的重传问题。但从一开始只看到数据包截图的判断结果&#xff0c;和最后拿到实际数据包的分析结果&#xff0c;却不是一个结论&#xff0c;方向有点跑偏&#xff0c;…

java web如何调用py脚本文件

Controller public class IndexController {RequestMapping("/pythonTest")ResponseBodypublic String pythonTest(){// 假设你的Python脚本名为script.pyString pythonScriptPath "D:\\project\\c1\\hello.py";ProcessBuilder processBuilder new Proce…

Python电影项目并连数据库的登录系统

目录 1.项目架构 1.1介绍 1.2系统架构 1.3所需依赖包 2.项目的使用 3.项目效果图 3.1登录界面&#xff08;login_ui.py&#xff09;&#xff1a; 3.2点击注册&#xff0c;跳转去注册界面&#xff08;register_ui.py &#xff09; 3.3 movie_util.py文件主要功能是抓取和读取电影…

【内存管理】页表映射

页表的一些术语 现在Linux内核中支持四级页表的映射&#xff0c;我们先看下内核中关于页表的一些术语&#xff1a; 全局目录项&#xff0c;PGD&#xff08;Page Global Directory&#xff09; 上级目录项&#xff0c;PUD&#xff08;Page Upper Directory&#xff09; 中间目…

WordPress 高级缓存插件 W3 Total Cache 开启支持 Brotli 压缩算法

今天明月给大家分享一下 WordPress 高级缓存插件 W3 Total Cache 开启支持 Brotli 压缩算法的教程&#xff0c;在撰写【WordPress 高级缓存插件 W3 Total Cache Pro 详细配置教程】一文的时候明月就发现 W3 Total Cache 已经支持 Brotli 压缩算法了&#xff0c;可惜的是在安装完…

Three.js和Babylon.js,webGL中的对比效果分析!

hello&#xff0c;今天分享一些three.js和babylon.js常识&#xff0c;为大家选择three.js还是babylon.js做个分析&#xff0c;欢迎点赞评论转发。 一、Babylon.js是什么 Babylon.js是一个基于WebGL技术的开源3D游戏引擎和渲染引擎。它提供了一套简单易用的API&#xff0c;使开发…

Anzo 跟单社区现已正式上线!即刻体验无与伦比的强大功能

Anzo 跟单社区现已正式上线! ANZO 跟单社区是一个颠覆性的创新跟单社区平台&#xff0c;作为新一代跟单社区&#xff0c;我们旨在让更多的用户享受跟单交易带来的便捷性和收益性。交易者可以通过跟单社区&#xff0c;学习和分享交易策略&#xff0c;轻松复制交易专家的交易策略…