当前位置: 首页 > article >正文

Springboot使用事件流调用大模型接口

什么是事件流

事件流(Event Stream) 是一种处理和传递事件的方式,通常用于系统中的异步消息传递或实时数据流。在事件驱动架构(Event-Driven Architecture)中,事件流扮演着至关重要的角色。

事件流的概念:

  1. 事件(Event)
    事件是指系统中的某个状态变更或者操作的发生。例如,用户点击按钮、订单创建、传感器检测到的温度变化等都可以视为事件。

  2. 事件流(Event Stream)
    事件流是指一系列有序的事件,这些事件按照时间顺序传输并可能被处理。事件流是一个数据流,它将事件按顺序传递给系统中的不同组件或服务。

  3. 流的特性

    • 时间序列:事件流通常按照时间顺序传递,也就是说,先发生的事件会先传递。
    • 异步性:事件流通常是异步的,意味着事件的生产者和消费者之间不一定同步工作,消费者可以在稍后的时间消费事件。
    • 连续性:事件流是一个连续的过程,事件会不断地产生并被处理。

事件流的应用场景:

  1. 日志流
    在现代分布式系统中,日志通常会以事件流的形式处理和传输。例如,系统的操作、错误或者状态变更会作为事件记录下来,并通过事件流传输到日志收集和分析系统中。

  2. 实时数据处理
    事件流在实时数据处理场景中非常重要,比如流式处理框架(例如Apache Kafka、Apache Flink等)就是用于处理不断产生的事件流。这些流可以表示实时的交易、用户活动、传感器数据等。

  3. 消息传递
    在消息队列系统中,消息也可以被视为事件流的一部分。生产者发布消息(事件),消费者接收并处理这些消息。

  4. 事件驱动架构(EDA)
    在事件驱动架构中,系统的各个组件通过事件进行通信。每当一个事件发生时,系统的某个部分会被触发并响应这些事件。

事件流与传统流的不同:

  • 传统流:通常是指一系列数据或任务的流转,它通常是在一定的顺序和时间点进行处理。
  • 事件流:是一种更加灵活的流动方式,侧重于异步传递、处理和反应的模式。事件流中的每个事件通常是独立的、无状态的,并且具有明确的触发条件。

事件流的优势:

  • 解耦:生产者和消费者之间通过事件流进行通信,从而降低了系统组件之间的耦合度。
  • 扩展性:可以通过增加事件消费者来横向扩展系统处理能力。
  • 实时性:适合处理实时数据流,事件流可以实时反映系统中的变化。

事件流的实现方式

(1) Servlet 编程中的响应对象:HttpServletResponse

HttpServletResponse 是经典的 Servlet 编程中的响应对象,可以用于向客户端实时推送数据。主要适用于简单的事件流场景。

实现方式

  • 使用 HttpServletResponse 来直接写数据到客户端。
  • 通常通过长连接保持客户端和服务器之间的连接,以便持续推送事件数据。

示例代码

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/event-stream")
public class EventStreamServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 设置响应头,告知客户端这是一个事件流response.setContentType("text/event-stream");response.setCharacterEncoding("UTF-8");// 获取输出流PrintWriter out = response.getWriter();// 模拟一个简单的事件流int endIndex = 100;while (true) {endIndex--;if( endIndex <= 0 ){break;}out.println("data: " + System.currentTimeMillis());out.println(); // 事件的分隔符out.flush();try {Thread.sleep(1000); // 每秒推送一次事件} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}
}

特点

  • 基本实现:简单地使用 HttpServletResponse 输出流来推送数据。
  • 客户端与服务器之间通过长连接保持数据传输。
  • 没有事件的流控或背压处理,适用于低负载、简单的应用场景。

客户端代码(HTML + JavaScript)

<!DOCTYPE html>
<html>
<head><title>SSE Example</title><script>const eventSource = new EventSource("/sse-stream");eventSource.onmessage = function(event) {console.log("Received event: ", event.data);document.getElementById("output").innerText = event.data;};</script>
</head>
<body><h1>Server Sent Events Example</h1><div id="output"></div>
</body>
</html>

(2) SseEmitter‌

仅需spring-boot-starter-web即可实现基本SSE功能
SSE(Server-Sent Events)是一种基于HTTP的单向通信协议,允许服务器主动推送实时数据到客户端。其核心特点包括轻量级协议、自动重连机制和浏览器原生支持

实现方式

  • 使用 SseEmitter 长连接保持客户端和服务器之间的连接,以便持续推送事件数据。
  • 注意事项
      • ‌超时设置‌:SSE连接默认无超时限制,需显式设置SseEmitter超时参数以避免资源泄漏。
      • ‌‌响应格式‌:确保响应头包含Content-Type: text/event-stream,事件数据需遵循data: \n\n格式。
      • ‌‌连接管理‌:使用ConcurrentHashMap管理客户端连接,及时清理断开或超时的SseEmitter实例。
      • ‌‌异常处理‌:捕获IOException并调用completeWithError()释放资源,避免内存泄漏

示例代码

@RestController
public class SseController {// 使用线程安全集合管理连接private static final ConcurrentHashMap<String, SseEmitter> emitters = new ConcurrentHashMap<>();// 建立SSE连接@GetMapping(value = "/sse/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter connect(@RequestParam String clientId) {// 设置30秒超时(根据业务调整)SseEmitter emitter = new SseEmitter(30_000L);emitters.put(clientId, emitter);// 注册连接清理回调emitter.onCompletion(() -> emitters.remove(clientId));emitter.onTimeout(() -> emitters.remove(clientId));emitter.onError(e -> {log.error("SSE Error: {}", e.getMessage());emitters.remove(clientId);});// 立即发送初始化握手信号try {emitter.send(SseEmitter.event().name("INIT").data("{\"status\": \"CONNECTED\"}"));} catch (IOException e) {emitter.completeWithError(e);}return emitter;}// 消息推送方法(可从其他服务调用)public void pushMessage(String clientId, String message) {SseEmitter emitter = emitters.get(clientId);if (emitter != null) {try {emitter.send(SseEmitter.event().id(UUID.randomUUID().toString()).name("MESSAGE").data(message));} catch (IOException e) {emitter.completeWithError(e);emitters.remove(clientId);}}}
}

特点

  • SseEmitter: 这是一个用于发送事件流的类。每次调用 emitter.send() 时,都会向客户端推送一个新的事件。
  • 线程: 在新线程中模拟事件流的生成,每1秒发送一个事件。你可以根据需要调整事件的生成方式。
  • complete() 和 completeWithError(): 这两个方法分别用于表示事件流的正常结束和错误结束。

客户端代码(HTML + JavaScript)

// 建立连接
const eventSource = new EventSource('/sse/connect?clientId=123');// 监听消息
eventSource.addEventListener('MESSAGE', (e) => {console.log('Received:', JSON.parse(e.data));
});// 错误处理
eventSource.onerror = (err) => {console.error('SSE Error:', err);eventSource.close();  // 手动关闭连接
};

(3) WebFlux 实现事件流

在使用 Spring WebFlux 构建事件流时,可以通过响应式编程的方式实现高效的事件推送。WebFlux 是 Spring 5 引入的响应式编程模块,主要用于构建异步和非阻塞的应用程序。WebFlux 通过 MonoFlux 来表示异步的数据流,可以非常方便地实现事件流推送。

1. WebFlux 实现事件流的核心概念

  • Mono: 表示一个单一的异步值,通常用于返回单个对象或空值。
  • Flux: 表示多个异步值的流,通常用于返回多个对象。

WebFlux 是基于非阻塞 I/O 的,能够在高并发的环境下进行高效的事件流处理。它允许服务器以流的方式向客户端推送数据,特别适用于实时应用,如实时通知、事件推送等。

2. 实现事件流的步骤

下面是如何通过 WebFlux 实现事件流的一个简单示例。

示例:通过 WebFlux 推送事件流
  1. 创建 Spring Boot 项目并添加 WebFlux 依赖
    首先,确保你有一个 Spring Boot 项目,并且在 pom.xml 中包含 WebFlux 依赖:
<dependencies><!-- WebFlux 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- Spring Boot 启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency>
</dependencies>
  1. 创建事件流控制器

在 WebFlux 中,我们可以使用 Flux 来构建一个事件流。Flux 可以通过不同的方式发出多个数据流。在下面的例子中,我们通过每秒钟发出一个新的时间戳来模拟一个事件流。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.Duration;@RestController
public class EventStreamController {@GetMapping("/events")public Flux<String> streamEvents() {// 使用 Flux.interval 每秒钟发送一次事件return Flux.interval(Duration.ofSeconds(1)).map(sequence -> "Event at: " + System.currentTimeMillis());}
}
解释:
  • Flux.interval(Duration.ofSeconds(1)) 创建一个每秒产生一个事件的流。
  • .map() 方法用来将每个时间戳转换成字符串,表示事件数据。
  • 这个流会一直持续下去,直到客户端关闭连接。
  1. 创建客户端来接收事件流
    在客户端,您可以使用 JavaScript 的 EventSource 来接收服务器推送的事件。以下是一个简单的 HTML 页面,展示了如何接收并显示服务器推送的事件:
<!DOCTYPE html>
<html>
<head><title>WebFlux Event Stream</title><script>const eventSource = new EventSource("/events");eventSource.onmessage = function(event) {document.getElementById("event-data").innerText = event.data;};</script>
</head>
<body><h1>WebFlux Event Stream</h1><div id="event-data"></div>
</body>
</html>
解释:
  • EventSource("/events") 会建立一个长连接,接收从 /events 路径推送的事件流。
  • 每次收到事件时,onmessage 事件处理程序会将事件内容显示在页面上。
  • WebFlux 是实现事件流的理想选择,特别是当需要处理高并发、高吞吐量的事件流时。
  • 通过 FluxMono 可以简洁地构建异步事件流。
  • 客户端可以通过 EventSource 实现与服务器的事件流通信,提供实时的推送体验。

3. 运行和测试

  1. 启动 Spring Boot 应用。
  2. 访问 http://localhost:8080/ 查看实时事件流。
  3. 每秒钟,页面会显示当前的时间戳,表示从服务器推送的事件。

4. WebFlux 特点

  • 异步和非阻塞: WebFlux 使用响应式编程模型,处理请求时不会阻塞线程,适合高并发场景。
  • 低延迟: 通过 FluxMono,服务器可以高效地处理多个客户端的事件流。
  • 高可扩展性: 适合构建大规模的实时应用(如实时数据分析、推送通知、直播系统等)。
  • 与传统 Servlet 的区别: WebFlux 与传统的 Servlet API 不同,它支持响应式和非阻塞操作,能够更好地应对高负载和高并发的场景。

实战用法(AI流式问答)

!!!!!更推荐使用WebFlux !!!!

Springboot以智普AI的免费AI问答接口为例

配置webclient

package com.gt.quality.ai;import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;import java.time.Duration;/*** 万里悲秋常作客,百年多病独登台** @author : makeJava*/
@Component
public class AiLocalConfig {HttpClient httpClient = HttpClient.create().// 设置连接超时时间为60秒option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000).//  设置响应超时时间为60秒responseTimeout(Duration.ofMillis(60000)).doOnConnected(con -> con.addHandlerLast(// 设置读取超时时间为60秒new ReadTimeoutHandler(60)// 设置写入超时时间为60秒).addHandlerLast(new WriteTimeoutHandler(60)));/*** 智普AI对话使用接口的处理器* 设置为 5MB缓冲区** @param builder Builder* @return WebClient*/@Bean(name = "useDialogue")public WebClient useDialogue(WebClient.Builder builder) {return builder.baseUrl("https://open.bigmodel.cn/api/paas/v4/chat/completions")// 设置为 5MB.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(5 * 1024 * 1024)).clientConnector(new ReactorClientHttpConnector(httpClient)).build();}
}

接口使用

/*** 事件流---式调用问答*/@RequestMapping(value = "/zhi_pu_say", method = {RequestMethod.GET, RequestMethod.POST}, produces = MediaType.TEXT_EVENT_STREAM_VALUE)@Operation(summary = "流式问答")public Flux<String> testSseInvoke(@RequestParam(value = "question", defaultValue = "2025年国家GPD第一季度的详细情况?", required = false) String question) {log.info("question:{}", question);return zhiPuAiProxyService.streamInvoke(question);}/*** 事件流---式调用问答*/@RequestMapping(value = "/jsonToSay", method = RequestMethod.POST, produces = MediaType.TEXT_EVENT_STREAM_VALUE)@Operation(summary = "流式问答")public Flux<String> jsonToSay(@RequestBody String question) {return zhiPuAiProxyService.streamInvoke(question);}

业务http的流是调用智普AI

@Overridepublic Flux<String> streamInvoke(String question) {// Create a map to store the request bodyMap<String, Object> body = new HashMap<>();// Set the model to "glm-4-flash"body.put("model", "glm-4-flash");// Create a list to store the questionsList<Map<String, Object>> questionList = getAiRoleAndUserBody(question);// Add the list of questions to the request bodybody.put("messages", questionList);// Set the request_id to a random UUIDbody.put("request_id", UUID.randomUUID().toString());// Set the do_sample to truebody.put("do_sample", true);// Set the temperature to 0.95body.put("temperature", 0.95);// Set the stream to truebody.put("stream", true);// Set the max_tokens to 4095body.put("max_tokens", 4095);// Create a map to store the response formatMap<String, Object> responseFormat = new HashMap<>();// Set the type of the response format to "json_object"responseFormat.put("type", "json_object");// Add the response format to the request bodybody.put("response_format", responseFormat);// function、retrieval、web_search。body.put("type", "web_search");try {HttpHeaders headers = new HttpHeaders();headers.set("Content-Type", MediaType.APPLICATION_JSON_VALUE);headers.set("Accept", MediaType.TEXT_EVENT_STREAM_VALUE);headers.set("Accept-Encoding", "gzip, deflate, br");headers.set("Connection", "keep-alive");headers.set("Authorization", "Bearer " + ZhiPuAIConstant.ZHI_PU_AI_API_KEY);// 数据库对话分析return webClient.post().headers(httpHeaders -> httpHeaders.putAll(headers)).bodyValue(JSONUtil.toJsonStr(body)).retrieve().bodyToFlux(String.class).map(s -> s.replaceAll("data:", ""));} catch (Throwable e) {log.error(e.getMessage(), e);return Flux.error(new BusinessSelfException("系统走神了,请稍后再试..."));}}/*** 获取ai角色和用户信息* @param question question* @return*/private List<Map<String, Object>> getAiRoleAndUserBody(String question) {List<Map<String, Object>> questionList = new ArrayList<>();// Create a map to store the first questionMap<String, Object> questionMap = new HashMap<>();// Set the role of the first question to "system"questionMap.put("role", "system");// Set the content of the first questionquestionMap.put("content", "你是一个乐于回答各种问题的小助手,你的任务是提供专业、准确、有洞察力的建议。");// Add the first question to the listquestionList.add(questionMap);// Create a map to store the second questionMap<String, Object> questionMap2 = new HashMap<>();// Set the role of the second question to "user"questionMap2.put("role", "user");// Set the content of the second questionquestionMap2.put("content", question);// Add the second question to the listquestionList.add(questionMap2);return questionList;}

测试接口

在这里插入图片描述

Over

相关文章:

Springboot使用事件流调用大模型接口

什么是事件流 事件流&#xff08;Event Stream&#xff09; 是一种处理和传递事件的方式&#xff0c;通常用于系统中的异步消息传递或实时数据流。在事件驱动架构&#xff08;Event-Driven Architecture&#xff09;中&#xff0c;事件流扮演着至关重要的角色。 事件流的概念…...

计算机网络--2

TCP三次握手 TCP连接为什么需要三次握手 1. 由于网络情况复杂,可能会出现丢包现象,如果第二次握手的时候服务器就认为这个端口可用,然后一直开启,但是如果客户端未收到服务器发送的回复,那么就会重新发送请求,服务器就会重新开启一个端口连接,这样就会浪费一个端口。 三…...

【已解决】WORD域相关问题;错误 未找到引用源;复制域出错;交叉引用域到底是个啥

&#xff08;微软赶紧倒闭 所有交叉引用域&#xff0c;有两个状态&#xff1a;1.锁定。2.手动。可通过编辑->链接查看。 “锁定”状态域的能力&#xff1a; 1. 导出PDF格式稳定&#xff08;【已解决】WORD导出PDF时&#xff0c;参考文献上标自动被取消/变为正常文本_word…...

尤雨溪宣布:Vue 生态正式引入 AI

在前端开发领域,Vue 框架一直以其易用性和灵活性受到广大开发者的喜爱。 而如今,Vue 生态在人工智能(AI)领域的应用上又迈出了重要的一步。 尤雨溪近日宣布,Vue、Vite 和 Rolldown 的文档网站均已添加了llms.txt文件,这一举措旨在让大型语言模型(LLM)更方便地理解这些…...

蓝桥杯第十六届c组c++题目及个人理解

本篇文章只是部分题目的理解&#xff0c;代码和思路仅供参考&#xff0c;切勿当成正确答案&#xff0c;欢迎各位小伙伴在评论区与博主交流&#xff01; 题目&#xff1a;2025 题目解析 核心提取 要求的数中至少有1个0、2个2、1个5 代码展示 #include<iostream> #incl…...

【MVCP】基于解纠缠表示学习和跨模态-上下文关联挖掘的多模态情感分析

多处可看出与同专栏下的DCCMCI很像 abstract 多模态情感分析旨在从多模态数据中提取用户表达的情感信息,包括语言、声学和视觉线索。 然而,多模态数据的异质性导致了模态分布的差异,从而影响了模型有效整合多模态互补性和冗余性的能力。此外,现有的方法通常在获得表征后直…...

Go语言--语法基础4--基本数据类型--类型转换

Go 编程语言中 if 条件语句的语法如下&#xff1a; 1 、基本形式 if 布尔表达式 { /* 在布尔表达式为 true 时执行 */ } If 在布尔表达式为 true 时&#xff0c;其后紧跟的语句块执行&#xff0c;如果为 false 则 不执行。 package main import "fmt"…...

硬件工程师笔记——电子器件汇总大全

目录 1、电阻 工作原理 欧姆定律 电阻的物理本质 一、限制电流 二、分压作用 三、消耗电能&#xff08;将电能转化为热能&#xff09; 2、压敏电阻 伏安特性 1. 过压保护 2. 电压调节 3. 浪涌吸收 4. 消噪与消火花 5. 高频应用 3、电容 工作原理 &#xff08;…...

微软推动智能体协同运作:支持 A2A、MCP 协议

今日凌晨&#xff0c;微软宣布 Azure AI Foundry 和 Microsoft Copilot Studio 两大开发平台支持最新 Agent 开发协议 A2A&#xff0c;并与谷歌合作开发扩大该协议&#xff0c;这一举措对智能体赛道意义重大。 现状与变革意义 当前智能体领域类似战国时代&#xff0c;各家技术…...

Qt模块化架构设计教程 -- 轻松上手插件开发

概述 在软件开发领域,随着项目的增长和需求的变化,保持代码的可维护性和扩展性变得尤为重要。一个有效的解决方案是采用模块化架构,尤其是利用插件系统来增强应用的功能性和灵活性。Qt框架提供了一套强大的插件机制,可以帮助开发者轻松实现这种架构。 模块化与插件系统 模…...

Linxu实验五——NFS服务器

一.NFS服务器介绍 NFS服务器&#xff08;Network File System&#xff09;是一种基于网络的分布式文件系统协议&#xff0c;允许不同操作系统的主机通过网络共享文件和目录3。其核心作用在于实现跨平台的资源透明访问&#xff0c;例如在Linux和Unix系统之间共享静态数据&#…...

RV1126 ROS2环境交叉编译及部署(基于官方Docker)

RV1126 ROS2环境交叉编译及部署(基于官方Docker) 0 前言1 SDK源码更新1.1 启动Docker容器1.2 更新SDK源码1.3 SDK更新问题2 ROS2编译配置3 Buildroot rootfs编译ROS2的依赖包3.1 编译问题解决4 使用Docker交叉编译ROS24.1 准备Linux(Ubuntu) PC机的依赖环境4.1.1 Ubuntu PC机…...

20242817李臻《Linux⾼级编程实践》第9周

20242817李臻《Linux⾼级编程实践》第9周 一、AI对学习内容的总结 第十章 Linux下的数据库编程 10.1 MySQL数据库简介 MySQL概述&#xff1a;MySQL是一个开源的关系型数据库管理系统&#xff0c;最初由瑞典MySQL AB公司开发&#xff0c;后经SUN公司收购&#xff0c;现属于O…...

查看YOLO版本的三种方法

查看YOLO版本的三种方法&#xff1a; 一、通过命令行直接查询 使用Python交互式查询&#xff1a; from ultralytics import __version__ print(__version__) # 示例输出: 11.0.5二、检查PyTorch环境兼容性 import torch, ultralytics print(f"PyTorch: {torch.__versi…...

双流 JOIN 与维表 JOIN 的区别

Flink 双流 JOIN 与维表 JOIN 的区别 1. 数据关联的实时性与更新机制 维表 JOIN 基于当前快照 关联外部存储&#xff08;如 MySQL、HBase&#xff09;的 最新状态&#xff0c;仅反映处理时间的当前数据&#xff0c;历史结果不会随维表更新而修正。无状态回溯 无法关联历史版…...

MySQL OCP和Oracle OCP怎么选?

近期oracle 为庆祝 MySQL 数据库发布 30 周年&#xff0c;Oracle 官方推出限时福利&#xff1a;2025 年 4 月 20 日至 7 月 31 日期间&#xff0c;所有人均可免费报考 MySQL OCP&#xff08;Oracle Certified Professional&#xff09;认证考试&#xff08;具体可查看MySQL OCP…...

汽车为什么需要以太网?带宽?实时?

一、传统总线“堵车”&#xff1a;为什么CAN、LIN扛不住了&#xff1f; 1. 带宽危机 案例&#xff1a;一辆L3级自动驾驶汽车每秒产生约4GB数据&#xff08;激光雷达摄像头&#xff09;&#xff0c;而CAN FD总线最高仅8Mbps。若用CAN传输&#xff0c;需 500秒才能传完1秒的数据—…...

开源分享:TTS-Web-Vue系列:SSML格式化功能与高级语音合成

&#x1f3af; 本文是TTS-Web-Vue系列的第十二篇文章&#xff0c;重点介绍项目新增的SSML格式化功能以及SSML在语音合成中的应用。通过自动格式化和实时预览&#xff0c;我们显著提升了SSML编辑体验&#xff0c;让用户能够更精确地控制语音合成的细节&#xff0c;实现更自然、更…...

[人机交互]理解界面对用户的影响

零.重点 – 什么是情感因素 – 富有表现力的界面 – 用户的挫败感 – 拟人化在交互设计中的应用 – 虚拟人物&#xff1a;代理 一.什么是情感方面 情感是指某事物对心理造成的一种状态 二.计算机科学中存在的两个相关的研究领域 2.1情感计算 机器如何能感知其他代理的情感&…...

FAST-LIO笔记

1.FAST-LIO FAST-LIO 是一个计算效率高、鲁棒性强的激光-惯性里程计系统。该系统通过紧耦合的迭代扩展卡尔曼滤波器&#xff08;IEKF&#xff09;将激光雷达特征点与IMU数据进行融合&#xff0c;使其在快速运动、噪声较大或环境复杂、存在退化的情况下仍能实现稳定的导航。 1…...

软考中级软件设计师——UML(统一建模语言)篇

UML的词汇表包含3种构造块:事物、关系和图。事物是对模型中最具有代表性的成分的抽象;关系把事物结合在一起;图聚集了相关的事物。 一、事物 UML 事物是模型中的基本元素&#xff0c;分为 结构事物、行为事物、分组事物、注释事物。 1. 结构事物 类&#xff08;Class&#x…...

TSN网络与DIOS融合:破解煤矿井下电力系统越级跳闸难题

一、引言 1.1 研究背景与意义 在现代煤矿生产中&#xff0c;井下电力系统作为整个煤矿生产的动力核心&#xff0c;其重要性不言而喻。煤矿井下的各类机械设备&#xff0c;如采煤机、刮板输送机、通风机、排水泵等&#xff0c;都依赖稳定的电力供应才能正常运行。电力系统的稳定…...

python 实现文件批量重命名

以下是使用Python实现文件批量重命名的示例代码。该代码可以将指定目录下的文件按照一定规则进行重命名,这里以将文件重命名为带有编号的文件名为例: import osdef batch_rename(directory):if not os.path.isdir(directory):print(...

SierraNet协议分析使用指导[RDMA]| 如何设置 NVMe QP 端口以进行正确解码

在解码RoCEv2数据包&#xff08;包括TCP RDMA和RoCE RDMA&#xff09;时&#xff0c;若捕获的跟踪数据无法正确解码&#xff0c;通常需要执行特定的解码步骤。对于RoCE RDMA跟踪数据的处理&#xff0c;分析器主要采用两种方式获取必要信息以实现数据包解码&#xff1a; 首先&am…...

Nodejs核心机制

文章目录 前言 前言 结合 Node.js 的核心机制进行说明&#xff1a; 解释事件循环的各个阶段。 答案 Node.js 事件循环分为 6 个阶段&#xff0c;按顺序执行&#xff1a; Timers&#xff1a;执行 setTimeout 和 setInterval 的回调。 Pending I/O Callbacks&#xff1a;处理系…...

Win全兼容!五五 Excel Word 转 PDF 工具解决多场景转换难题

各位办公小能手们&#xff01;今天给你们介绍一款超牛的工具——五五Excel Word批量转PDF工具V5.5版。这玩意儿专注搞批量格式转换&#xff0c;能把Excel&#xff08;.xls/.xlsx&#xff09;和Word&#xff08;.doc/.docx&#xff09;文档唰唰地变成PDF格式。 先说说它的核心功…...

【Bluedroid】HID DEVICE 连接的源码分析

本文分析Android Bluetooth协议栈中HID device设备连接流程的完整实现,从应用层接口到协议栈底层的交互细节。通过关键函数(如connect()、BTA_HdConnect()、HID_DevConnect()等)的代码解析,重点关注btif、bta、HID协议栈三层的协同机制,揭示BTA_HD_CONN_STATE_EVT事件传递…...

【AI大模型】SpringBoot整合Spring AI 核心组件使用详解

目录 一、前言 二、Spring AI介绍 2.1 Spring AI介绍 2.2 Spring AI主要特点 2.3 Spring AI核心组件 2.4 Spring AI应用场景 2.5 Spring AI优势 2.5.1 与 Spring 生态无缝集成 2.5.2 模块化设计 2.5.3 简化 AI 集成 2.5.4 支持云原生和分布式计算 2.5.5 安全性保障…...

Redis的操作以及Spring Cache框架

Redis是一种开源的内存数据结构存储&#xff0c;用作数据库、缓存和消息代理。它支持多种数据结构&#xff0c;如字符串、哈希、列表、集合、有序集合等。在Spring应用中&#xff0c;可以使用Spring Cache框架结合Redis来实现高效的缓存机制。本文将详细介绍Redis的基本操作以及…...

C#输出参数:使用、要求与新特性

在C#编程中&#xff0c;输出参数是一种强大的工具&#xff0c;用于从方法体内把数据传出到调用代码。它的行为与引用参数类似&#xff0c;但也有自己的特点。今天我们就来详细了解一下C#中的输出参数。 输出参数的基本要求 修饰符的使用 输出参数必须在声明和调用中都使用修…...