Java springboot 串口 通信
基于win10 环境
- Virtual Serial Port Driver Pro 开通两个虚拟串口
- 打开串口调试助手
- 代码逻辑
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>port</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>port</name>
<description>Demo Serial Port project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.16</lombok.version>
<commons.lang3.version>3.11</commons.lang3.version>
<fastjson.version>1.2.75</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.RXTXcomm</groupId>
<artifactId>RXTXcomm</artifactId>
<version>1.0.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/RXTXcomm.jar</systemPath>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/lib</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</resources>
</build>
</project>
package com.example.port;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PreDestroy;
@SpringBootApplication
public class PortApplication {
public static void main(String[] args) {
SpringApplication.run(PortApplication.class, args);
}
@PreDestroy
public void destory() {
//关闭应用前 关闭端口
SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
serialPortUtil.removeListener(PortInit.serialPort, new MyLister());
serialPortUtil.closePort(PortInit.serialPort);
}
}
package com.example.port;
import gnu.io.SerialPort;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@Component
public class PortInit implements ApplicationRunner {
public static SerialPort serialPort = null;
@Value("${portname}")
private String portname;
@Override
public void run(ApplicationArguments args) {
//TestA();
//查看所有串口
SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
ArrayList<String> port = serialPortUtil.findPort();
System.out.println("发现全部串口:" + port);
System.out.println("打开指定portname:" + portname);
//打开该对应portname名字的串口
PortInit.serialPort = serialPortUtil.openPort(portname, 9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
//给对应的serialPort添加监听器
serialPortUtil.addListener(PortInit.serialPort, new MyLister());
}
}
package com.example.port;
/**
* @author 7788
* @version 1.0
* @date 2021/4/6 上午 9:26
* @location wuhan
*/
import gnu.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;
public class SerialPortUtil {
private static final Logger logger = LoggerFactory.getLogger(SerialPortUtil.class);
private static SerialPortUtil serialPortUtil = null;
static {
//在该类被ClassLoader加载时就初始化一个SerialTool对象
if (serialPortUtil == null) {
serialPortUtil = new SerialPortUtil();
}
}
//私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象
private SerialPortUtil() {
}
/**
* 获取提供服务的SerialTool对象
*
* @return serialPortUtil
*/
public static SerialPortUtil getSerialPortUtil() {
if (serialPortUtil == null) {
serialPortUtil = new SerialPortUtil();
}
return serialPortUtil;
}
/**
* 查找所有可用端口
*
* @return 可用端口名称列表
*/
public ArrayList<String> findPort() {
//获得当前所有可用串口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
ArrayList<String> portNameList = new ArrayList<>();
//将可用串口名添加到List并返回该List
while (portList.hasMoreElements()) {
String portName = portList.nextElement().getName();
portNameList.add(portName);
}
return portNameList;
}
/**
* 打开串口
*
* @param portName 端口名称
* @param baudrate 波特率
* @param databits 数据位
* @param parity 校验位(奇偶位)
* @param stopbits 停止位
* @return 串口对象
* // * @throws SerialPortParameterFailure 设置串口参数失败
* // * @throws NotASerialPort 端口指向设备不是串口类型
* // * @throws NoSuchPort 没有该端口对应的串口设备
* // * @throws PortInUse 端口已被占用
*/
public SerialPort openPort(String portName, int baudrate, int databits, int parity, int stopbits) {
try {
//通过端口名识别端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
//打开端口,并给端口名字和一个timeout(打开操作的超时时间)
CommPort commPort = portIdentifier.open(portName, 2000);
//判断是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
try {
//设置一下串口的波特率等参数
serialPort.setSerialPortParams(baudrate, databits, stopbits, parity);
} catch (UnsupportedCommOperationException e) {
}
System.out.println("Open " + portName + " sucessfully !");
return serialPort;
} else {
logger.error("不是串口");
}
} catch (NoSuchPortException e1) {
logger.error("没有找到端口");
e1.printStackTrace();
} catch (PortInUseException e2) {
logger.error("端口被占用");
e2.printStackTrace();
}
return null;
}
/**
* 关闭串口
*
* @param serialPort 待关闭的串口对象
*/
public void closePort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
}
}
/**
* 往串口发送数据
*
* @param serialPort 串口对象
* @param order 待发送数据
* // * @throws SendDataToSerialPortFailure 向串口发送数据失败
* // * @throws SerialPortOutputStreamCloseFailure 关闭串口对象的输出流出错
*/
public void sendToPort(SerialPort serialPort, byte[] order) {
OutputStream out = null;
try {
out = serialPort.getOutputStream();
out.write(order);
out.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 从串口读取数据
*
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据
* // * @throws ReadDataFromSerialPortFailure 从串口读取数据时出错
* // * @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错
*/
public byte[] readFromPort(SerialPort serialPort) {
InputStream in = null;
byte[] bytes = null;
try {
in = serialPort.getInputStream();
int bufflenth = in.available();
while (bufflenth != 0) {
bytes = new byte[bufflenth];
in.read(bytes);
bufflenth = in.available();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
/**
* 添加监听器
*
* @param port 串口对象
* @param listener 串口监听器
* // * @throws TooManyListeners 监听类对象过多
*/
public void addListener(SerialPort port, SerialPortEventListener listener) {
try {
//给串口添加监听器
port.addEventListener(listener);
//设置当有数据到达时唤醒监听接收线程
port.notifyOnDataAvailable(true);
//设置当通信中断时唤醒中断线程
port.notifyOnBreakInterrupt(true);
} catch (TooManyListenersException e) {
// throw new TooManyListeners();
logger.error("太多监听器");
e.printStackTrace();
}
}
/**
* 删除监听器
*
* @param port 串口对象
* @param listener 串口监听器
* // * @throws TooManyListeners 监听类对象过多
*/
public void removeListener(SerialPort port, SerialPortEventListener listener) {
//删除串口监听器
port.removeEventListener();
}
}
package com.example.port;
import com.alibaba.fastjson.JSON;
import com.example.port.ISO8583.ISO8583;
import com.example.port.ISO8583.TransISO8583MessageUtil;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import lombok.SneakyThrows;
import java.util.Date;
/**
* @author best
*/
public class MyLister implements SerialPortEventListener {
@SneakyThrows
@Override
public void serialEvent(SerialPortEvent arg0) {
if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
byte[] bytes = serialPortUtil.readFromPort(PortInit.serialPort);
String byteStr = new String(bytes, 0, bytes.length).trim();
// System.out.println(new Date() + "【读到的字节数组】:-----" + byteStr);
// ISO8583 aiISO8583DTO = (ISO8583) TransISO8583MessageUtil.unpackISO8583(ISO8583.class, byteStr);
// System.out.println("UNPACK ISO8583: " + JSON.toJSONString(aiISO8583DTO));
System.out.println("===========start===========");
System.out.println(new Date() + "【读到的字节数组】:-----" + byteStr);
String needData = printHexString(bytes);
System.out.println(new Date() + "【字节数组转字符串】:-----" + needData);
System.out.println(new Date() + "【16进制字符串转字符串】:" + hexStringToString(needData));
System.out.println("===========end===========");
// ISO8583 aiiso8583DTO = new ISO8583();
//
// aiiso8583DTO.setCardNo02(String.valueOf(System.currentTimeMillis()));
// aiiso8583DTO.setTransProcCode03("123456");
// aiiso8583DTO.setTransAmt04("000010000000");
// aiiso8583DTO.setSysTrackNo11("888888");
// aiiso8583DTO.setServiceInputModeCode22("100");
// aiiso8583DTO.setServiceConditionCode25("66");
// aiiso8583DTO.setCardAcceptorTerminalID41("08022206");
// aiiso8583DTO.setCardAcceptorID42("000100000000005");
// aiiso8583DTO.setAdditionalDataPrivate48("0000");
// aiiso8583DTO.setCurrencyCode49("168");
// aiiso8583DTO.setEWalletTransInfo58("53560118FFFFFFFFFFFF03104890100000006059FFFFFFFF0101000200000064020000080000032017122310225672FB47880000012B01");
// aiiso8583DTO.setFld60Domain60("41000006666");
// aiiso8583DTO.setOriginalInfoDomain61("000666000181");
// aiiso8583DTO.setFld63Domain63("0000000000000000");
// String maxBitmap = "7020048000C1805B";
// final String TPDU = "6000000000";
// final String HEAD = "612200000000";
// String sendMsg = TransISO8583MessageUtil.packISO8583(aiiso8583DTO, maxBitmap, TPDU, HEAD, "0300");
//接收到消息后 回复一个当前时间
serialPortUtil.sendToPort(PortInit.serialPort, new Date().toString().getBytes());
}
}
// 字节数组转字符串
private String printHexString(byte[] b) {
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sbf.append(hex.toUpperCase() + " ");
}
return sbf.toString().trim();
}
/**
* 16进制转换成为string类型字符串
*
* @param s
* @return
*/
public static String hexStringToString(String s) {
if (s == null || s.equals("")) {
return null;
}
s = s.replace(" ", "");
byte[] baKeyword = new byte[s.length() / 2];
for (int i = 0; i < baKeyword.length; i++) {
try {
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
} catch (Exception e) {
e.printStackTrace();
}
}
try {
s = new String(baKeyword, "UTF-8");
new String();
} catch (Exception e1) {
e1.printStackTrace();
}
return s;
}
}
接下来启动项目就可以了, 可以完善MyLister的功能 对收到的消息进行处理,然后回复消息 比如ISO8583的报文解析并http调用接口更新数据