SpringBootWeb 篇-入门了解 Spring Cache 、Spring Task 与 WebSocket 框架

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 Spring Cache 概述

        1.1 Spring Cache 具体使用

        1.1.1 引入依赖

        1.1.2 Spring Cache 相关注解的介绍

        2.0 Spring Task 概述

        2.1 cron 表达式

        2.2 Spring Task 使用步骤

        3.0 WebSocket 概述

        3.1 WebSocket 与 HTTP 的区别

        3.2 WebSocket 实现定时给客户端推送数据任务的步骤


        1.0 Spring Cache 概述

        Spring Cache 是 Spring 框架通过对方法调用结果进行缓存管理的技术。Spring Cache 提供了一种简单易用的方法来减少方法的调用时间,提高系统性能。

        Spring Cache 通过将方法调用的结果缓存在缓存中,下次再次调用该方法时,直接从缓存中取数据,避免了重复计算,减少了系统的负担和资源消耗。

        Spring Cache 支持多种缓存提供器,包括 Ehcache、Guava Cache、Caffeine、Redis等,开发者可以根据实际需求选择合适的缓存提供器来进行缓存管理。

        简单来说,Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现。

        1.1 Spring Cache 具体使用

        1.1.1 引入依赖

        引入 Spring Cache 的依赖:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>

        还需引入缓存中间件的依赖,这里使用的是 Redis 的中间件:因此引入 Redis 的依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

        接着就要在 application.yml 配置文件中配置 Redis 相关的信息:

  redis:host: localhostport: 6379password: 123456database: 0

        1.1.2 Spring Cache 相关注解的介绍

        提供了几个常用的注解来管理方法调用的结果缓存。

        1)@EnableCacheing:开启缓存注解功能,通常加在启动类上。

代码演示:

 

        2)@Cacheable:在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,则会调用方法并将方法的返回值放到缓存中。

代码演示:

        举个例子:根据 id 来查询用户信息,当前的 Redis 中是不存在用户信息的。

现在要根据 id 查询用户信息,首先会查询缓冲中是否有相关的数据,如果没有就会到数据库中进行查询相关的数据:

    @Autowiredprivate UserMapper userMapper;@GetMapping@Cacheable(cacheNames = "user",key = "#id")public User getById(Long id){User user = userMapper.getById(id);return user;}

使用 Postman 发送请求:

 当请求发送到服务端,先根据 (cacheNames = "user",key = "#id") 查询 Redis 缓存是否存在相应的数据,当前是第一次查询,因此缓存不存在相应的数据,所以会到数据库中查询数据,查询之后,会将结果自动放入到 Redis 缓存中,那么下一次查询相同的数据,就会直接从 Redis 缓存中获取到。

第一次查询之后,Redis 缓存中的数据:

 

        3)@CachePut:将方法的返回值放到缓存中。

举个例子:新增的用户数据之后,就可以直接将数据放入到 Redis 缓存中。

代码演示:

    @Autowiredprivate UserMapper userMapper;@PostMapping@CachePut(cacheNames = "user",key = "#user.id")public User save(@RequestBody User user){userMapper.insert(user);return user;}

使用 Postman 发送请求:

        当发送请求之后,服务端就会给数据添加到数据库中,接着将返回值放到 Redis 缓存中来。

新增完之后的 Redis:

        4)@CacheEvict:将一条或多条数据从缓存中删除。

举个例子:

        删除一条数据:当从数据库中删除用户的数据,那么缓存中的该用户的数据也要删除。

代码演示:

    @Autowiredprivate UserMapper userMapper;@DeleteMapping@CacheEvict(cacheNames = "user",key = "#id")public void deleteById(Long id){userMapper.deleteById(id);}

使用 Postman 来发送请求:

删除之前的 Redis 的数据:

删除之后的 Redis 的数据:

        删除多条数据:删除 user/ 下的全部数据。

代码演示:

    @Autowiredprivate UserMapper userMapper;@DeleteMapping("/delAll")@CacheEvict(cacheNames = "user",allEntries = true)public void deleteAll(){userMapper.deleteAll();}

        2.0 Spring Task 概述

        Spring Task 是 Spring 框架提供的任务调度工具,可以按照约定时间自动指定某个代码逻辑。

        2.1 cron 表达式

        cron 表达式其实就是一个字符串,通过 cron 表达式可以定义任务触发的时间,构成规则:分为 6 或 7 个域,由空格分隔开,每个域代表一个含义。每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)。

举个例子:2024年6月16日上午10点整对应的 cron 表达式:0 0 10 16 6 ?2024

        1)可以使用工具来根据需求来生成相应的 cron

        cron 表达式在线生成器:Cron - 在线Cron表达式生成器 (ciding.cc)

相关的说明:

 

        2.2 Spring Task 使用步骤

        1)导入 maven 坐标

        包含在 Spring-boot-starter jar 包中,因此不需要引入额外的 jar 包了。

        2)启动类添加注解 @EnableScheduling 开启任务调度

        3)自定义定时任务类

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.Date;@Component
@Slf4j
public class MyTask {@Scheduled(cron = "0/5 * * * * ? ")public void runTask(){log.info("定时任务开始执行:{}",new Date());  }}

        定义一个定时类,该类需要交给 Spring 容器管理,因此需要加上 @Component 注解。在类中定义的方法为:需要定时执行的具体任务,通过 @Scheduled(cron = "") 注解来指定具体的时间。

运行结果:

        3.0 WebSocket 概述

        WebSocket 是一种基于 TCP 协议的网络通信协议,可以实现客户端和服务器之间双向通信。相对于传统的 HTTP 协议,WebSocket 具有更低的延迟和更少的网络开销。通过 WebSocket,客户端和服务器可以建立持久性的连接,实现实时的双向数据传输,而无需每次请求都建立新的连接。

        WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

        3.1 WebSocket 与 HTTP 的区别

总的来说:

        HTTP 是短连接。

        WebSocket 是长连接。

        HTTP 通信是单向的,基于请求响应模式。

        WebSocket 支持双向通信。

        HTTP 与 WebSocket 底层都是 TCP 连接。

        3.2 WebSocket 实现定时给客户端推送数据任务的步骤

        1)客户端浏览器发送一次握手请求给服务端来请求建立联系。

        主要分为三个部分:

第一部分:向服务器发送建立连接请求。

    var websocket = null;var clientId = Math.random().toString(36).substr(2);//判断当前浏览器是否支持WebSocketif('WebSocket' in window){//连接WebSocket节点websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);}else{alert('Not support websocket')}

        通过 new WebSocket("请求的路径") 来请求与服务端建立联系。

第二部分:回调函数

        自动调用的函数,比如说:当服务端发送的消息,那么客户端就会自动调用接收信息的函数。

    //连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(){setMessageInnerHTML("连接成功");}//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");}

第三部分:客户端调用的函数

        客户端手动调用的函数,比如说:发送消息给服务端。

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function(){websocket.close();}//将消息显示在网页上function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';}//发送消息function send(){var message = document.getElementById('text').value;websocket.send(message);}//关闭连接function closeWebSocket() {websocket.close();}

完整的客户端前端代码:

<!DOCTYPE HTML>
<html>
<head><meta charset="UTF-8"><title>WebSocket Demo</title>
</head>
<body><input id="text" type="text" /><button onclick="send()">发送消息</button><button onclick="closeWebSocket()">关闭连接</button><div id="message"></div>
</body>
<script type="text/javascript">var websocket = null;var clientId = Math.random().toString(36).substr(2);//判断当前浏览器是否支持WebSocketif('WebSocket' in window){//连接WebSocket节点websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);}else{alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(){setMessageInnerHTML("连接成功");}//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function(){websocket.close();}//将消息显示在网页上function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';}//发送消息function send(){var message = document.getElementById('text').value;websocket.send(message);}//关闭连接function closeWebSocket() {websocket.close();}
</script>
</html>

        2)导入 WebSocket 的 maven 坐标。

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

        3)导入 WebSocket 服务端组件 WebSocketServer,用于和客户端进行通信。

        当有客户端发送请求建立连接时,服务端就会通过 @ServerEndpoint("/ws/{sid}") 注解来接收到请求。由于发送请求的客户端不止一个,所以需要用到 map 集合来接收 session 即会话对象。

/*** WebSocket服务*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {//存放会话对象private static Map<String, Session> sessionMap = new HashMap();}

        同样的,服务端也会存在一些回调函数,比如说,当客户端发送消息给服务端,服务端就会自动接收到消息。

    @OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}/*** 连接关闭调用的方法** @param sid*/@OnClosepublic void onClose(@PathParam("sid") String sid) {System.out.println("连接断开:" + sid);sessionMap.remove(sid);}

        也会存在一些手动调用的函数,比如:发送消息给客户端。

    /*** 群发** @param message*/public void sendToAllClient(String message) {Collection<Session> sessions = sessionMap.values();for (Session session : sessions) {try {//服务器向客户端发送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}

完整的服务端代码: 

import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;/*** WebSocket服务*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {//存放会话对象private static Map<String, Session> sessionMap = new HashMap();/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}/*** 连接关闭调用的方法** @param sid*/@OnClosepublic void onClose(@PathParam("sid") String sid) {System.out.println("连接断开:" + sid);sessionMap.remove(sid);}/*** 群发** @param message*/public void sendToAllClient(String message) {Collection<Session> sessions = sessionMap.values();for (Session session : sessions) {try {//服务器向客户端发送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}

         

        4)导入配置类 WebSocketConfiguration,注册 WebSocket 的服务端组件。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** WebSocket配置类,用于注册WebSocket的Bean*/
@Configuration
public class WebSocketConfiguration {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

        5)导入定时任务类 WebSocketTask,定时向客户端推送数据。

import com.itheima.WebSocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;@Component
public class WebSocketTask {@Autowiredprivate WebSocketServer webSocketServer;/*** 通过WebSocket每隔5秒向客户端发送消息*/@Scheduled(cron = "0/5 * * * * ?")public void sendMessageToClient() {webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));}
}

运行结果:

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

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

相关文章

云平台DNS故障导致网站访问卡顿异常排查过程,wireshark、strace等工具在实际问题排查过程中的应用方法

一、问题现象 项目上使用华为私有云&#xff0c;前段时间华为升级云平台后&#xff0c;云上用户反馈业务系统出现卡顿&#xff0c;之前几秒可以刷新出来的页面现在需要几十秒。提供了一个比较明显的url和curl调用方法。 10.213.x.xxx:8082/files/login curl -H "Content-…

LabVIEW开发指针式压力仪表图像识别

系统利用LabVIEW编程实现对指针式压力仪表的读取&#xff0c;通过相机、光源、固定支架等硬件捕捉仪表图像&#xff0c;并通过图像识别技术解析压力值。系统分为两个阶段&#xff1a;第一阶段固定相机更换仪表&#xff0c;第二阶段移动相机识别多个固定仪表。本文介绍硬件选择、…

Jenkins 发测试邮件报错 553 Mail from must equal authorized user

Jenkins 发测试邮件报错 553 Mail from must equal authorized user 报错信息报错原因解决办法 报错信息 org.eclipse.angus.mail.smtp.SMTPSenderFailedException: 553 Mail from must equal authorized user at org.eclipse.angus.mail.smtp.SMTPTransport.mailFrom(SMTPTra…

我工作中用Redis的10种场景

Redis作为一种优秀的基于key/value的缓存&#xff0c;有非常不错的性能和稳定性&#xff0c;无论是在工作中&#xff0c;还是面试中&#xff0c;都经常会出现。 今天这篇文章就跟大家一起聊聊&#xff0c;我在实际工作中使用Redis的10种场景&#xff0c;希望对你会有所帮助。 …

丹尼尔·T·琼斯:精益生产到底是什么?

本文摘要自《精益思想》、《改变世界的机器》作者之一丹尼尔T琼斯的文章。丹尼尔T琼斯是一位学者、英国作家和研究员。他曾多次获得瑞士山吉奥卓越运营奖研究与专业出版类别的奖项&#xff0c;也包括了国际精益六西格玛研究所&#xff08;ILSSI&#xff09;[1]的"精益思想…

【Java】已解决java.sql.SQLException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.sql.SQLException异常 在Java中&#xff0c;java.sql.SQLException是一个通用的异常类&#xff0c;用于表示在数据库操作中发生的错误。无论是类型错误、数据类型不匹配…

Nacos 2.x 系列【15】数据源插件支持达梦、Oracel、PostgreSQL......

文章目录 1. 概述2. 持久层机制2.1 固定语句2.2 数据源插件 3. 案例演示3.1 编译已实现插件3.2 自定义插件3.3 数据库初始化3.4 插件引入3.4.1 方式一&#xff1a;引入到源码3.4.2 方式二&#xff1a;插件加载目录 3.5 修改配置3.6 测试 1. 概述 在实际项目开发中&#xff0c;…

[Linux] 历史根源

UNIX系统&#xff1a; 1969年&#xff0c;由贝尔实验室的K.Thompson和D.M.Ritchie为PDP-7机器编写的一个分时操作系统&#xff0c; 最初使用汇编语言编写&#xff0c; 后来1972年C语言出世以后&#xff0c;二人由使用C写了UNIX3&#xff0c; 此后UNIX大为流行开来 UNIX流派树&a…

vxe-table 列表过滤踩坑_vxe-table筛选

但是这个过滤输入值必须是跟列表的值必须一致才能查到&#xff0c;没做到模糊查询的功能&#xff0c;根据关键字来过滤并没有实现。 下面提供一下具体实现方法&#xff1a;&#xff08;关键字来过滤&#xff09; filterNameMethod({ option, row }) {if (row.name.indexOf(op…

不拼搏不是兄弟的京东,618被指「心眼子」太多上热榜……

好多年不咋公开露面的刘强东&#xff0c;在明尼苏达州事件逐渐不被人提起后&#xff0c;其按捺不住的互联网企业家网红属性&#xff0c;这大半年内&#xff0c;好像又血脉觉醒了……‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 比如在今年618前夕&#xff0c;刘强东因跨国操盘京东&a…

GlusterFS企业分布式存储

GlusterFS 分布式文件系统代表-nfs常见分布式存储Gluster存储基础梳理GlusterFS 适合大文件还是小文件存储&#xff1f; 应用场景术语Trusted Storage PoolBrickVolumes Glusterfs整体工作流程-数据访问流程GlusterFS客户端访问流程 GlusterFS常用命令部署 GlusterFS 群集准备环…

轻松选购指南:如何挑选3D建模和3D渲染的高效计算机?

选择最适合 3D 建模和3D渲染的计算机可能是一项艰巨的任务&#xff0c;特别是对于初学者来说。有很多因素需要考虑&#xff0c;包括处理器、显卡、内存和存储容量。 如果你计划购买一台计算机或利用3D产品渲染服务&#xff0c;那么你必须了解需要考虑的特性。以下是选择3D建模…

中望CAD 2025 (ZW3D2025) 简体中文修改版

名称&#xff1a;中望CAD 2025 (ZW3D2025) 简体中文修改版 描述&#xff1a;一款三维CAD设计工具&#xff0c;运行破解补丁ZW3D2025-2024-Patch执行修补。 链接&#xff1a;夸克网盘分享 &#x1f4c1; 大小&#xff1a;3.2GB &#x1f3f7; 标签&#xff1a;#PC软件 #CAD #设…

项目四 OpenStack身份管理

任务一 理解身份服务 1.1 •Keystone的基本概念 • 认证 &#xff08; Authentication &#xff09; —— 确认用户身份的过程 &#xff0c;又称身份验证 。 • 凭证 &#xff08; Credentials &#xff09; —— 又 称凭据&#xff0c;是用于 确认用户身份的数据 。 • 令牌…

jeecg快速启动(附带本地运行可用版本下载)

版本整理&#xff08;windows x64位&#xff09;&#xff1a; redis&#xff1a;3.0.504 MYSQL&#xff1a;5.7 Maven&#xff1a;3.9.4(setting文件可下载) Nodejs&#xff1a;v16.20.2&#xff08;建议不要安装默认路径下&#xff0c;如已安装在c盘&#xff0c;运行yarn报…

多线程(总结黑马程序员)

一、什么是线程&#xff1f; 是一个程序内部的一条执行流程 多线程是什么&#xff1f; 多条线程由CPU负责调度执行 多线程的创建方式一&#xff1a;继承Thread类 //1.继承Thread类 public class MyThread extends Thread {//2.必须重写run方法Overridepublic void run() {…

机器人学习和研究的物质基础包含哪些内容?

为啥写这个&#xff1f; 在很多博客里面提及物质基础&#xff0c;没想到询问的也非常多&#xff0c;写一篇详细一点的。 之前的故事 不合格且失败机器人讲师个人理解的自身课程成本情况-CSDN博客 迷失自我无缘多彩世界-2024--CSDN博客 物质基础与情绪稳定的关系-CSDN博客 …

Javaweb登录校验

登录校验 JWT令牌的相关操作需要添加相关依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>一、摘要 场景&#xff1a;当我们想要访问一个网站时&am…

Vue开发中Element UI/Plus使用指南:常见问题(如Missing required prop: “value“)及中文全局组件配置解决方案

文章目录 一、vue中使用el-table的typeindex有时不显示序号Table 表格显示索引自定义索引报错信息解决方案 二、vue中Missing required prop: “value” 报错报错原因解决方案 三、el-table的索引值index在翻页的时候可以连续显示方法一方法二 四、vue3中Element Plus全局组件配…

VMware RedHat虚拟机磁盘扩容(添加磁盘和扩展磁盘)

前言 自己的电脑上配一个虚拟机还是很有必要的&#xff0c;用起来比双系统方便一点&#xff0c;之前搞了100g的ubuntu没用到&#xff0c;后面重装redhat觉得随便搞个20g就够用了&#xff0c;后面用到之后就遇到磁盘不够用的情况&#xff0c;只能说情况允许的话&#xff0c;磁盘…