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

Java 串口通信—收发,监听数据(代码实现)

一、串口通信与串行通信的原理

        串行通信是指仅用一根接收线和一根发送线,将数据以位进行依次传输的一种通讯方式,每一位数据占据一个固定的时间长度。

        串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节的通信方式。

        串口通信时首先要约定好帧格式与波特率,并且串口通信采用TTL逻辑(Transistor-Transistor Logic) 是指晶体管-晶体管逻辑。

TTL逻辑门的标准输出状态是:

高电平(逻辑“1”或HIGH):典型值为+2.4V至+5V(对于标准5V电源供电的TTL),代表有效信号。
低电平(逻辑“0”或LOW):典型值接近于地电压(0V至+0.4V),代表无效信号。
这种通信方式抗干扰能力弱,下图中,静电让某一个低电平变高,就会导致通信距离很短,越1米。

        所以为了提示通信的稳定性与距离,产生了由美国制订的推荐标准RS232、RS485,都是在基础串口通信的基础上加了特定的电平转换芯片改变电压传输值。

串口通信主要可分为232、485、422三种通信方式。

232通信

232通信主要是由RX、TX、GND三根线组成。RX接TX,TX接RX,GND接GND。发送和接收由不同的线路处理,所以能够同时进行发送和接收数据,因此232是全双工通信。

485通信

为了解决232通信距离受限问题,于是有了485通信。 485通信只需要+、-两根线(也叫A、B两根线),A、B两根线的差分电平信号就是作为数据信号传输。发送和接收都用这两根线,每次只能发送数据或者接收数据,因此485是半双工通信。

422通信

        422通信兼具232与485的特点,既能实现全双工通信,又能增大传输距离。422也常被标注为485-4,而485被标注为485-2。因为485-2是2根线,485-4是4根线。

并行和串行的区别:

  • 并行传输: 多根线路传输,每条物理线代表一个比特位,可以同时发送和接受多个字节;

  • 串行传输: 只用一条线路传输,逐位传输,字节内允许出现延迟(如开始或结束等),而每个字节之间必须有完整的停止和起始位置。

同步传输和异步传输的差别:

  • 同步传输:在知道对方状态下进行全双工传输,需要调节系统时钟,使得传送速度不超过缓存容量,并保持包络上均衡。

  • 异步传输:既能针对字符流,也可针对比特流。异步传输没有明确定义的“帧”模式,因此不需要同步时钟,但会增加一个帧同步域,用于在接收端恢复字节边界,并通过位数逐个地进行帧的识别。

在实际应用中,串口通常使用异步技术来发送和接收数据。异步传输可以按需动态调整数据传输速率,以便快速响应用户操作或自动控制事件的发生。

二、Java 实现串口通信

准备工作

要想使用串口包进行串口通信,除了设置好环境变量之外,还要准备对应的串口通信的jar包

1. 下载对应版本的rxtx 解压后得到三个文件 rxtxParallel.dll、rxtxSerial.dll、RXTXcomm.jar/

下载地址如下:RXTX for Java (fizzed.com)


2. 将rxtxParallel.dll、rxtxSerial.dll 放进当前使用的jdk的bin目录( jdk版本必须与下载的rxtx一致 ,区分32位/64位 AMD/IA)


3. (windows x64系统可以将当前项目libs下的 rxtxParallel.dll、rxtxSerial.dll 直接放入jdk下的bin目录)
4. 需要将libs下的RXTXcomm.jar加入项目依赖,将javax.usb.properties复制到 JRE\lib或者JDK\lib.

<dependency><groupId>org.rxtx</groupId><artifactId>rxtx</artifactId><version>2.2</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/lib/RXTXcomm.jar</systemPath>
</dependency>

说明:(如果没有正常引入将会出现这个错误)

代码实现 

package com.ss.serialport.controller;import gnu.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;public class SerialPortTool {public static void main(String[] args) {// 查询串口findSystemAllComPort();//        //发送16进制数据——实际应用中串口通信传输的数据,大都是 16 进制String hexStrCode = "455A432F5600";SerialPort serialPort = SerialPortTool.openComPort(null, 38400, 8, 1, 0);// 设置串口监听SerialPortTool.setListenerToSerialPort(serialPort, new SerialPortEventListener() {@Overridepublic void serialEvent(SerialPortEvent arg0) {if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {//数据通知byte[] bytes = SerialPortTool.readData(serialPort);System.out.println("收到的数据长度:" + bytes.length);System.out.println("收到的数据:" + new String(bytes));}}});new Thread(new Runnable() {@Overridepublic void run() {int i = 1;while (i < 1000) {byte[] bytes = hexStrCode.getBytes();SerialPortTool.sendDataToComPort(serialPort, bytes);//发送数据i++;try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}/*** 查找电脑上所有可用 com 端口** @return 可用端口名称列表,没有时 列表为空*/public static final ArrayList<String> findSystemAllComPort() {/***  getPortIdentifiers:获得电脑主板当前所有可用串口*/Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();ArrayList<String> portNameList = new ArrayList<>();/***  将可用串口名添加到 List 列表*/System.out.println("===========串口信息start==============");while (portList.hasMoreElements()) {CommPortIdentifier commPortIdentifier = portList.nextElement();StringBuffer returnStr = new StringBuffer();String portName = commPortIdentifier.getName();//名称如 COM1、COM2....String isOwner = String.valueOf(commPortIdentifier.isCurrentlyOwned());returnStr.append(isOwner).append("\t 占用情况:").append(isOwner);System.out.println(returnStr);portNameList.add(portName);}System.out.println("===========串口信息end==============");return portNameList;}/*** 打开电脑上指定的串口** @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个* @param b        波特率(baudrate),如 9600* @param d        数据位(datebits),如 SerialPort.DATABITS_8 = 8* @param s        停止位(stopbits),如 SerialPort.STOPBITS_1 = 1* @param p        校验位 (parity),如 SerialPort.PARITY_NONE = 0* @return 打开的串口对象,打开失败时,返回 null*/public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {CommPort commPort = null;try {//当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个if (portName == null || "".equals(portName)) {List<String> comPortList = findSystemAllComPort();if (comPortList != null && comPortList.size() > 0) {portName = comPortList.get(0);}}System.out.println("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);//通过端口名称识别指定 COM 端口CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);/*** open(String TheOwner, int i):打开端口* TheOwner 自定义一个端口名称,随便自定义即可* i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.* 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application*/commPort = portIdentifier.open(portName, 5000);/*** 判断端口是不是串口* public abstract class SerialPort extends CommPort*/if (commPort instanceof SerialPort) {SerialPort serialPort = (SerialPort) commPort;/*** 设置串口参数:setSerialPortParams( int b, int d, int s, int p )* b:波特率(baudrate)* d:数据位(datebits),SerialPort 支持 5,6,7,8* s:停止位(stopbits),SerialPort 支持 1,2,3* p:校验位 (parity),SerialPort 支持 0,1,2,3,4* 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter* 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用*/serialPort.setSerialPortParams(b, d, s, p);System.out.println("打开串口 " + portName + " 成功...");return serialPort;} else {System.out.println("当前端口 " + commPort.getName() + " 不是串口...");}} catch (NoSuchPortException e) {e.printStackTrace();} catch (PortInUseException e) {System.out.println("串口 " + portName + " 已经被占用,请先解除占用...");e.printStackTrace();} catch (UnsupportedCommOperationException e) {System.out.println("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");e.printStackTrace();if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用commPort.close();}}System.out.println("打开串口 " + portName + " 失败...");return null;}/*** 往串口发送数据** @param serialPort 串口对象* @param orders     待发送数据*/public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {OutputStream outputStream = null;try {if (serialPort != null) {outputStream = serialPort.getOutputStream();outputStream.write(orders);outputStream.flush();System.out.println("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");} else {System.out.println("gnu.io.SerialPort 为null,取消数据发送...");}} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 从串口读取数据** @param serialPort 要读取的串口* @return 读取的数据*/public static byte[] readData(SerialPort serialPort) {InputStream is = null;byte[] bytes = null;try {is = serialPort.getInputStream();//获得串口的输入流int bufflenth = is.available();//获得数据长度while (bufflenth != 0) {bytes = new byte[bufflenth];//初始化byte数组is.read(bytes);bufflenth = is.available();}} catch (IOException e) {e.printStackTrace();} finally {try {if (is != null) {is.close();is = null;}} catch (IOException e) {e.printStackTrace();}}return bytes;}/*** 给串口设置监听** @param serialPort* @param listener*/public static void setListenerToSerialPort(SerialPort serialPort, SerialPortEventListener listener) {try {//给串口添加事件监听serialPort.addEventListener(listener);} catch (TooManyListenersException e) {e.printStackTrace();}serialPort.notifyOnDataAvailable(true);//串口有数据监听serialPort.notifyOnBreakInterrupt(true);//中断事件监听}/*** 关闭串口** @param serialPort 待关闭的串口对象*/public static void closeComPort(SerialPort serialPort) {if (serialPort != null) {serialPort.close();System.out.println("关闭串口 " + serialPort.getName());}}/*** 16进制字符串转十进制字节数组* 这是常用的方法,如某些硬件的通信指令就是提供的16进制字符串,发送时需要转为字节数组再进行发送** @param strSource 16进制字符串,如 "455A432F5600",每两位对应字节数组中的一个10进制元素*                  默认会去除参数字符串中的空格,所以参数 "45 5A 43 2F 56 00" 也是可以的* @return 十进制字节数组, 如 [69, 90, 67, 47, 86, 0]*/public static byte[] hexString2Bytes(String strSource) {if (strSource == null || "".equals(strSource.trim())) {System.out.println("hexString2Bytes 参数为空,放弃转换.");return null;}strSource = strSource.replace(" ", "");int l = strSource.length() / 2;byte[] ret = new byte[l];for (int i = 0; i < l; i++) {ret[i] = Integer.valueOf(strSource.substring(i * 2, i * 2 + 2), 16).byteValue();}return ret;}}

整合成串口工具类 :

package com.ss.serialport.utils;import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;/*** @ClassName DLSC_SerialPort* @Description 串口工具类 :打开串口 ;接受数据 ;发送数据* @Version 1.0*/
public class DLSC_SerialPort {private SerialPort serialPort;private InputStream inputStream;private OutputStream outputStream;private BlockingQueue<String> receivedDataQueue = new LinkedBlockingQueue<>();private volatile boolean isRunning = true;private void connect(String portName) throws Exception {// 获取串口通信端口实例CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(portName);if (portId.isCurrentlyOwned()) {System.err.println("Error: Port is currently in use");} else {// 打开端口,并获取输入、输出流serialPort = (SerialPort) portId.open("SerialCommExample", 2000);inputStream = serialPort.getInputStream();outputStream = serialPort.getOutputStream();// 设置串口参数serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);// 启动读取数据的线程Thread readThread = new Thread(() -> {try {while (isRunning) {int available = inputStream.available();if (available > 0) {byte[] bytes = new byte[available];inputStream.read(bytes);String data = new String(bytes, "UTF-8");receivedDataQueue.put(data); // 将数据放入队列}Thread.sleep(100); // 等待一段时间再检查是否有新数据}} catch (IOException | InterruptedException e) {e.printStackTrace();}});readThread.start();}}private void sendData(String data) throws IOException {if (outputStream != null) {outputStream.write(data.getBytes("UTF-8"));outputStream.flush(); // 确保数据被发送出去}}private String receiveData(long timeout) throws InterruptedException {return receivedDataQueue.poll(timeout, TimeUnit.MILLISECONDS); // 尝试从队列中获取数据,超时则返回null}private void disconnect() throws Exception {isRunning = false; // 设置标志位以停止读取数据的线程if (serialPort != null) {serialPort.removeEventListener();serialPort.close();}}public static void send (String msg) {DLSC_SerialPort example = new DLSC_SerialPort();try {// 连接到串口example.connect("COM3"); // 替换为你的串口名称// 发送数据example.sendData(msg + "\r\n");// 断开连接example.disconnect();} catch (Exception e) {e.printStackTrace();}}public static Double sendAndReceives(String msg) {DLSC_SerialPort example = new DLSC_SerialPort();try {// 连接到串口example.connect("COM1"); // 替换为你的串口名称// 发送数据example.sendData(msg + "\r\n");// 等待并接收数据String receivedData = example.receiveData(5000); // 等待最多5秒来获取数据if (receivedData != null) {Double backData = Double.valueOf(receivedData);System.out.println("Received data: " + backData);return backData;} else {System.out.println("No data received within the timeout period.");}// 断开连接example.disconnect();} catch (Exception e) {e.printStackTrace();}return null;}//    public static String sendAndReceive(String msg) {
//
//        SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
//        ArrayList<String> port = serialPortUtil.findPort();
//        if (port != null && !port.isEmpty()) {
//            System.out.println("没有发现任何端口");
//        }
//        String portName = port.get(2);
//        SerialPort serialPort = serialPortUtil.openPort(
//                portName, 9600, 8, 1, 0);
//        if (serialPort == null) {
//            System.out.println("打开串口(" + portName + ")失败");
//        }
//        System.out.println("成功连接串口:" + portName);serialPortUtil.sendToPort(serialPort, "SOUR:VOLT 28\r\n".getBytes());
//        try {
//            Thread.sleep(1000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        serialPortUtil.sendToPort(serialPort, "SOUR:CURR:LIMIT:HIGH?\r\n".getBytes());
//        byte[] bytes = serialPortUtil.readFromPort(serialPort);
//        if (bytes != null) {
//            return new String(bytes);
//        }
//        serialPortUtil.closePort(serialPort);
//        return null;
//    }//    public static String sendAndReceive(String msg) {
//
//        SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
//        ArrayList<String> port = serialPortUtil.findPort();
//        if (port != null && !port.isEmpty()) {
//            System.out.println("没有发现任何端口");
//        }
//        String portName = port.get(0);
//        SerialPort serialPort = serialPortUtil.openPort(
//                portName, 9600, 8, 1, 0);
//        if (serialPort == null) {
//            System.out.println("打开串口(" + portName + ")失败");
//        }
//        System.out.println("成功连接串口:" + portName);serialPortUtil.sendToPort(serialPort, "SOUR:VOLT 28\r\n".getBytes());
//        try {
//            Thread.sleep(6000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        serialPortUtil.sendToPort(serialPort, "SOUR:CURR:LIMIT:HIGH?\r\n".getBytes());
//        byte[] bytes = serialPortUtil.readFromPort(serialPort);
//        if (bytes != null) {
//            return new String(bytes);
//        }
//        System.out.println(serialPort);
//        serialPortUtil.closePort(serialPort);
//        return null;
//    }public static String sendAndReceive(String msg) {SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();ArrayList<String> port = serialPortUtil.findPort();System.out.println(port);if (port == null || port.isEmpty()) {System.out.println("没有发现任何端口");return null;}String portName = port.get(0);SerialPort serialPort = serialPortUtil.openPort(portName, 9600, 8, 1, 0);if (serialPort == null) {System.out.println("打开串口(" + portName + ")失败");return null;}System.out.println("成功连接串口:" + portName);try {// serialPortUtil.sendToPort(serialPort, "SOUR:VOLT 28\r\n".getBytes());Thread.sleep(6000);serialPortUtil.sendToPort(serialPort, "SOUR:CURR:LIMIT:HIGH?\r\n".getBytes());byte[] bytes = serialPortUtil.readFromPort(serialPort);if (bytes != null) {return new String(bytes);} else {System.out.println("未读取到任何数据");return null;}} catch (InterruptedException e) {e.printStackTrace();return null;} finally {// 确保串口在所有情况下都关闭serialPortUtil.closePort(serialPort);}}
}

相关文章:

Java 串口通信—收发,监听数据(代码实现)

一、串口通信与串行通信的原理 串行通信是指仅用一根接收线和一根发送线&#xff0c;将数据以位进行依次传输的一种通讯方式&#xff0c;每一位数据占据一个固定的时间长度。 串口通信&#xff08;Serial Communications&#xff09;的概念非常简单&#xff0c;串口按位&#x…...

fileinput pdf编辑初始化预览

var $fileLinkInput $(#file_link_full); $fileLinkInput.fileinput({language: zh,uploadUrl: <?php echo Yii::$app->urlManager->createUrl([file/image, type > work_file]);?>,initialPreview: [defaultFile],initialPreviewAsData: true,initialPrevie…...

微信支付开发-需求整理及需求设计

一、客户要求 1、通过唤醒机器人参与答题项&#xff0c;机器人自动获取题目&#xff0c;用户进行答题&#xff1b; 2、用户答对题数与后台设置的一样或者更多&#xff0c;则提醒用户可以领取奖品&#xff0c;但是需要用户支付邮费&#xff1b; 3、用户在几天之内不能重复领取奖…...

vs code: pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1,因为在此系统上禁止运行脚本

在visual studio code运行pnpm出错&#xff1a; pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本 解决方案&#xff1a; 到C:\Program Files\nodejs文件夹下删除pnpm.ps1即可。 C:\Program Files\nodejs改成你自己的路径...

web测试必备技能:浏览器兼容性测试

如今&#xff0c;市面上的浏览器种类越来越多&#xff08;尤其是在平板和移动设备上&#xff09;&#xff0c;这就意味着你所测试的站点需要在这些你声称支持浏览器上都能很好的工作。 同时&#xff0c;主流浏览器&#xff08;IE&#xff0c;Firefox&#xff0c;Chrome&#x…...

《数据资产管理核心技术与应用》首次大型赠书活动圆满结束

《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书&#xff0c;作者为张永清等著&#xff0c;在2024.9.11号晚上20:00&#xff0c;本书作者张永清联合锋哥聊数仓公众号和清华大学出版社一起&#xff0c;向各大大数据技术爱好者通过三轮互动活动赠送了3本正版图书。…...

vue在一个组件引用其他组件

在vue一个组件中引用另一个组件的步骤 必须在script中导入要引用的组件需要在export default的components引用导入的组件(这一步经常忘记)在template使用导入的组件<script><!-- 第一步,导入--> import Vue01 from "@/components/Vue01.vue";...

软件测试学习笔记丨Postman实战练习

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32096#h-22 二、实战练习 2.1 宠物商店接口文档分析 接口文档&#xff1a;http://petstore.swagger.io &#xff0c;这是宠物商店接口的 swagger 文档。 2.1.1 什么是 swagger Swagger 是…...

kubernetes微服务基础及类型

目录 1 什么是微服务 2 微服务的类型 3 ipvs模式 ipvs模式配置方式 4 微服务类型详解 4.1 ClusterIP 4.2 ClusterIP中的特殊模式headless 4.3 nodeport 4.4 metalLB配合loadbalance实现发布IP 1 什么是微服务 用控制器来完成集群的工作负载&#xff0c;那么应用如何暴漏出去&…...

linux-L3_linux 查看进程(node-red)

linux 查看进程 以查看进程node-red为例 ps aux | grep node-red...

区块链之变:揭秘Web3对互联网的改变

传统游戏中&#xff0c;玩家的虚拟资产&#xff08;如角色、装备&#xff09;通常由游戏公司控制&#xff0c;玩家无法真正拥有这些资产或进行交易。而在区块链游戏中&#xff0c;虚拟资产通过去中心化技术记录在区块链上&#xff0c;玩家对其拥有完全的所有权&#xff0c;并能…...

SAP B1 Web Client MS Teams App集成连载一:先决条件/Prerequisites

一、先决条件/Prerequisites 在设置 SAP Business One 应用之前&#xff0c;确保您已具备以下各项&#xff1a;Before you set up the SAP Business One app, make sure you have acquired the following: 1.Microsoft Teams 管理员账户/A Microsoft Teams admin account 您需…...

去除单细胞数据中环境游离的RNA污染-decontX工具学习

DecontX 是一种用于单细胞 RNA 测序数据的去除环境污染物&#xff08;decontamination&#xff09;的工具&#xff0c;主要用于减少由细胞外RNA造成的污染效应。 开发者在20年的文章中已经把这个工具适用的情况说的非常清楚了&#xff1a;简单来说就是基于微流控的单细胞技术会…...

Games101图形学笔记——光栅化

这里写目录标题 Rasterization光栅化屏幕空间隔行扫描三角形采样采样产生的问题反走样处理方法&#xff1a;采样前模糊 频率&#xff0c;时域傅里叶级数展开傅里叶变换 滤波高通滤波低通滤波 卷积卷积的一些定理 反走样MSAA&#xff08;Multisample Anti-Aliasing&#xff09;多…...

2024年汉字小达人区级自由报名的几个最新问题和真题练一练

2024年第十一届汉字小达人的区级活动的时间9月25-30日正式开赛&#xff0c;还有不到两周。 今天继续回答家长和孩子们的几个问题&#xff0c;并给大家看看一些真题&#xff0c;让孩子对汉字小达人的题型和比赛有直观的了解&#xff0c;从而更好地备考。 本专题在比赛前持续更…...

从简单分析到智能问数,Smartbi AIChat让数据回归业务

大数据产业创新服务媒体 ——聚焦数据 改变商业 在某科技公司&#xff0c;资深数据分析师李晨&#xff08;化名&#xff09;正忙于分析新产品的市场表现。面对传统自助式BI工具&#xff0c;李晨在功能界面中手动设置各种查询条件&#xff0c;进行了一番复杂的拖拉拽操作&#…...

基于SpringBoot+Vue+MySQL的考编论坛网站

系统展示 用户前台界面 管理员后台界面 系统背景 在当前信息化高速发展的时代&#xff0c;考编已成为众多求职者的重要选择。然而&#xff0c;备考过程中信息获取、经验交流及资源分享的需求日益凸显。基于SpringBoot、Vue.js与MySQL构建的考编论坛网站应运而生&#xff0c;旨在…...

SpringSecurity剖析

1、SpringSecurity 入门 1.1、简介 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。Spring Security是一个框架&#xff0c;致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样&#xff0c;Sp…...

一文搞懂 Flink Graph 构建过程源码

一文搞懂 Flink Graph 构建过程 1. StreamGraph构建过程1.1 transform(): 构建的核心1.2 transformOneInputTransform1.3 构造顶点1.4 构造边1.5 transformSource1.6 transformPartition1.7 transformSink 1. StreamGraph构建过程 链接: 一文搞懂 Flink 其他重要源码点击我 e…...

【spring】IDEA 新建一个spring boot 项目

参考新建项目-sprintboot 选择版本、依赖,我选了一堆 maven会重新下载一次么?...

LeetCode[简单] 搜索插入位置

给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 思路&#xff1a;类似与二分查找 唯一需要注意的是&#xff0c;搜索…...

(代码可运行)Bootstrap框架的HTML示例

Bootstrap&#xff1a;一套流行的前端开发框架&#xff0c;基于HTML、CSS和JavaScript&#xff0c;适用于快速构建响应式Web应用。 以下是一个使用Bootstrap构建的简单响应式Web应用的HTML示例&#xff1a; <!DOCTYPE html> <html lang"en"> <head&…...

IntelliJ IDEA 2024创建Java项目

一、前言 本文将带领大家手把手创建纯Java项目&#xff0c;不涉及Maven。如有问题&#xff0c;欢迎大家在评论区指正说明&#xff01; 二、环境准备 名称版本jdk1.8idea2024 1.4操作系统win10 jdk的安装教程 idea的安装教程 三、创建项目 首先我们点击新建项目 然后我们…...

Python之 条件与循环(Python‘s Conditions and loops)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…...

C++学习,多态纯虚函数

多态字面意思是多种形态&#xff0c;当类之间存在层次结构&#xff0c;并且类之间是通过继承时&#xff0c;就会用到多态。多态允许通过基类指针或引用来调用派生类中的成员函数。这种机制允许函数&#xff0c;在运行时根据对象的实际类型来确定执行哪个函数&#xff0c;从而实…...

飞速(FS)与西门子联合打造交换机自动化灌装测试生产线

2024年9月&#xff0c;备受信赖的信息通信技术&#xff08;ICT&#xff09;解决方案提供商飞速&#xff08;FS&#xff09;与工业自动化领域的领先企业西门子公司正式宣布&#xff0c;双方共同打造的ILTP&#xff08;智能灌装测试平台&#xff09;和自动化生产线将正式启动。此…...

Vue组合式API:setup()函数

1、什么是组合式API Vue 3.0 中新增了组合式 API 的功能&#xff0c;它是一组附加的、基于函数的 API&#xff0c;可以更加灵活地组织组件代码。通过组合式 API 可以使用函数而不是声明选项的方式来编写 Vue 组件。因此&#xff0c;使用组合式 API 可以将组件代码编写为多个函…...

Redis底层数据结构(详细篇)

Redis底层数据结构 一、常见数据结构的底层数据结构1、动态字符串SDS&#xff08;Simple Dynamic String&#xff09;组成 2、IntSet组成如何保证动态如何确保有序呢? 底层如何查找的呢? 3、Dict(dictionary)3.1组成3.2 扩容3.3 收缩3.4 rehash 4、ZipList连锁更新问题总结特…...

树和二叉树基本术语、性质

总结二叉树的度、树高、结点数等属性之间的关系&#xff08;通过王道书 5.2.3 课后小题来复习“二叉 树的性质”&#xff09; 树的相关知识 叶子结点的度0 层次默认从1开始 有些题目从0 开始也不要奇怪 常见考点1&#xff1a;结点数总度数&#xff0b;1 常见考点2&#xff1…...

FEDERATED引擎

入门 MySQL引擎主要有以下几种&#xff1a; MyISAM&#xff1a;这是MySQL 5.5.5之前的默认存储引擎&#xff0c;不支持事务、外键约束和聚簇索引&#xff0c;适用于读多写少的场景。InnoDB&#xff1a;这是MySQL 5.5.5之后的默认存储引擎&#xff0c;支持事务、外键约束、行级…...