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

WebSocket+Http实现功能加成

WebSocket+Http实现功能加成

在这里插入图片描述

前言

首先,WebSocket和HTTP是两种不同的协议,它们在设计和用途上有一些显著的区别。以下是它们的主要特点和区别:

HTTP (HyperText Transfer Protocol):

  1. 请求-响应模型: HTTP 是基于请求-响应模型的协议,客户端发送请求,服务器返回响应。这是一个单向通信的模式。

  2. 无状态: HTTP 是无状态的协议,每个请求都是独立的,服务器不会记住之前的请求状态。为了维护状态,通常使用会话(Session)和 Cookie。

  3. 连接短暂: 每个请求都需要建立一个新的连接,然后在响应后关闭。这种短暂的连接模型适用于传统的网页浏览,但对于实时通信则显得不够高效。

  4. 端口: 默认使用端口80进行通信(HTTPS使用端口443)。

WebSocket:

  1. 双向通信: WebSocket 提供全双工通信,允许在客户端和服务器之间建立持久性的双向连接,实现实时数据传输。

  2. 状态: WebSocket 连接是持久性的,服务器和客户端之间可以保持状态。这减少了每次通信时的开销,使其适用于需要频繁交换数据的实时应用。

  3. 协议升级: WebSocket 连接通常通过HTTP协议的升级头部进行初始化,然后升级到WebSocket连接。这样的设计允许在HTTP和WebSocket之间平稳切换,同时在需要时实现更高级的协议升级。

  4. 端口: 默认使用端口80进行非安全通信,使用端口443进行安全通信。

  5. 低开销: 相比于HTTP轮询或长轮询,WebSocket 通信的开销较低,因为它减少了头部信息的传输,同时避免了不必要的连接和断开。

HTTP适用于传统的请求-响应模型,而WebSocket适用于需要实时、双向通信的应用场景,如在线游戏、聊天应用和实时协作工具。在某些情况下,它们可以结合使用,以充分发挥各自的优势。

代码实现

在这里,我们首先确定一个事情,就是这个我们以若依为主要的参考,在若依的基础上进行演示和操作,所以,对于若依这套架子有成见的同志请移步!!我们先创建一个信号量相关处理的工具类,作为辅助工具!

这段 Java 代码是一个用于处理信号量(Semaphore)的工具类,其中包含了获取信号量和释放信号量的方法。信号量是一种用于控制同时访问特定资源的线程数的同步工具。

package com.ruoyi.framework.websocket;import java.util.concurrent.Semaphore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** 信号量相关处理* * @author ruoyi*/
public class SemaphoreUtils
{/*** SemaphoreUtils 日志控制器*/private static final Logger LOGGER = LoggerFactory.getLogger(SemaphoreUtils.class);/*** 获取信号量* * @param semaphore* @return*/public static boolean tryAcquire(Semaphore semaphore){boolean flag = false;try{// 尝试获取信号量,如果成功返回 true,否则返回 falseflag = semaphore.tryAcquire();}catch (Exception e){// 捕获异常并记录日志LOGGER.error("获取信号量异常", e);}return flag;}/*** 释放信号量* * @param semaphore*/public static void release(Semaphore semaphore){try{// 释放信号量,增加可用的许可数semaphore.release();}catch (Exception e){// 捕获异常并记录日志LOGGER.error("释放信号量异常", e);}}
}

解释每个部分的功能:

  1. tryAcquire(Semaphore semaphore) 方法:该方法尝试从信号量中获取一个许可。如果成功获取许可,返回 true;如果无法获取许可,返回 false。在获取信号量时,可能会抛出异常,例如在等待获取信号量的过程中发生中断或超时,因此在方法内捕获异常并记录日志。

  2. release(Semaphore semaphore) 方法:该方法释放一个许可到信号量中,增加信号量的可用许可数。同样,可能会在释放信号量时发生异常,捕获异常并记录日志。

这样的工具类通常用于协调多个线程对共享资源的访问,通过信号量可以限制同时访问某个资源的线程数量,以避免竞争和提高系统的稳定性。在这个类中,异常处理的目的是确保即使在获取或释放信号量的过程中发生异常,也能够进行适当的处理并记录相关信息。

然后呢,我们来编写一个websocket的配置文件,内容很简单,如下:

package com.ruoyi.framework.websocket;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** websocket 配置* * @author ruoyi*/
@Configuration
public class WebSocketConfig
{@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
/************************************************自己增加的内容*******************************************************************/@Beanpublic ServletServerContainerFactoryBean createWebSocketContainer() {ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();// 在此处设置bufferSizecontainer.setMaxTextMessageBufferSize(5120000);container.setMaxBinaryMessageBufferSize(5120000);container.setMaxSessionIdleTimeout(15 * 60000L);return container;}
}

这是一个WebSocket配置类,用于配置WebSocket相关的参数和组件。以下是对每个部分的详细介绍:

  1. @Configuration 注解:

    • 表示这是一个Spring配置类,用于配置WebSocket相关的组件。
  2. @Bean 方法 - serverEndpointExporter:

    • 创建并返回一个ServerEndpointExporter对象。
    • ServerEndpointExporter是Spring提供的用于注册和管理WebSocket端点的Bean,它会在Spring容器中查找所有使用@ServerEndpoint注解的WebSocket端点并注册它们。
    • 这个Bean的存在使得WebSocket端点能够被正确地注册并且可以被使用。
  3. @Bean 方法 - createWebSocketContainer:

    • 创建并返回一个ServletServerContainerFactoryBean对象。
    • ServletServerContainerFactoryBean是Spring提供的用于配置WebSocket容器的工厂Bean。通过配置它,可以设置WebSocket容器的一些参数。
    • 在这个方法中,设置了以下WebSocket容器的参数:
      • setMaxTextMessageBufferSize(5120000): 设置文本消息的最大缓冲区大小为5 MB。
      • setMaxBinaryMessageBufferSize(5120000): 设置二进制消息的最大缓冲区大小为5 MB。
      • setMaxSessionIdleTimeout(15 * 60000L): 设置会话的最大空闲时间为15分钟。

简而言之,这个WebSocket配置类使用Spring的Java配置方式,通过@Bean注解创建了两个Bean,分别是ServerEndpointExporterServletServerContainerFactoryBean。前者用于注册WebSocket端点,后者用于配置WebSocket容器的一些参数。这样,你的Spring Boot应用就能够正确地支持WebSocket了。

然后呢,就到了最主要的内容,我们需要写一个websocket服务类,里面有众多方法

package com.ruoyi.framework.websocket;import java.util.concurrent.Semaphore;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** websocket 消息处理* * @author ruoyi*/
@Component
@ServerEndpoint("/websocket/message")
public class WebSocketServer
{/*** WebSocketServer 日志控制器*/private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);/*** 默认最多允许同时在线人数100*/public static int socketMaxOnlineCount = 100;private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount);/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session) throws Exception{boolean semaphoreFlag = false;// 尝试获取信号量semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore);if (!semaphoreFlag){// 未获取到信号量LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount);WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数:" + socketMaxOnlineCount);session.close();}else{// 添加用户WebSocketUsers.put(session.getId(), session);LOGGER.info("\n 建立连接 - {}", session);LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size());WebSocketUsers.sendMessageToUserByText(session, "连接成功");}}/*** 连接关闭时处理*/@OnClosepublic void onClose(Session session){LOGGER.info("\n 关闭连接 - {}", session);// 移除用户WebSocketUsers.remove(session.getId());// 获取到信号量则需释放SemaphoreUtils.release(socketSemaphore);}/*** 抛出异常时处理*/@OnErrorpublic void onError(Session session, Throwable exception) throws Exception{if (session.isOpen()){// 关闭连接session.close();}String sessionId = session.getId();LOGGER.info("\n 连接异常 - {}", sessionId);LOGGER.info("\n 异常信息 - {}", exception);// 移出用户WebSocketUsers.remove(sessionId);// 获取到信号量则需释放SemaphoreUtils.release(socketSemaphore);}/*** 服务器接收到客户端消息时调用的方法*/@OnMessagepublic void onMessage(String message, Session session){String msg = message.replace("你", "我").replace("吗", "");WebSocketUsers.sendMessageToUserByText(session, msg);}
}

这段代码是一个WebSocket服务器端的实现,用于处理与客户端的WebSocket通信。让我们逐步解释其关键部分:

  1. @Component 注解:

    • 表示将该类作为Spring组件进行管理,可以通过Spring的扫描机制自动识别并注册为bean。
  2. @ServerEndpoint("/websocket/message") 注解:

    • 将该类标记为WebSocket的端点,客户端可以通过访问 “/websocket/message” 路径来与服务器建立WebSocket连接,我们如果需要连接WebSocket,那么连接地址就是:ws:localhost:端口号/websocket/message,类似于http请求!
  3. @OnOpen 注解:

    • 标注一个方法,在WebSocket连接建立时触发。在这里,它用于处理连接建立成功后的逻辑。
    • 尝试获取信号量,如果成功,表示连接建立成功,会将该连接加入到用户列表中;否则,如果在线人数超过限制,会发送错误信息并关闭连接。
  4. @OnClose 注解:

    • 标注一个方法,在WebSocket连接关闭时触发。在这里,它用于处理连接关闭后的清理逻辑,包括移除用户并释放信号量。
  5. @OnError 注解:

    • 标注一个方法,在WebSocket发生异常时触发。在这里,它用于处理异常情况,关闭连接并进行相应的清理工作。
  6. @OnMessage 注解:

    • 标注一个方法,在服务器接收到客户端消息时触发。在这里,它将接收到的消息进行处理,例如将消息中的 “你” 替换为 “我”,去掉 “吗”,然后通过 WebSocketUsers.sendMessageToUserByText 方法将处理后的消息发送回客户端。

总体而言,这个类实现了WebSocket服务器的基本功能,包括连接的建立、关闭、异常处理以及消息的处理。同时,它通过信号量控制了最大允许同时在线人数,确保连接数不超过设定的限制。

代码也很简单,大家在网上也会找到类似的工具类,只不过若依是多加了一些封装

最后,就到了服务升级了,这也是若依特有的,我们一起看看:

package com.ruoyi.framework.websocket;import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.websocket.Session;import com.alibaba.fastjson2.JSON;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** websocket 客户端用户集* * @author ruoyi*/
public class WebSocketUsers
{/*** WebSocketUsers 日志控制器*/private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUsers.class);/*** 用户集*/private static Map<String, Session> USERS = new ConcurrentHashMap<String, Session>();/*** 存储用户** @param key 唯一键* @param session 用户信息*/public static void put(String key, Session session){USERS.put(key, session);}/*** 移除用户** @param session 用户信息** @return 移除结果*/public static boolean remove(Session session){String key = null;boolean flag = USERS.containsValue(session);if (flag){Set<Map.Entry<String, Session>> entries = USERS.entrySet();for (Map.Entry<String, Session> entry : entries){Session value = entry.getValue();if (value.equals(session)){key = entry.getKey();break;}}}else{return true;}return remove(key);}/*** 移出用户** @param key 键*/public static boolean remove(String key){LOGGER.info("\n 正在移出用户 - {}", key);Session remove = USERS.remove(key);if (remove != null){boolean containsValue = USERS.containsValue(remove);LOGGER.info("\n 移出结果 - {}", containsValue ? "失败" : "成功");return containsValue;}else{return true;}}/*** 获取在线用户列表** @return 返回用户集合*/public static Map<String, Session> getUsers(){return USERS;}/*** 群发消息文本消息** @param message 消息内容*/public static void sendMessageToUsersByText(String message){Collection<Session> values = USERS.values();for (Session value : values){sendMessageToUserByText(value, message);}}/*** 发送文本消息** @param userName 自己的用户名* @param message 消息内容*/public static void sendMessageToUserByText(Session session, String message){if (session != null){try{session.getBasicRemote().sendText(message);}catch (IOException e){LOGGER.error("\n[发送消息异常]", e);}}else{LOGGER.info("\n[你已离线]");}}
/************************************************自己增加的内容***************************************************************//*** 群发消息文本消息** @param messages 消息内容*/public static void sendMessageToUsers(List<String> messages, Collection<Session> values) {for (String message : messages) {for (Session value : values) {sendMessageToUserByText(value, message);}}}public static void sendMessageToUsersMap(List<Map<String, Object>> li, Collection<Session> values) {for (Map<String, Object> map : li) {for (Session value : values) {sendMessageToUserByText(value, JSON.toJSONString(map));}}}/*** 获取指定用户** @param userIds 用户id* @return*/public static Collection<Session> getSessionUserMap(List<Long> userIds) {Map<String, Session> sessionUserMap = new HashMap<>();if (CollectionUtils.isNotEmpty(userIds)) {List<String> newUserIds = userIds.stream().map(String::valueOf).collect(Collectors.toList());Map<String, Session> users = USERS;for (Iterator<Map.Entry<String, Session>> it = users.entrySet().iterator(); it.hasNext(); ) {Map.Entry<String, Session> item = it.next();String key = item.getKey();// 发送用户处理if (newUserIds.contains(key.substring(0, key.indexOf("_")))) {sessionUserMap.put(key, item.getValue());}}}return sessionUserMap.values();}/*** 给用户发消息** @param message 消息内容* @param userId  用户id*/public static void sendMessageToUser(String message, Long userId) {List<Long> userList = new ArrayList<>();List<String> msgs = new ArrayList<>();// 添加发送对象userList.add(userId);// 添加发送内容msgs.add(message);Collection<Session> sessionUserMap = WebSocketUsers.getSessionUserMap(userList);WebSocketUsers.sendMessageToUsers(msgs, sessionUserMap);}
}

这段代码定义了一个用于管理WebSocket用户的工具类 WebSocketUsers

  1. put 方法:

    • 用于将用户信息存储到USERS集合中,其中key是用户的唯一标识,session是与用户连接关联的Session对象。
  2. remove 方法 (两个重载):

    • USERS集合中移除用户。一个版本是通过Session对象移除,另一个版本是通过用户的唯一键移除。
    • 首先检查是否包含给定的Session,然后根据情况找到对应的键,最后移除用户。
  3. getUsers 方法:

    • 返回当前在线用户的集合,即USERS集合。
  4. sendMessageToUsersByText 方法:

    • 用于向所有在线用户发送文本消息。遍历USERS集合中的每个用户的Session对象,并调用sendMessageToUserByText方法发送消息。
  5. sendMessageToUserByText 方法:

    • 向指定用户的Session发送文本消息。
    • 如果session不为null,使用session.getBasicRemote().sendText(message)发送文本消息;否则,记录用户已离线的信息。
  6. sendMessageToUsers 方法:

    • 向一组用户发送消息,接收一个包含消息的列表和一个包含Session对象的集合。
    • 遍历消息列表和Session集合,为每个用户的Session对象发送相应的消息。
  7. sendMessageToUsersMap 方法:

    • 向一组用户发送包含Map<String, Object>消息的列表。
    • 将每个Map对象转换为JSON格式的字符串,并使用sendMessageToUserByText方法发送给每个用户。
  8. getSessionUserMap 方法:

    • 根据给定的用户id列表,返回相应用户的Session对象集合。
    • 使用用户id列表过滤出匹配的Session对象,并将其存储在sessionUserMap中返回。
  9. sendMessageToUser 方法:

    • 向指定用户发送消息,接收消息内容和目标用户的id。
    • 创建包含目标用户id和消息内容的列表,然后通过getSessionUserMap方法获取匹配的Session对象集合,并使用sendMessageToUsers方法发送消息。

这些方法共同构成了一个WebSocket用户管理类,用于存储用户信息、发送消息,以及一些特定需求的消息发送,如向指定用户发送消息、向特定用户组发送消息等。

这样,我们就大概完成了整个代码逻辑,也不是非常复杂!

然后,我们就需要进行测试一波----------

ApiPost测试

在这里插入图片描述

在线工具测试 https://wstool.js.org/

在这里插入图片描述

控制台日志

在这里插入图片描述
然后,大家会问,怎么实现http功能加成,其实大家可以看到在WebSocketUsers有需要业务层的处理方法,其实这些就是供http请求调用的

如:
在这里插入图片描述
这就是专门提供给http调用的,实现给指定用户发送消息,如消息通知,或者是公告,审批消息提醒等————
完毕,感谢大家阅读!

所谓好运,所谓幸福,显然不是一种客观的程序,而是完全心灵的感受,是强烈的幸福感罢了。
——史铁生

相关文章:

WebSocket+Http实现功能加成

WebSocketHttp实现功能加成 前言 首先&#xff0c;WebSocket和HTTP是两种不同的协议&#xff0c;它们在设计和用途上有一些显著的区别。以下是它们的主要特点和区别&#xff1a; HTTP (HyperText Transfer Protocol): 请求-响应模型&#xff1a; HTTP 是基于请求-响应模型的协…...

go语言实现LRU缓存

go语言实现LRU Cache 题目描述详细代码 题目描述 设计和构建一个“最近最少使用”缓存&#xff0c;该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值)&#xff0c;并在初始化时指定最大容量。当缓存被填满时&#xff0c;它应该删除最近最…...

git的奇特知识点

展示帮助信息 git help -gThe common Git guides are:attributes Defining attributes per pathcli Git command-line interface and conventionscore-tutorial A Git core tutorial for developerscvs-migration Git for CVS usersdiff…...

按键扫描16Hz-单片机通用模板

按键扫描16Hz-单片机通用模板 一、按键扫描的原理1、直接检测高低电平类型2、矩阵扫描类型3、ADC检测类型二、key.c的实现1、void keyScan(void) 按键扫描函数①void FHiKey(void) 按键按下功能②void FSameKey(void) 按键长按功能③void FLowKey(void) 按键释放功能三、key.h的…...

在容器镜像中为了安全为什么要删除 setuid 和 setgid?

在容器镜像中删除 setuid&#xff08;set user ID&#xff09;和 setgid&#xff08;set group ID&#xff09;权限通常是出于安全考虑。这两个权限位允许进程在执行时以文件所有者或文件所属组的身份运行&#xff0c;而不是以调用进程的用户身份运行。 删除 setuid 和 setgid…...

Flink 动态表 (Dynamic Table) 解读

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…...

【原创 附源码】Flutter海外登录--Google登录最详细流程

最近接触了几个海外登录的平台&#xff0c;踩了很多坑&#xff0c;也总结了很多东西&#xff0c;决定记录下来给路过的兄弟坐个参考&#xff0c;也留着以后留着回顾。更新时间为2024年2月8日&#xff0c;后续集成方式可能会有变动&#xff0c;所以目前的集成流程仅供参考&#…...

第70讲axios后端请求工具类封装

axios工具类封装&#xff1a; // 引入axios import axios from axios;// 创建axios实例 const httpService axios.create({// url前缀-http:xxx.xxx// baseURL: process.env.BASE_API, // 需自定义baseURL:http://localhost:80/,// 请求超时时间timeout: 3000 // 需自定义 })…...

【数学建模】【2024年】【第40届】【MCM/ICM】【F题 减少非法野生动物贸易】【解题思路】

一、题目 &#xff08;一&#xff09; 赛题原文 2024 ICM Problem F: Reducing Illegal Wildlife Trade Illegal wildlife trade negatively impacts our environment and threatens global biodiversity. It is estimated to involve up to 26.5 billion US dollars per y…...

第3节、电机定速转动【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍用定时器定时的方式&#xff0c;精准控制脉冲时间&#xff0c;从而控制步进电机速度。 一、计算过程 电机每一步的角速度等于走这一步所花费的时间&#xff0c;走一步角度等于步距角&#xff…...

【51单片机】LCD1602(可视化液晶屏)调试工具的使用

前言 大家好吖&#xff0c;欢迎来到 YY 滴 单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY…...

Netty应用(四) 之 Reactor模型 零拷贝

目录 6.Reactor模型 6.1 单线程Reactor 6.2 主从多线程Reactor (主--->Boss | 从--->Worker | 一主多从机制) 7.扩展与补充 8.Reactor模型的实现 8.1 多线程Reactor模型的实现&#xff08;一个Boss线程&#xff0c;一个Worker线程&#xff09; 8.2 多线程Reactor模…...

Huggingface上传模型

Huggingface上传自己的模型 参考 https://juejin.cn/post/7081452948550746148https://huggingface.co/blog/password-git-deprecationAdding your model to the Hugging Face Hub&#xff0c; huggingface.co/docs/hub/ad…Welcome&#xff0c;huggingface.co/welcome三句指…...

kyuubi 接入starrocks | doris

kyuubi 接入starrocks 一、环境 Hadoop集群 组件版本Hadoop3.1.1spark3.Xzookeeper3.XHive3.X kyuubi 版本 1.7.1 starrocks 2.X   已将kyuubi部署到yarn上&#xff0c;并且接入了spark3引擎&#xff0c;并通过Ambari进行kyuubi组件的管理&#xff0c;下面步骤为新增对sta…...

notepad++成功安装后默认显示英文怎么设置中文界面?

前几天使用电脑华为管家清理电脑后&#xff0c;发现一直使用的notepad软件变回了英文界面&#xff0c;跟刚成功安装的时候一样&#xff0c;那么应该怎么设置为中文界面呢&#xff1f;具体操作如下&#xff1a; 1、打开notepad软件&#xff0c;点击菜单栏“Settings – Prefere…...

HiveSQL——连续增长问题

注&#xff1a;参考文章&#xff1a; SQL连续增长问题--HQL面试题35_sql判断一个列是否连续增长-CSDN博客文章浏览阅读2.6k次&#xff0c;点赞6次&#xff0c;收藏30次。目录0 需求分析1 数据准备3 小结0 需求分析假设我们有一张订单表shop_order shop_id,order_id,order_time…...

使用cocos2d-console初始化一个项目

先下载好cocos2d-x的源码包 地址 https://www.cocos.com/cocos2dx-download 这里使用的版本是 自己的电脑要先装好python27 用python安装cocos2d-console 看到项目中有个setup.py的一个文件 python setup.py 用上面的命令执行一下。 如果执行正常的话回出现上面的图 然后…...

VitePress-13- 配置-title的作用详解

作用描述 1、title 是当前站点的标题&#xff1b;2、默认值是 &#xff1a;VitePress&#xff1b;3、当使用默认主题时&#xff0c;会直接展示在 页面的【导航条】中&#xff1b;4、一个特殊的作用 &#xff1a; 会作为单个页面的默认标题后缀&#xff01;除非又指定了【title…...

Rust-AI todo list 开发体验

之前用AI协助开发了一个Vue模块&#xff0c;感觉意犹未尽&#xff0c;所以决定再让AI 来协助我做一个todo list。 todo list对我来说真是一个刚需&#xff0c;从我决定做一件事情&#xff0c;到这件事情做完&#xff0c;我的todo list不但不会减少&#xff0c;反而会增加。 回…...

2024-02-07(Sqoop,Flume)

1.Sqoop的增量导入 实际工作中&#xff0c;数据的导入很多时候只需要导入增量的数据&#xff0c;并不需要将表中的数据每次都全部导入到hive或者hdfs中&#xff0c;因为这样会造成数据重复问题。 增量导入就是仅导入新添加到表中的行的技术。 sqoop支持两种模式的增量导入&a…...

LDAR管理系统解决方案

1、密封点数量不准确 工业企业LDAR项目多委托第三方进行检测&#xff0c;由于前几年由于检测费较高&#xff0c;为减少开支&#xff0c;很多企业只安排检测公司检测了部分密封点&#xff0c;造成密封点遗漏。也有少数企业为了从中谋私利&#xff0c;虚增密封点。 2、密封点台账…...

[vscode]ssh报错: Resolver error: Error: XHR failedscode错误

场景问题&#xff1a;通过vscode ssh连接远程服务器失败&#xff0c;报错&#xff1a;Resolver error: Error: XHR failedscode&#xff1a; 问题原因&#xff1a;~/.vscode-server/bin/一串数字下的vscode-server-linux-x64.tar.gz由于某种原因无法正常下载 解决方式&#x…...

【Maven】依赖、构建管理 继承与聚合 快速学习(3.6.3 )

文章目录 Maven是什么&#xff1f;一、Maven安装和配置本地配置文件设置idea配置本地maven 二、基于IDEA的Maven工程创建2.1 Maven工程GAVP属性2.2 Idea构建Maven JavaEE工程 三、Maven工程项目结构说明四、Maven核心功能依赖和构建管理4.1 依赖管理和配置4.2 依赖传递和冲突4.…...

Flume安装部署

安装部署 安装包连接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1m0d5O3Q2eH14BpWsGGfbLw?pwd6666 &#xff08;1&#xff09;将apache-flume-1.10.1-bin.tar.gz上传到linux的/opt/software目录下 &#xff08;2&#xff09;解压apache-flume-1.10.1-bin.tar.gz…...

点云从入门到精通技术详解100篇-非结构化道路下无人平台路径规划与运动控制

目录 前言 路径规划方法研究现状 传统规划算法 智能规划算法 规划方法比较...

生成树技术华为ICT网络赛道

9.生成树 目录 9.生成树 9.1.生成树技术概述 9.2.STP的基本概念及工作原理 9.3.STP的基础配置 9.4.RSTP对STP的改进 9.5.生成树技术进阶 9.1.生成树技术概述 技术背景&#xff1a;二层交换机网络的冗余性与环路 典型问题1&#xff1a;广播风暴 典型问题2&#xff1a;MA…...

[HTTP协议]应用层的HTTP 协议介绍

目录 1.前言 2.使用fiddler抓包来观察HTTP协议格式 3.HTTP协议的基本格式 2.1请求 2,1.1首行 2.1.2请求头 2.1.3空行 2.2响应 2.2.1首行 2.2.2响应头 键值对 ​编辑2.2.3空行 2.2.4载荷(响应正文) 3.认识URL 3.1关于URL encode 1.前言 我们在前面的博客中,简单的…...

Linux 命令基础

Shell概述 Linux操作系统的Shell作为操作系统的外壳&#xff0c;为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。 Shell是用户和Linux内核之间的接口程序&#xff0c;如果把硬件想象成一个球体的中心&#xff0c;内核围绕在硬件的外层管理着…...

【开源】JAVA+Vue+SpringBoot实现实验室耗材管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…...

集成开发环境 IntelliJ IDEA的基本使用

集成开发环境 IntelliJ IDEA 是由 JetBrains 开发的一个强大的 Java IDE&#xff0c;它也被广泛用于其他编程语言的开发&#xff0c;如 Kotlin、Scala 和 Groovy 等。IntelliJ IDEA 以其智能的代码补全、代码分析、重构工具和强大的调试功能而闻名。以下是 IntelliJ IDEA 的基本…...

【Flink入门修炼】1-2 Mac 搭建 Flink 源码阅读环境

在后面学习 Flink 相关知识时&#xff0c;会深入源码探究其实现机制。因此&#xff0c;需要现在本地配置好源码阅读环境。 本文搭建环境&#xff1a; Mac M1&#xff08;Apple Silicon&#xff09;Java 8IDEAFlink 官方源码 一、 下载 Flink 源码 github 地址&#xff1a;h…...

Spring IoC容器详解

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 基本概念 Spring IoC容器是Spring框架的核心组件&#xff0c;它实现了控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09;的设计原则。IoC是一种编程思…...

06 MP之自动填充+SQL执行的语句和速度分析

1. 自动填充 在项目中有一些属性&#xff0c;比如常见的创建时间和更新时间可以设置为自动填充。 1.1 实例 需求: 将创建时间和更新时间设置为自动填充, 这样每次插入数据时可以不用理会这两个字段 1.1.1 在数据库增加字段 默认开启驼峰映射 createTime --> create_time…...

3 scala集合-Set

与 Java 的 Set 一样&#xff0c;scala 的 set 中&#xff0c;元素都是唯一的&#xff0c;而且遍历 set 中集合的顺序&#xff0c;跟元素插入的顺序是不一样的。 同样&#xff0c;Set 也包含可变和不可变两种。要实现可变 Set 集合&#xff0c;需要使用类 scala.collection.mu…...

Android应用图标微技巧,8.0系统中应用图标的适配

大家好,2018年的第一篇文章到的稍微有点迟,也是因为在上一个Glide系列结束之后一直还没想到什么好的新题材。 现在已经进入了2018年,Android 8.0系统也逐渐开始普及起来了。三星今年推出的最新旗舰机Galaxy S9已经搭载了Android 8.0系统,紧接着小米、华为、OV等国产手机厂…...

java学习(多态)

一、多态 含义&#xff1a;方法或对象具有多种形态。是面向对象的第三大特征&#xff0c;多态是建立在封装和继承基础上的。 多态的具体体现&#xff1a; 1&#xff09;方法的多态 &#xff08;例如重写和重载&#xff09; 2&#xff09;对象的多态 多态注意事项&#xff1…...

[UI5 常用控件] 07.SplitApp,SplitContainer

文章目录 前言1. SplitApp1.1 组件结构1.2 Demo1.3 mode属性 2. SplitContainer 前言 本章节记录常用控件SplitApp&#xff0c;SplitContainer。主要功能是在左侧显示Master页面&#xff0c;右侧显示Detail页面。 Master页面和Detail页面可以由多个Page组成&#xff0c;并支持…...

MyBatisPlus之分页查询及Service接口运用

一、分页查询 1.1 基本分页查询 配置分页查询拦截器 package com.fox.mp.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springfra…...

对象存储minio

参考Linux搭建免费开源对象存储 创建一个data目录 --address和--console-address是MinIO服务器启动命令中的两个参数&#xff0c;它们具有以下区别&#xff1a; --address参数&#xff1a;用于指定MinIO服务器监听的S3 API访问地址。S3 API是用于与MinIO进行对象存储操作的…...

大模型学习笔记二:prompt工程

文章目录 一、经典AI女友Prompt二、prompt怎么做&#xff1f;1&#xff09;注重格式&#xff1a;2&#xff09;prompt经典构成3&#xff09;简单prompt的python询问代码4&#xff09;python实现订阅手机流量套餐的NLU5&#xff09;优化一&#xff1a;加入垂直领域推荐6&#xf…...

MATLAB实现LSTM时间序列预测

LSTM模型可以在一定程度上学习和预测非平稳的时间序列&#xff0c;其具有强大的记忆和非线性建模能力&#xff0c;可以捕捉到时间序列中的复杂模式和趋势[4]。在这种情况下&#xff0c;LSTM模型可能会自动学习到时间序列的非平稳性&#xff0c;并在预测中进行适当的调整。其作为…...

Kubernetes CNI Calico:Route Reflector 模式(RR) calico IPIP切换RR网络模式

1. 概述 Calico 路由反射模式是一种 BGP 互联方案,用于解决大规模网络中路由信息的分发和同步问题。在 Calico 的路由反射模式中,路由反射器(Route Reflectors)被用来集中管理路由信息,以减少网络中的路由信息数量和减小路由信息的分发规模。 在 Calico 的路由反射模式中…...

探索Gin框架:Golang Gin框架请求参数的获取

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。 前言 我们在专栏的前面几篇文章内讲解了Gin框架的路由配置&#xff0c;服务启动等内容。 专栏地址&…...

极值图论基础

目录 一&#xff0c;普通子图禁图 二&#xff0c;Turan问题 三&#xff0c;Turan定理、Turan图 1&#xff0c;Turan定理 2&#xff0c;Turan图 四&#xff0c;以完全二部图为禁图的Turan问题 1&#xff0c;最大边数的上界 2&#xff0c;最大边数的下界 五&#xff0c;…...

word导出链接

java 使用 POI 操作 XWPFDocumen 创建和读取 Office Word 文档基础篇 https://www.cnblogs.com/mh-study/p/9747945.html word标签解析文档 http://www.datypic.com/sc/ooxml/e-w_tbl-1.html...

(delphi11最新学习资料) Object Pascal 学习笔记---第4章第2.5节(重载和模糊调用)

4.2.5 重载和模糊调用 ​ 当调用一个重载的函数时&#xff0c;编译器通常会找到匹配的版本并正确工作&#xff0c;或者如果没有任何重载版本具有正确匹配的参数&#xff08;正如我们刚刚看到的&#xff09;&#xff0c;则会报出错误。 ​ 但还有第三种情况&#xff1a;假设编…...

ElementUI Data:Table 表格

ElementUI安装与使用指南 Table 表格 点击下载learnelementuispringboot项目源码 效果图 el-table.vue&#xff08;Table表格&#xff09;页面效果图 项目里el-table.vue代码 <script> export default {name: el_table,data() {return {tableData: …...

11.2 OpenGL可编程顶点处理:细分着色器

细分 Tessellation Tessellation&#xff08;细分&#xff09;是计算机图形学中的一种技术&#xff0c;用于在渲染过程中提高模型表面的几何细节。它通过在原始图元&#xff08;如三角形、四边形或补丁&#xff09;之间插入新的顶点和边&#xff0c;对图元进行细化分割&#x…...

微软正在偷走你的浏览记录,Edge浏览器偷疯了

虽然现在 Edge 浏览器相当强大&#xff0c;甚至在某种程度上更符合中国用户的使用体验&#xff1b;但最近新的Edge浏览器推出后一直在使用的用户应该有感受到&#xff0c;原本的冰清玉洁的转校生慢慢小鸡脚藏不住了&#xff0c;广告越来越多&#xff0c;越来越流氓了。 电脑之前…...

什么是数据库软删除,什么场景下要用软删除?(go GORM硬删除)

文章目录 什么是数据库软删除&#xff0c;什么场景下要用软删除&#xff1f;go GORM硬删除什么是数据库软删除什么场景下要用软删除 什么是数据库软删除&#xff0c;什么场景下要用软删除&#xff1f; go GORM硬删除 使用的是 GORM&#xff0c;默认启用了软删除功能&#xff…...