引入依赖 <!-- 串口通信 --> <dependency> <groupId>com.fazecast</groupId> <artifactId>jSerialComm</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.13</version> </dependency>引入工具 package com. lhbl. digitaltwin. utils. com ; import com. fazecast. jSerialComm. SerialPort ; import com. fazecast. jSerialComm. SerialPortDataListener ; import com. fazecast. jSerialComm. SerialPortEvent ; import com. lhbl. digitaltwin. utils. web. ConvertHexStrAndStrUtils ; import lombok. extern. slf4j. Slf4j ; import org. springframework. stereotype. Component ; import java. util. ArrayList ; import java. util. List ; import java. util. Map ; import java. util. concurrent. ConcurrentHashMap ; import java. util. stream. Collectors ; @Slf4j @Component public class SerialPortManager { // 波特率 根据实际情况改 public static final int SERIAL_BAUD_RATE = 9600 ; private static final Map < String , SerialPortHolder > PORT_MAP = new ConcurrentHashMap < > ( ) ; @FunctionalInterface public interface SerialPortCallback { void onDataReceived ( String portName, byte [ ] data) ; } private static class SerialPortHolder { volatile SerialPort serialPort; volatile boolean connected; SerialPortCallback callback; SerialPortHolder ( SerialPort serialPort, boolean connected, SerialPortCallback callback) { this . serialPort= serialPort; this . connected= connected; this . callback= callback; } } private static class DataListener implements SerialPortDataListener { private final String portName; private final SerialPortCallback callback; DataListener ( String portName, SerialPortCallback callback) { this . portName= portName; this . callback= callback; } @Override public int getListeningEvents ( ) { return SerialPort . LISTENING_EVENT_DATA_AVAILABLE ; } @Override public void serialEvent ( SerialPortEvent event) { if ( callback!= null ) { byte [ ] data= readSerialPortData ( portName) ; if ( data!= null ) { try { callback. onDataReceived ( portName, data) ; } catch ( Exception e) { log. error ( "串口数据处理失败: {}" , e. getMessage ( ) ) ; } } } } } public static List < String > getSerialPortList ( ) { SerialPort [ ] serialPorts= SerialPort . getCommPorts ( ) ; List < String > portNameList= new ArrayList < > ( ) ; for ( SerialPort serialPort: serialPorts) { log. debug ( "可用串口: {}" , serialPort. getSystemPortName ( ) ) ; portNameList. add ( serialPort. getSystemPortName ( ) ) ; } return portNameList. stream ( ) . distinct ( ) . collect ( Collectors . toList ( ) ) ; } public static void connectSerialPort ( String portName) { connectSerialPort ( portName, SERIAL_BAUD_RATE , null ) ; } public static void connectSerialPort ( String portName, Integer baudRate, SerialPortCallback callback) { if ( PORT_MAP . containsKey ( portName) ) { log. warn ( "串口已连接: {}" , portName) ; return ; } try { SerialPort serialPort= openSerialPort ( portName, baudRate) ; if ( serialPort. isOpen ( ) ) { SerialPortCallback dataCallback= callback!= null ? callback: SerialPortManager :: defaultDataHandler ; serialPort. addDataListener ( new DataListener ( portName, dataCallback) ) ; PORT_MAP . put ( portName, new SerialPortHolder ( serialPort, true , dataCallback) ) ; log. info ( "串口连接成功: {}" , portName) ; } else { log. error ( "串口连接失败: {},请查看端口!" , portName) ; } } catch ( Exception ex) { log. error ( "串口连接异常: {}" , ex. getMessage ( ) , ex) ; } } private static void defaultDataHandler ( String portName, byte [ ] data) { try { String hexStr= ConvertHexStrAndStrUtils . bytesToHexStr ( data) ; if ( hexStr. length ( ) >= 8 ) { String comStatus= hexStr. substring ( 6 , 8 ) ; if ( "00" . equals ( comStatus) ) { log. debug ( "行程开关关闭 - 端口: {}, 数据: {}" , portName, hexStr) ; } else if ( "FF" . equals ( comStatus) ) { log. debug ( "行程开关闭合 - 端口: {}, 数据: {}" , portName, hexStr) ; } } } catch ( Exception e) { log. error ( "串口数据解析失败: {}" , e. getMessage ( ) ) ; } } public static SerialPort openSerialPort ( String portName, Integer baudRate) { SerialPort serialPort= SerialPort . getCommPort ( portName) ; if ( baudRate!= null ) { serialPort. setBaudRate ( baudRate) ; } if ( ! serialPort. isOpen ( ) ) { serialPort. openPort ( 1000 ) ; } serialPort. setFlowControl ( SerialPort . FLOW_CONTROL_DISABLED ) ; serialPort. setComPortParameters ( baudRate, 8 , SerialPort . ONE_STOP_BIT , SerialPort . NO_PARITY ) ; serialPort. setComPortTimeouts ( SerialPort . TIMEOUT_READ_BLOCKING | SerialPort . TIMEOUT_WRITE_BLOCKING , 1000 , 1000 ) ; return serialPort; } public static void closeSerialPort ( String portName) { SerialPortHolder holder= PORT_MAP . remove ( portName) ; if ( holder!= null && holder. serialPort!= null && holder. serialPort. isOpen ( ) ) { holder. serialPort. closePort ( ) ; log. info ( "串口关闭: {}" , portName) ; } } public static void closeAllSerialPorts ( ) { PORT_MAP . forEach ( ( portName, holder) -> { if ( holder. serialPort!= null && holder. serialPort. isOpen ( ) ) { holder. serialPort. closePort ( ) ; log. info ( "串口关闭: {}" , portName) ; } } ) ; PORT_MAP . clear ( ) ; } public static void sendSerialPortData ( String portName, byte [ ] content) { SerialPortHolder holder= PORT_MAP . get ( portName) ; if ( holder!= null && holder. serialPort!= null && holder. serialPort. isOpen ( ) ) { holder. serialPort. writeBytes ( content, content. length) ; log. debug ( "串口发送数据 - 端口: {}, 长度: {}" , portName, content. length) ; } } public static byte [ ] readSerialPortData ( String portName) { SerialPortHolder holder= PORT_MAP . get ( portName) ; if ( holder!= null && holder. serialPort!= null && holder. serialPort. isOpen ( ) ) { try { int i= 0 ; while ( holder. serialPort. bytesAvailable ( ) > 0 && i++ < 5 ) { Thread . sleep ( 20 ) ; } byte [ ] readBuffer= new byte [ holder. serialPort. bytesAvailable ( ) ] ; int numRead= holder. serialPort. readBytes ( readBuffer, readBuffer. length) ; if ( numRead> 0 ) { return readBuffer; } } catch ( InterruptedException e) { log. error ( "串口读取中断: {}" , e. getMessage ( ) ) ; Thread . currentThread ( ) . interrupt ( ) ; } } return null ; } public static boolean isConnected ( String portName) { SerialPortHolder holder= PORT_MAP . get ( portName) ; return holder!= null && holder. connected&& holder. serialPort!= null && holder. serialPort. isOpen ( ) ; } } 开机连接串口 @SpringBootApplication public class DigitalTwinApplication implements ApplicationRunner { public static void main ( String [ ] args) { SpringApplication . run ( DigitalTwinApplication . class , args) ; } @Override public void run ( ApplicationArguments args) throws Exception { SerialPortManager . connectSerialPort ( "COM4" , 9600 , ( comName, data) -> { System . out. println ( data) ; } ) ; } } 定时任务实时发送 @Component @Slf4j public class ScheduledCOM { private String sendMsg= "00 04 00 00 00 03 B1 DA" ; @Scheduled ( fixedRate= 1000 ) public void readComData ( ) { new Thread ( new Runnable ( ) { @Override public void run ( ) { byte [ ] bytes= HexUtil . decodeHex ( sendMsg) ; SerialPortManager . sendSerialPortData ( bytes) ; } } ) . start ( ) ; } } 其他辅助工具 public class ConvertHexStrAndStrUtils { private static final char [ ] HEXES = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' } ; public static String bytesToHexStr ( byte [ ] bytes) { if ( bytes== null || bytes. length== 0 ) { return null ; } StringBuilder hex= new StringBuilder ( bytes. length* 2 ) ; for ( byte b: bytes) { hex. append ( HEXES [ ( b>> 4 ) & 0x0F ] ) ; hex. append ( HEXES [ b& 0x0F ] ) ; } return hex. toString ( ) . toUpperCase ( ) ; } public static byte [ ] hexStrToBytes ( String hex) { if ( hex== null || hex. length ( ) == 0 ) { return null ; } char [ ] hexChars= hex. toCharArray ( ) ; byte [ ] bytes= new byte [ hexChars. length/ 2 ] ; // 如果 hex 中的字符不是偶数个, 则忽略最后一个 for ( int i= 0 ; i< bytes. length; i++ ) { bytes[ i] = ( byte ) Integer . parseInt ( "" + hexChars[ i* 2 ] + hexChars[ i* 2 + 1 ] , 16 ) ; } return bytes; } public static String strToHexStr ( String str) { StringBuilder sb= new StringBuilder ( ) ; byte [ ] bs= str. getBytes ( ) ; int bit; for ( int i= 0 ; i< bs. length; i++ ) { bit= ( bs[ i] & 0x0f0 ) >> 4 ; sb. append ( HEXES [ bit] ) ; bit= bs[ i] & 0x0f ; sb. append ( HEXES [ bit] ) ; } return sb. toString ( ) . trim ( ) ; } public static String hexStrToStr ( String hexStr) { //能被16整除,肯定可以被2整除 byte [ ] array= new byte [ hexStr. length ( ) / 2 ] ; try { for ( int i= 0 ; i< array. length; i++ ) { array[ i] = ( byte ) ( 0xff & Integer . parseInt ( hexStr. substring ( i* 2 , i* 2 + 2 ) , 16 ) ) ; } hexStr= new String ( array, StandardCharsets . UTF_8 ) ; } catch ( Exception e) { e. printStackTrace ( ) ; return "" ; } return hexStr; } } 流程:启动时先对串口进行 连接 连接上后发送数据给设备 数据格式和设备的数据格式一致时 设备会返回数据到回调 data 里面 处理这个data即可