SpringBoot_websocket实战

news2025/1/12 12:01:02

SpringBoot_websocket实战

  • 前言
  • 1.websocket入门
    • 1.1 websocket最小化配置
      • 1.1.1 后端配置
      • 1.1.2 前端配置
    • 1.2 websocket使用sockjs
      • 1.2.1 后端配置
      • 1.2.2 前端配置
    • 1.3 websocket使用stomp协议
      • 1.3.1 后端配置
      • 1.3.2 前端配置
  • 2.websocket进阶
    • 2.1 websocket与stomp有什么区别
    • 2.2 websocket与stomp怎么选
  • 3.websocket实战
    • 3.1 案例1:websocket 实现web-ssh
    • 3.2 案例2:websocket 实现控制台日志在线展示

前言

本文记录说明springboot websocket示例及实战,你将学习到
三种websocket开发方式

  • /websocket 接口演示原生websocket前后端收发websocket消息
  • /websocket-sockjs 演示使用sockjs 前后端收发websocket消息
  • /weboscket-stomp 演示使用stomp协议使用websocket

以及通过实战演示在不同业务场景的技术选择

  • web-ssh 使用sockjs点对点数据传输
  • 日志项目 使用stomp广播数据

使用环境:

  • springboot: 2.3.2.RELEASE
  • jdk: java11

1.websocket入门

Spring Boot WebSocket是Spring框架的一部分,用于实现WebSocket通信协议的支持。WebSocket是一种双向通信协议,允许服务器与客户端之间进行实时、低延迟的数据交换,适用于实时聊天、实时通知、在线协作和实时数据展示等场景。Spring Boot WebSocket提供了使用WebSocket的简化和高效的方法,让开发者能够轻松地实现WebSocket通信。

以下是Spring Boot WebSocket的主要特点和概念:

  1. WebSocket协议支持: Spring Boot WebSocket支持WebSocket通信协议,允许双向的、实时的通信。WebSocket允许服务器主动向客户端推送数据,而不需要客户端发起请求。
  2. STOMP协议支持: 除了原始WebSocket,Spring Boot WebSocket还支持STOMP(Simple Text Oriented Messaging Protocol)协议。STOMP是一个基于文本的协议,它提供了更高级的消息传递功能,例如消息订阅、目标广播和认证等。
  3. 消息处理器: Spring Boot WebSocket允许你定义消息处理器,用于处理WebSocket消息。你可以编写处理器来处理接收到的消息,并决定如何响应。
  4. 消息代理: Spring Boot WebSocket支持消息代理,你可以配置一个消息代理服务器(如RabbitMQ或ActiveMQ),用于处理WebSocket消息的分发和广播。这使得构建分布式和扩展的WebSocket应用程序更容易。
  5. 消息广播: Spring Boot WebSocket允许你将消息广播到多个订阅者。这对于实现群聊、广播通知和实时数据展示等功能非常有用。
  6. 安全性: Spring Boot WebSocket提供了与Spring Security集成的方式,可以轻松实现WebSocket连接的安全性和认证。
  7. SockJS支持: Spring Boot WebSocket还支持SockJS,这是一个JavaScript库,用于处理浏览器不支持WebSocket的情况下的降级处理,使得WebSocket通信在各种浏览器上都能正常工作

1.1 websocket最小化配置

步骤说明

  • 后端通过@EnableWebSocket注解开启websocket功能
    1. 定义websocket的访问端点 (作用: 定义对外暴露websocket接口)
    2. 定义websocket的处理器 (作用: 解决websocket建立后消息怎么处理)
  • 前端通过new WebSocket(“ws://localhost:9090/websocket”); 打开websocket连接并监听消息

1.1.1 后端配置

  • maven 依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--websocket-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
  • WebSocketConfiguration 实现WebSocketConfigurer注册websocket接口及处理器
@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {

    @Autowired
    private EchoWebSocketHandler echoWebSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 配置原生WebSocket处理器
        registry.addHandler(echoWebSocketHandler, "/websocket")
                .setAllowedOrigins("*"); //允许跨域
    }


    @Bean
    public EchoWebSocketHandler echoWebSocketHandler() {
        return new EchoWebSocketHandler();
    }
}
  • EchoWebSocketHandler 实现WebSocketHandler接口, 接受消息后简单打印转发消息
public class EchoWebSocketHandler implements WebSocketHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(EchoWebSocketHandler.class);
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 连接建立时的处理逻辑
        LOGGER.info("[websocket-echo] session:{} ConnectionEstablished", session.getId());
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws IOException {
        String payload = (String) message.getPayload();
        LOGGER.info("[websocket-echo] session:{} receive:{}", session.getId(), payload);
        session.sendMessage(new TextMessage(payload));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 处理传输错误
    }

    // 连接关闭时的处理逻辑
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        LOGGER.info("[websocket-echo] WebSocketSession[{}] close all ssh connection", session.getId());
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}

1.1.2 前端配置

TODO 说明下WebSocket 对象作用

<!DOCTYPE html>
<html>
<head>
    <title>原始WebSocket示例</title>
</head>
<body>
<h1>测试默认websocket 接发消息</h1>
<div id="messages"></div>
<input type="text" id="message" placeholder="输入消息">
<button onclick="sendMessage()">发送</button>

<script>
    var socket = new WebSocket("ws://localhost:9090/websocket");

    socket.onopen = function(event) {
        console.log("WebSocket连接已打开");
    };

    socket.onmessage = function(event) {
        var messages = document.getElementById("messages");
        messages.innerHTML += "<p>" + event.data + "</p>";
    };

    function sendMessage() {
        var messageInput = document.getElementById("message");
        var message = messageInput.value;
        socket.send(message);
        messageInput.value = "";
    }
</script>
</body>
</html>

1.2 websocket使用sockjs

为了区别原生WebSocket处理器,以示区别,再注册一个接口/websocket-sockjs. 并且开启.withSockJS()

1.2.1 后端配置

@Configuration
@EnableWebSocket
@Import({WebSocketStompConfiguration.class})
public class WebSocketConfiguration implements WebSocketConfigurer {

    @Autowired
    private EchoWebSocketHandler echoWebSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 配置原生WebSocket处理器器
        registry.addHandler(echoWebSocketHandler, "/websocket")
                .setAllowedOrigins("*");
                //WebSocket connection to 'ws://localhost:9090/websocket' failed: Error during WebSocket handshake: Unexpected response code: 200
                //.withSockJS();

        //.withSockJS()的作用是声明我们想要使用 SockJS 功能,如果WebSocket不可用的话,会使用 SockJS。(前端需要使用sockjs库)
        registry.addHandler(echoWebSocketHandler, "/websocket-sockjs")
                .setAllowedOrigins("*")
                .withSockJS();
    }


    @Bean
    public EchoWebSocketHandler echoWebSocketHandler() {
        return new EchoWebSocketHandler();
    }
}

1.2.2 前端配置

使用sockjs需要引入前端sockjs的库: https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js

<!DOCTYPE html>
<html>
<head>
    <title>原始WebSocket示例</title>

		<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
</head>
<body>
<h1>测试websocket sockjs接发消息</h1>
<div id="messages"></div>
<input type="text" id="message" placeholder="输入消息">
<button onclick="sendMessage()">发送</button>

<script>
    // var socket = new WebSocket("ws://localhost:9090/websocket");//原始写法
    var socket = new SockJS('http://localhost:9090/websocket-sockjs');// 依赖sockjs库
    socket.onopen = function(event) {
        console.log("WebSocket连接已打开");
    };

    // 监听websockt消息回调
    socket.onmessage = function(event) {
        var messages = document.getElementById("messages");
        messages.innerHTML += "<p>" + event.data + "</p>";
    };

    // 定义连接关闭时的回调函数
    socket.onclose = function () {
        console.log('WebSocket 连接已关闭');
    };

    // 定义连接错误时的回调函数
    socket.onerror = function (e) {
        console.error('WebSocket 连接出错:', e);
    };

    function sendMessage() {
        var messageInput = document.getElementById("message");
        var message = messageInput.value;
        socket.send(message);
        messageInput.value = "";
    }
</script>
</body>
</html>

1.3 websocket使用stomp协议

步骤说明

  • 启用stomp协议, 通过@EnableWebSocketMessageBroker 并注册stomp的端点
    1. 定义stomp端点 WebSocketStompConfiguration
    2. 配置stomp消息路由 TestWebSocketStompController

1.3.1 后端配置

@EnableWebSocketMessageBroker //在 WebSocket 上启用 STOMP
public class WebSocketStompConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public WebSocketMessageBrokerConfigurer brokerConfigurer() {
		return new WebSocketMessageBrokerConfigurer() {
			/**
			 * stomp 协议,一种格式比较简单且被广泛支持的通信协议,spring4提供了以stomp协议为基础的websocket通信实现。
			 * spring 的websocket实现,实际上是一个简易版的消息队列(而且是主题-订阅模式的)
			 * @param registry
			 */
			@Override
			public void registerStompEndpoints(StompEndpointRegistry registry) {
				// "/stomp-websocket",客户端需要注册这个端点进行链接,
				// .withSockJS()的作用是声明我们想要使用 SockJS 功能,如果WebSocket不可用的话,会使用 SockJS。
				registry.addEndpoint("/websocket-stomp")
						.setAllowedOrigins("*")
						.withSockJS();
				
			}

		};
	}

}
  • 配置消息转发路由
@Controller
public class TestWebSocketStompController {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestWebSocketStompController.class);

    @Autowired
    SimpMessagingTemplate messagingTemplate;

    @GetMapping("/websocket/print/{msg}")
    @ResponseBody
    public String print(@PathVariable String msg) {
        messagingTemplate.convertAndSend("/topic/print", msg);
        return msg;
    }

    @MessageMapping("/app/{destination}") // 使用 {destination} 占位符来捕获动态的目的地
    @SendTo("/topic/print") // 服务器广播消息的目的地
    public String handleMessage(@DestinationVariable String destination, String message) {
        // 处理接收到的消息
        LOGGER.info("Dynamic destination:[{}] Received message:{}", destination, message);
        // 根据动态目的地执行不同的操作
        if ("destination1".equals(destination)) {
            // 处理目的地1的操作
        } else if ("destination2".equals(destination)) {
            // 处理目的地2的操作
        } else {
            // 直接转发到对应订阅地址
            messagingTemplate.convertAndSend("/topic/" + destination, "copy:" + message);
        }

        // 可以根据需要添加更多的条件

        // 返回响应消息
        return message;
    }
}
  • 最后通过@Import导入WebSocketStompConfiguration配置
@Configuration
@EnableWebSocket
@Import({WebSocketStompConfiguration.class})
public class WebSocketConfiguration implements WebSocketConfigurer {

    @Autowired
    private EchoWebSocketHandler echoWebSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 配置原生WebSocket处理器
        registry.addHandler(echoWebSocketHandler, "/websocket")
                .setAllowedOrigins("*");
                //WebSocket connection to 'ws://localhost:9090/websocket' failed: Error during WebSocket handshake: Unexpected response code: 200
                //.withSockJS();

        //.withSockJS()的作用是声明我们想要使用 SockJS 功能,如果WebSocket不可用的话,会使用 SockJS。(前端需要使用sockjs库)
        registry.addHandler(echoWebSocketHandler, "/websocket-sockjs")
                .setAllowedOrigins("*")
                .withSockJS();
    }


    @Bean
    public EchoWebSocketHandler echoWebSocketHandler() {
        return new EchoWebSocketHandler();
    }
}

1.3.2 前端配置

前端依赖sockjs及stomp.min.js的库

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Example</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.2/sockjs.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

</head>
<body>
<h1>测试websocket stomp协议接发消息</h1>
<h2>发送示例</h2>
<input type="text" id="sendDestination" placeholder="Enter send destination">

<input type="text" id="message" placeholder="Enter your message">
<button onclick="sendMessage()">Send Message</button>

<hr>
<h2>订阅示例</h2>
<input type="text" id="listenDestination" placeholder="Enter listen destination">
<button onclick="subscribeToDestination()">Subscribe</button>
<div id="messages"></div>

<script>
    var stompClient = null;
    var listenDestination = null;

    function connect() {
        var socket = new SockJS('/websocket-stomp'); // WebSocket端点
        stompClient = Stomp.over(socket);

        stompClient.connect({}, function (frame) {
            console.log('stomp Connected: ' + frame);
        });
    }

    function sendMessage() {
        var sendDestination = document.getElementById('sendDestination').value; // 获取发送目的地
        var message = document.getElementById('message').value;
        stompClient.send('/app/' + sendDestination, {}, message); // 发送消息到指定的目的地
    }

    function subscribeToDestination() {
        listenDestination = document.getElementById('listenDestination').value; // 获取监听目的地
        stompClient.subscribe('/topic/' + listenDestination, function (message) {
            displayMessage(message.body);
        });
    }

    function displayMessage(message) {
        var messagesDiv = document.getElementById('messages');
        var p = document.createElement('p');
        p.appendChild(document.createTextNode(message));
        messagesDiv.appendChild(p);
    }

    connect();
</script>
</body>
</html>

2.websocket进阶

2.1 websocket与stomp有什么区别

  • WebSocket
    1. WebSocket 是一种通信协议: WebSocket 是一种在Web浏览器和服务器之间提供双向通信的协议。它允许在客户端和服务器之间创建持久性的连接,以便在连接建立后实时地发送和接收消息。
    2. 原始的、低级的协议: WebSocket 是一种相对较低级的协议,它允许在两端之间直接发送原始的消息帧(frames)。这意味着你可以通过WebSocket发送任意的二进制或文本数据。
    3. 需要自行处理消息格式和路由逻辑: WebSocket 本身并没有规定消息的格式或路由逻辑。在WebSocket上发送的消息可以是任意格式的数据,你需要自行定义消息的结构和处理逻辑。
  • STOMP
    1. STOMP 是一种消息协议: STOMP 是一种基于文本的简单消息协议,它定义了客户端和消息代理(broker)之间如何进行交互的规范。STOMP 通常运行在WebSocket之上,它提供了一种在客户端和服务器之间进行实时消息通信的方式。
    2. 面向文本的消息格式: STOMP 消息是文本格式的,它使用类似于HTTP报文的格式来定义消息的头部和体。这种面向文本的格式使得它易于阅读和调试。
    3. 定义了消息的结构和路由逻辑: STOMP 规定了消息的格式和消息目的地的语义。它定义了消息头部的各种属性(例如,目的地、消息类型等),并提供了一种简单的消息路由机制,使得消息能够被发送到特定的目的地。

2.2 websocket与stomp怎么选

如果你期望WebSocket连接之间是隔离的,不需要共享数据,那么使用原始的WebSocket通信是一个合适的选择。原始WebSocket通信提供了一种简单而轻量级的方式,每个连接都是独立的,不会共享会话数据。

STOMP协议通常用于需要高级消息传递功能和消息广播的场景,其中不同连接之间需要共享数据。如果你不需要这种复杂性,原始WebSocket通信足以满足需求,而且更容易理解和维护。

因此,你可以根据你的应用程序需求选择使用原始WebSocket通信或STOMP协议。如果只需要简单的双向通信并希望保持连接之间的隔离,原始WebSocket通信通常是一个更直接的选择

3.websocket实战

3.1 案例1:websocket 实现web-ssh

springboot实现webssh功能, 使用xterm(前端) + websocket + jsch技术实现。后端主要实现websocket消息与jsch命令收发即可。还在开发中, 篇幅关系,实现过程就不写了。有需要点赞或留言,开源后再通知。

在这里插入图片描述

3.2 案例2:websocket 实现控制台日志在线展示

web在线查看springboot后台日志,源码参考:https://github.com/easycode8/easy-log 的easy-log-web模块, 代码量很少。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ThingJS】类型转换以及注册

前言 目前国家提倡加快数字化发展&#xff0c;建设数字中国&#xff0c;并于今年2月份中共中央、国务院印发的《数字中国建设整体布局规划》中明确&#xff0c;数字中国建设按照“2522”的整体框架进行布局。其中提到“构建以数字孪生流域为核心的智慧水利体系”&#xff0c;可…

HarmonyOS(三)—— 应用程序入口—UIAbility

前言 学习过android的同学都是知道Activity&#xff0c;Activity是Android组件中最基本也是最为常见用的四大组件之一&#xff0c;用户可以用来交互为了完成某项任务。 Activity中所有操作都与用户密切相关&#xff0c;是一个负责与用户交互的组件&#xff0c;可以通过setCon…

Mac自带的看图如何连续查看多张图片

一、问题 mac看访达里的图片时&#xff0c;双击打开一张图片&#xff0c;然后按上下左右键都没法切换到另外的图片。而且也没找到像window一样单击缩略图可以看到预览图。其实是自己不懂得怎么使用&#xff0c;哈哈哈&#x1f602; 二、方法 2.1、图标方式 可以看到缩略图&a…

原理Redis-QuickList

QuickList **问题1&#xff1a;**ZipList虽然节省内存&#xff0c;但申请内存必须是连续空间&#xff0c;如果内存占用较多&#xff0c;申请内存效率很低。怎么办&#xff1f; 为了缓解这个问题&#xff0c;我们必须限制ZipList的长度和entry大小。 **问题2&#xff1a;**但是…

【NLP】GPT 模型如何工作

介绍 2021 年&#xff0c;我使用 GPT 模型编写了最初的几行代码&#xff0c;那时我意识到文本生成已经达到了拐点。我要求 GPT-3 总结一份很长的文档&#xff0c;并尝试了几次提示。我可以看到结果比以前的模型先进得多&#xff0c;这让我对这项技术感到兴奋&#xff0c;并渴望…

[数据结构]-AVL树

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、AVL树基…

陪玩圈子系统APP小程序H5,详细介绍,源码交付,支持二开!

陪玩圈子系统&#xff0c;页面展示&#xff0c;源码交付&#xff0c;支持二开&#xff01; 陪玩后端下载地址&#xff1a;电竞开黑陪玩系统小程序&#xff0c;APP&#xff0c;H5: 本系统是集齐开黑&#xff0c;陪玩&#xff0c;陪聊于一体的专业APP&#xff0c;小程序&#xff…

Github Copilot AI编码完成工具

目录 一、GitHub Copilot 1、简介 2、工作原理 3、功能 二、GitHub Copilot X 1、什么是 GitHub Copilot X 2、GitHub Copilot X 的功能 三、支持、使用 1、支持 2、使用 四、实际研究、验证(代码方向) 1、代码生成 2、代码提示 3、生成测试用例 4、代码解释 5…

排序算法--归并排序

实现逻辑 ① 将序列每相邻两个数字进行归并操作&#xff0c;形成floor(n/2)个序列&#xff0c;排序后每个序列包含两个元素 ② 将上述序列再次归并&#xff0c;形成floor(n/4)个序列&#xff0c;每个序列包含四个元素 ③ 重复步骤②&#xff0c;直到所有元素排序完毕 void pri…

Rust并发编程:理解线程与并发

大家好&#xff01;我是lincyang。 今天我们来深入探讨Rust中的并发编程&#xff0c;特别是线程的使用和并发的基本概念。 Rust中的线程 Rust使用线程来实现并发。线程是操作系统可以同时运行的最小指令集。在Rust中&#xff0c;创建线程非常简单&#xff0c;但与此同时&…

SHAP - 机器学习模型可解释性工具

github地址&#xff1a;shap/docs/index.rst at master shap/shap (github.com) SHAP使用文档&#xff1a;欢迎使用 SHAP 文档 — SHAP 最新文档 SHAP介绍 SHAP&#xff08;SHapley Additive exPlanations&#xff09;是一种用于解释预测结果的方法&#xff0c;它基于Shapley…

ADB命令介绍

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

系列七、ThreadLocal为什么会导致内存泄漏

一、ThreadLocal为什么会导致内存泄露 1.1、ThreadLocalMap的基本结构 ThreadLocalMap是ThreadLocal的内部类&#xff0c;没有实现Map接口&#xff0c;用独立的方式实现了Map的功能&#xff0c;其内部的Entry也是独立实现的。源码如下&#xff1a; 1.2、ThreadLocal引用示意图…

逸学java【初级菜鸟篇】9.3 Stream流

hi&#xff0c;我是逸尘&#xff0c;一起学java吧 得益于Lambda所带来的函数式编程&#xff0c;引入了一个全新的Stream流概念&#xff08;就是都基本使用lambda的形式&#xff09;。 流处理 我们首先理解什么是流处理&#xff0c;它类似于sql语句&#xff0c;可以执行非常复…

cocos2dx ​​Animate3D(二)

Twirl 扭曲旋转特效 // 持续时间(时间过后不会回到原来的样子) // 整个屏幕被分成几行几列 // 扭曲中心位置 // 扭曲的数量 // 振幅 static Twirl* create(float duration, const Size& gridSize, const Vec2& position, unsigned int twirls, float amplitude)…

Python基础【二】--基本语句【2023.11.22】

1.条件语句 在进行逻辑判断时&#xff0c;我们需要用到条件语句&#xff0c;Python 提供了 if、elif、else 来进行逻辑判断。格式如下所示&#xff1a; if 判断条件1:执行语句1... elif 判断条件2:执行语句2... elif 判断条件3:执行语句3... else:执行语句4...ainput("请输…

Django 模型和Admin站点管理(三)

一、定义模型 &#xff08;1&#xff09; 创建模型类&#xff0c;必须要继承自 models.Model from django.db import models# Create your models here. #设计数据库 #创建模型 class UserModel(models.Model):namemodels.CharField(max_length30) #对应于SQL name varchar(30…

EMG肌肉信号处理合集 (一)

本文归纳了常见的肌肉信号预处理流程&#xff0c;方便EMG信号的后续分析。使用pyemgpipeline库 来进行信号的处理。文中使用了 UC Irvine 数据库的下肢数据。 目录 1 使用wrappers 定义数据类&#xff0c;来进行后续的操作 2 肌电信号DC偏置去除 3 带通滤波器处理 4 对肌电…

opencv-直方图

直方图是一种对图像亮度分布的统计表示&#xff0c;它显示了图像中每个灰度级别的像素数量。在OpenCV中&#xff0c;你可以使用cv2.calcHist() 函数计算直方图。 以下是一个简单的示例&#xff0c;演示如何计算和绘制图像的直方图&#xff1a; import cv2 import numpy as np …

汽车级芯片NCV7518MWATXG 可编程六沟道低压侧 MOSFET预驱动器 特点、参数及应用

NCV7518MWATXG 可编程六沟道低压侧 MOSFET 预驱动器属于 FLEXMOS™ 汽车级产品&#xff0c;用于驱动逻辑电平 MOSFET。该产品可通过串行 SPI 和并行输入组合控制。该器件提供 3.3 V/5 V 兼容输入&#xff0c;并且串行输出驱动器可以采用 3.3 V 或 5 V 供电。内部通电重置提供受…