├── README.md ├── application.properties ├── bin └── rxtx-0.0.1-SNAPSHOT.jar ├── pom.xml └── src ├── main └── java │ └── com │ └── linchunsen │ └── rxtx │ ├── JdbcUtil.java │ ├── MessageParseAble.java │ ├── SerialAbstarctListener.java │ ├── SerialContext.java │ ├── SerialPortRxtx.java │ ├── SerialReader.java │ ├── SerialStarter.java │ └── SerialWriter.java └── test └── java └── com └── linchunsen └── rxtx └── example ├── Main.java └── MessageParse.java /README.md: -------------------------------------------------------------------------------- 1 | # rxtx 2 | 对java的通信框架rxtx进行了进一步的封装,通过传入properties对象便可以实现串口的监听配置 3 | 4 | ## 目录说明 5 | bin : 项目导出的jar包 6 | 7 | src/main : 项目的源代码 8 | 9 | src/test : 项目的示例代码 10 | 11 | application.properties : 项目的配置文件,里面包含项目的详细配置说明 12 | -------------------------------------------------------------------------------- /application.properties: -------------------------------------------------------------------------------- 1 | ##----------------------------## 2 | ##数据库配置 3 | 4 | #指示当前的数据库配置是否是加过密的 5 | # true表示"是" 6 | # false表示"否",默认值:否 7 | myJdbcUtil.isEncodedInfo=true 8 | #数据库driverName 9 | myJdbcUtil.driverName=Y29tLm1pY3Jvc29mdC5zcWxzZXJ2ZXIuamRiYy5TUUxTZXJ2ZXJEcml2ZXI= 10 | #数据库url 11 | myJdbcUtil.url=amRiYzpzcWxzZXJ2ZXI6Ly8xMC4xMzUuMi4yNTA6MTQzMzsgRGF0YWJhc2VOYW1lPWRhcw== 12 | #数据库user 13 | myJdbcUtil.user=c2FjdWl5dXNoYW4= 14 | #数据库password 15 | myJdbcUtil.password=Q1lTY3lzMTIzNDU2 16 | 17 | ##----------------------------## 18 | ##串口设置 19 | # 20 | ##说明: 21 | # 程序读取配置文件时,将会扫描以serial.rxtx为前缀的键,并以serial.rxtx.*为完整前缀,根据不同前缀的数目,配置并监听多个串口 22 | # 例如,当配置文件中同时出现serial.rxtx.com1.appName和serial.rxtx.com4.appName程序将会同时监听这两串口 23 | 24 | #COM1串口通信配置 25 | #延时等待端口数据准备的时间,端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完,默认值是1,单位是毫秒 26 | serial.rxtx.com1.delayRead=1 27 | #超时时间的配置值,默认值是3000,单位是毫秒 28 | serial.rxtx.com1.timeout=3000 29 | #串口名,默认值是serial.rxtx前缀的最后一个单词,如前缀serial.rxtx.com1则默认串口名为COM1,程序将会自动将小写转为大写 30 | serial.rxtx.com1.port=COM1 31 | #数据位的配置值,默认值是8,可能的取值是5,6,7,8 32 | serial.rxtx.com1.dataBits=8 33 | #停止位的配置值,默认值是1,可能的取值是1,1.5,2 34 | serial.rxtx.com1.stopBits=1 35 | #奇偶校验的配置值,0表示无校验,1表示奇/ODD校验,2表示偶/EVEN校验,默认值是无校验 36 | serial.rxtx.com1.parity=0 37 | #波特率的配置值,默认值是115200 38 | serial.rxtx.com1.rate=115200 39 | #串口的程序名,默认值是SerialRXTX,可以重复,无实际意义 40 | serial.rxtx.com1.appName="SerialRXTX" 41 | 42 | #COM4串口通信配置 43 | serial.rxtx.com4.appName="SerialRXTX" -------------------------------------------------------------------------------- /bin/rxtx-0.0.1-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/demoModel/rxtx/bb2eb110d28a3e40f96562660c5cc4e0f6d6fcdf/bin/rxtx-0.0.1-SNAPSHOT.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.yuanqitec.framework 5 | rxtx 6 | 0.0.1-SNAPSHOT 7 | 8 | 9 | 10 | org.apache.maven.plugins 11 | maven-compiler-plugin 12 | 3.1 13 | 14 | 1.8 15 | 1.8 16 | UTF-8 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/JdbcUtil.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | import java.sql.Connection; 6 | import java.sql.DriverManager; 7 | import java.sql.SQLException; 8 | import java.util.Properties; 9 | 10 | import sun.misc.BASE64Decoder; 11 | import sun.misc.BASE64Encoder; 12 | 13 | /** 14 | *
15 | *

简介

根据配置文件对象来获取数据库Connection的工具类 16 | *
17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | *
文件修改记录
修改日期修改人修改内容
2017年1月6日linchunsen新建文件,并实现基本功能
32 | */ 33 | public class JdbcUtil { 34 | 35 | private boolean isLoaded = false; 36 | /** 37 | * 配置文件的键头 38 | */ 39 | public static final String MYJDBC_KEY_BASE = "myJdbcUtil."; 40 | /** 41 | * 配置文件中isEncodedInfo的键 42 | */ 43 | public static final String MYJDBC_KEY_ISENCODEDINFO = "isEncodedInfo"; 44 | /** 45 | * 配置文件中driverName的键 46 | */ 47 | public static final String MYJDBC_KEY_DRIVERNAME = "driverName"; 48 | public String driverName; 49 | /** 50 | * 配置文件中user的键 51 | */ 52 | public static final String MYJDBC_KEY_USER = "user"; 53 | public String user; 54 | /** 55 | * 配置文件中password的键 56 | */ 57 | public static final String MYJDBC_KEY_PASSWORD = "password"; 58 | public String password; 59 | /** 60 | * 配置文件中url的键 61 | */ 62 | public static final String MYJDBC_KEY_URL = "url"; 63 | public String url; 64 | 65 | /** 66 | * 根据配置文件对象来加载数据源配置 67 | * 68 | * @param properties 要加载的配置文件对象 69 | * @throws IOException 70 | */ 71 | public void load(Properties properties) throws IOException { 72 | 73 | String isEncodedInfo=properties.getProperty(JdbcUtil.MYJDBC_KEY_BASE+JdbcUtil.MYJDBC_KEY_ISENCODEDINFO, null); 74 | String driverName = properties.getProperty(JdbcUtil.MYJDBC_KEY_BASE+JdbcUtil.MYJDBC_KEY_DRIVERNAME); 75 | String user = properties.getProperty(JdbcUtil.MYJDBC_KEY_BASE+JdbcUtil.MYJDBC_KEY_USER); 76 | String password = properties.getProperty(JdbcUtil.MYJDBC_KEY_BASE+JdbcUtil.MYJDBC_KEY_PASSWORD); 77 | String url = properties.getProperty(JdbcUtil.MYJDBC_KEY_BASE+JdbcUtil.MYJDBC_KEY_URL); 78 | 79 | if (isEncodedInfo!=null) { 80 | boolean isEncoded=Boolean.parseBoolean(isEncodedInfo); 81 | if (isEncoded) {//是已经加密过的配置信息 82 | this.driverName = getFromBase64(driverName); 83 | this.user = getFromBase64(user); 84 | this.password = getFromBase64(password); 85 | this.url = getFromBase64(url); 86 | } else {//不是已经加密过的配置信息,将在本次加密 87 | this.driverName=driverName; 88 | this.user=user; 89 | this.url=url; 90 | this.password=password; 91 | //加密配置信息 92 | driverName=getBase64(driverName); 93 | user=getBase64(user); 94 | url=getBase64(url); 95 | password=getBase64(password); 96 | isEncoded=true; 97 | } 98 | } else {//配置文件中没有配置项 99 | this.driverName=driverName; 100 | this.user=user; 101 | this.url=url; 102 | this.password=password; 103 | } 104 | 105 | this.isLoaded = true; 106 | } 107 | 108 | /** 109 | * 在执行了load(Properties properties)之后,才可以调用获取数据库的Connection实例 110 | * 111 | * @return Connection实例 112 | * @throws ClassNotFoundException 113 | * @throws SQLException 114 | */ 115 | public Connection getConnection() throws ClassNotFoundException, SQLException { 116 | Connection connection = null; 117 | if (isLoaded) { 118 | Class.forName(driverName); 119 | connection = DriverManager.getConnection(this.url, this.user, this.password); 120 | } else { 121 | throw new RuntimeException("未执行load(Properties properties)方法,执行该方法后重试"); 122 | } 123 | return connection; 124 | } 125 | 126 | /** 127 | * 将经过Base64转码的字符串还原 128 | * 129 | * @param source 130 | * 经过Base64转码的字符串 131 | * @return 还原的字符串 132 | * @throws IOException 133 | */ 134 | public String getFromBase64(String source) throws IOException { 135 | String result = null; 136 | byte[] bytes = null; 137 | if (source != null) { 138 | BASE64Decoder decoder = new BASE64Decoder(); 139 | bytes = decoder.decodeBuffer(source); 140 | result = new String(bytes, "utf-8"); 141 | } 142 | return result; 143 | } 144 | 145 | /** 146 | * 将目标字符串使用Base64进行编码 147 | * 148 | * @throws UnsupportedEncodingException 149 | */ 150 | public String getBase64(String source) throws UnsupportedEncodingException { 151 | String result = null; 152 | byte[] bytes = null; 153 | bytes = source.getBytes("utf-8"); 154 | if (bytes != null) { 155 | BASE64Encoder encoder = new BASE64Encoder(); 156 | result = encoder.encode(bytes); 157 | } 158 | return result; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/MessageParseAble.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | /** 4 | *
5 | *

简介

报文解析接口,只有实现了该接口的类才能被串口读取器所调用以解析报文 6 | *
7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | *
文件修改记录
修改日期修改人修改内容
2016年12月29日linchunsen新建文件,并实现基本功能
22 | */ 23 | public interface MessageParseAble { 24 | /** 25 | * 解析执行报文 26 | * 27 | * @param message 28 | * 报文 29 | * @throws Exception 30 | */ 31 | void messageParse(String message) throws Exception; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/SerialAbstarctListener.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | import java.util.Observable; 6 | 7 | import gnu.io.SerialPortEvent; 8 | import gnu.io.SerialPortEventListener; 9 | 10 | /** 11 | *
12 | *

简介

串口事件监听的抽象实现,对串口监听监听器进行了进一步的封装 13 | *
14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | *
文件修改记录
修改日期修改人修改内容
2017年1月4日linchunsen新建文件,并实现基本功能
29 | */ 30 | public abstract class SerialAbstarctListener extends Observable implements SerialPortEventListener { 31 | 32 | /** 33 | * 串口实例 34 | */ 35 | private SerialPortRxtx serialPortRxtx; 36 | /** 37 | * 读写延迟 38 | */ 39 | private long delayReadTime; 40 | 41 | public SerialAbstarctListener(SerialPortRxtx serialPortRxtx) { 42 | super(); 43 | this.serialPortRxtx = serialPortRxtx; 44 | this.delayReadTime=serialPortRxtx.getSerialContext().getDelay(); 45 | } 46 | 47 | /** 48 | * {@link SerialPortEventListener}接口的实现类 49 | */ 50 | @Override 51 | public void serialEvent(SerialPortEvent event) { 52 | if (serialPortRxtx.isOpen()) { 53 | try { 54 | Thread.sleep(delayReadTime); 55 | } catch (InterruptedException e) { 56 | e.printStackTrace(); 57 | } 58 | switch (event.getEventType()) { 59 | case SerialPortEvent.BI: // 10 60 | case SerialPortEvent.OE: // 7 61 | case SerialPortEvent.FE: // 9 62 | case SerialPortEvent.PE: // 8 63 | case SerialPortEvent.CD: // 6 64 | case SerialPortEvent.CTS: // 3 65 | case SerialPortEvent.DSR: // 4 66 | case SerialPortEvent.RI: // 5 67 | case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 68 | break; 69 | case SerialPortEvent.DATA_AVAILABLE: // 1 70 | InputStream inputStream = serialPortRxtx.getInputStream(); 71 | OutputStream outputStream = serialPortRxtx.getOutputStream(); 72 | readerAndWriter(inputStream, outputStream); 73 | break; 74 | } 75 | } else { 76 | throw new RuntimeException("串口未开启,请查看是否执行了SerialPortRxtx类的open()方法"); 77 | } 78 | } 79 | 80 | /** 81 | * 每次在接收合法数据时执行的读写操作 无返回 82 | * 83 | * @param inputStream 84 | * 串口输入流 85 | * @param outputStream 86 | * 串口输出流 87 | */ 88 | public abstract void readerAndWriter(InputStream inputStream, OutputStream outputStream); 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/SerialContext.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.util.Properties; 4 | 5 | import gnu.io.SerialPort; 6 | 7 | /** 8 | *
9 | *

简介

串口通信的上下文,包含了串口的配置信息 10 | *
11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | *
文件修改记录
修改日期修改人修改内容
2017年1月4日linchunsen新建文件,并实现基本功能
26 | */ 27 | public class SerialContext { 28 | /** 29 | * 配置文件中的key的基础部分(key前缀),即完整的key=key前缀+"."+"端口名"+"."+key 30 | */ 31 | private final static String SERIAL_RXTX_BASE_KEY = "serial.rxtx."; 32 | /** 33 | * 延时等待端口数据准备的时间,端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完 34 | */ 35 | public static final String SERIAL_DELAY_KEY = "delayRead"; 36 | /** 37 | * 延时等待端口数据准备的时间的配置值 38 | */ 39 | private int delay = 1; 40 | 41 | /** 42 | * 超时时间 43 | */ 44 | public static final String SERIAL_TIMEOUT_KEY = "timeout"; 45 | /** 46 | * 超时时间的配置值 47 | */ 48 | private int timeout = 3000; 49 | 50 | /** 51 | * 端口名称 52 | */ 53 | public static final String SERIAL_PORT_KEY = "port"; 54 | /** 55 | * 端口名称的配置值 56 | */ 57 | private String port = "COM3"; 58 | 59 | /** 60 | * 数据位 61 | */ 62 | public static final String SERIAL_DATABITS_KEY = "dataBits"; 63 | /** 64 | * 数据位的配置值 65 | */ 66 | private int dataBits = SerialPort.DATABITS_8; 67 | 68 | /** 69 | * 停止位 70 | */ 71 | public static final String SERIAL_STOPBITS_KEY = "stopBits"; 72 | /** 73 | * 停止位的配置值 74 | */ 75 | private int stopBits = SerialPort.STOPBITS_1; 76 | 77 | /** 78 | * 奇偶校验 79 | */ 80 | public static final String SERIAL_PARITY_KEY = "parity"; 81 | /** 82 | * 奇偶校验的配置值 83 | */ 84 | private int parity = SerialPort.PARITY_NONE; 85 | 86 | /** 87 | * 波特率 88 | */ 89 | public static final String SERIAL_RATE_KEY = "rate"; 90 | /** 91 | * 波特率的配置值 92 | */ 93 | private int rate = 115200; 94 | 95 | /** 96 | * 应用名 97 | * */ 98 | public static final String SERIAL_APP_KEY = "appName"; 99 | /** 100 | * 应用名的默认名为SerialRXTX 101 | */ 102 | private String appName = "SerialRXTX"; 103 | 104 | /** 105 | * 串口上下文的构造方法,采用默认配置 无返回 无参数 106 | * 107 | * @author linchunsen 108 | */ 109 | public SerialContext() { 110 | 111 | } 112 | 113 | /** 114 | * 串口上下文的构造方法,根据传入的配置和key前缀加载配置 无返回 115 | * 116 | * @param properties 117 | * 传入的配置 118 | * @param keyBase 119 | * key前缀 120 | * @author linchunsen 121 | */ 122 | public SerialContext(Properties properties, String portName) { 123 | this.port=portName.toUpperCase(); 124 | loadProperties(properties, SerialContext.SERIAL_RXTX_BASE_KEY +portName); 125 | } 126 | 127 | /** 128 | * 根据系统配置和key前缀加载配置 无返回 129 | * 130 | * @param properties 131 | * 传入的配置 132 | * @param keyBase 133 | * key前缀 134 | * @author linchunsen 135 | */ 136 | public void loadProperties(Properties properties, String keyBase) { 137 | String delay = properties.getProperty(keyBase+"."+ SERIAL_DELAY_KEY, "" + this.delay); 138 | String timeout = properties.getProperty(keyBase+"."+ SERIAL_TIMEOUT_KEY, "" + this.timeout); 139 | String port = properties.getProperty(keyBase+"."+ SERIAL_PORT_KEY, "" + this.port); 140 | String dataBits = properties.getProperty(keyBase+"."+ SERIAL_DATABITS_KEY, "" + this.dataBits); 141 | String stopBits = properties.getProperty(keyBase+"."+ SERIAL_STOPBITS_KEY, "" + this.stopBits); 142 | String parity = properties.getProperty(keyBase+"."+ SERIAL_PARITY_KEY, "" + this.parity); 143 | String rate = properties.getProperty(keyBase+"."+ SERIAL_RATE_KEY, "" + this.rate); 144 | 145 | this.delay = Integer.parseInt(delay); 146 | this.timeout = Integer.parseInt(timeout); 147 | this.port = port; 148 | this.dataBits = Integer.parseInt(dataBits); 149 | //设置数据位 150 | if (this.dataBits==5) { 151 | this.dataBits=SerialPort.DATABITS_5; 152 | } else if (this.dataBits==6) { 153 | this.dataBits=SerialPort.DATABITS_6; 154 | } else if (this.dataBits==7) { 155 | this.dataBits=SerialPort.DATABITS_7; 156 | } else { 157 | this.dataBits=SerialPort.DATABITS_8; 158 | } 159 | float floatStopBits = Float.parseFloat(stopBits); 160 | //设置停止位 161 | if (floatStopBits==2) { 162 | this.stopBits=SerialPort.STOPBITS_2; 163 | } else if (floatStopBits==1.5) { 164 | this.stopBits=SerialPort.STOPBITS_1_5; 165 | } else { 166 | this.stopBits=SerialPort.STOPBITS_1; 167 | } 168 | this.parity = Integer.parseInt(parity); 169 | //设置校验 170 | if (this.parity==1) {//奇校验 171 | this.parity=SerialPort.PARITY_ODD; 172 | } else if(this.parity==2) {//偶校验 173 | this.parity=SerialPort.PARITY_EVEN; 174 | }else {//无校验 175 | this.parity=SerialPort.PARITY_NONE; 176 | } 177 | this.rate = Integer.parseInt(rate); 178 | } 179 | 180 | public int getDelay() { 181 | return delay; 182 | } 183 | 184 | public void setDelay(int delay) { 185 | this.delay = delay; 186 | } 187 | 188 | public int getTimeout() { 189 | return timeout; 190 | } 191 | 192 | public void setTimeout(int timeout) { 193 | this.timeout = timeout; 194 | } 195 | 196 | public String getPort() { 197 | return port; 198 | } 199 | 200 | public void setPort(String port) { 201 | this.port = port; 202 | } 203 | 204 | public int getDataBits() { 205 | return dataBits; 206 | } 207 | 208 | public void setDataBits(int dataBits) { 209 | this.dataBits = dataBits; 210 | } 211 | 212 | public int getStopBits() { 213 | return stopBits; 214 | } 215 | 216 | public void setStopBits(int stopBits) { 217 | this.stopBits = stopBits; 218 | } 219 | 220 | public int getParity() { 221 | return parity; 222 | } 223 | 224 | public void setParity(int parity) { 225 | this.parity = parity; 226 | } 227 | 228 | public int getRate() { 229 | return rate; 230 | } 231 | 232 | public void setRate(int rate) { 233 | this.rate = rate; 234 | } 235 | 236 | public String getAppName() { 237 | return appName; 238 | } 239 | 240 | public void setAppName(String appName) { 241 | this.appName = appName; 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/SerialPortRxtx.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.TooManyListenersException; 7 | 8 | import gnu.io.CommPortIdentifier; 9 | import gnu.io.NoSuchPortException; 10 | import gnu.io.PortInUseException; 11 | import gnu.io.SerialPort; 12 | import gnu.io.SerialPortEventListener; 13 | import gnu.io.UnsupportedCommOperationException; 14 | 15 | /** 16 | *
17 | *

简介

根据串口上下文设置串口配置,并提供启动和关闭的方法 18 | *
19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | *
文件修改记录
修改日期修改人修改内容
2017年1月4日linchunsen新建文件,并实现基本功能
34 | */ 35 | public class SerialPortRxtx { 36 | /** 37 | * 标识端口是否已被打开 38 | */ 39 | private boolean isOpen; 40 | /** 41 | * 属性描述 42 | */ 43 | private CommPortIdentifier portId; 44 | /** 45 | * 属性描述 46 | */ 47 | private SerialPort serialPort; 48 | /** 49 | * 输入流 50 | */ 51 | private InputStream inputStream; 52 | /** 53 | * 输出流 54 | */ 55 | private OutputStream outputStream; 56 | /** 57 | * 串口上下文 58 | */ 59 | private SerialContext serialContext; 60 | 61 | public SerialPortRxtx(SerialContext serialContext) { 62 | this.serialContext = serialContext; 63 | } 64 | 65 | /** 66 | * 开启端口 无返回 无参数 67 | * 68 | * @author linchunsen 69 | */ 70 | public void open() throws NoSuchPortException, PortInUseException, IOException, TooManyListenersException, 71 | UnsupportedCommOperationException { 72 | portId = CommPortIdentifier.getPortIdentifier(serialContext.getPort()); 73 | serialPort = (SerialPort) portId.open(serialContext.getAppName(), serialContext.getTimeout()); 74 | inputStream = serialPort.getInputStream(); 75 | outputStream = serialPort.getOutputStream(); 76 | isOpen = true; 77 | } 78 | 79 | /** 80 | * 关闭端口 无返回 无参数 81 | * 82 | * @author linchunsen 83 | */ 84 | public void close() { 85 | if (isOpen) { 86 | try { 87 | serialPort.notifyOnDataAvailable(false); 88 | serialPort.removeEventListener(); 89 | inputStream.close(); 90 | outputStream.close(); 91 | serialPort.close(); 92 | isOpen = false; 93 | } catch (IOException ex) { 94 | // "关闭串口失败"; 95 | } 96 | } 97 | } 98 | 99 | public boolean isOpen() { 100 | return isOpen; 101 | } 102 | 103 | public void setOpen(boolean isOpen) { 104 | this.isOpen = isOpen; 105 | } 106 | 107 | public SerialContext getSerialContext() { 108 | return serialContext; 109 | } 110 | 111 | public void setSerialContext(SerialContext serialContext) { 112 | this.serialContext = serialContext; 113 | } 114 | 115 | public CommPortIdentifier getPortId() { 116 | return portId; 117 | } 118 | 119 | public void setPortId(CommPortIdentifier portId) { 120 | this.portId = portId; 121 | } 122 | 123 | public SerialPort getSerialPort() { 124 | return serialPort; 125 | } 126 | 127 | public void setSerialPort(SerialPort serialPort) { 128 | this.serialPort = serialPort; 129 | } 130 | 131 | public InputStream getInputStream() { 132 | return inputStream; 133 | } 134 | 135 | public void setInputStream(InputStream inputStream) { 136 | this.inputStream = inputStream; 137 | } 138 | 139 | public OutputStream getOutputStream() { 140 | return outputStream; 141 | } 142 | 143 | public void setOutputStream(OutputStream outputStream) { 144 | this.outputStream = outputStream; 145 | } 146 | 147 | /** 148 | * 为串口设置事件监听器 149 | * 无返回 150 | * @param listener 事件监听器 151 | * @author linchunsen 152 | * @throws TooManyListenersException 153 | * @throws UnsupportedCommOperationException 154 | */ 155 | public void addEventListener(SerialPortEventListener listener) throws TooManyListenersException, UnsupportedCommOperationException { 156 | if (isOpen) { 157 | this.serialPort.removeEventListener(); 158 | this.serialPort.addEventListener(listener); 159 | serialPort.notifyOnDataAvailable(true); 160 | serialPort.setSerialPortParams( 161 | serialContext.getRate(), 162 | serialContext.getDataBits(), 163 | serialContext.getStopBits(), 164 | serialContext.getParity()); 165 | }else { 166 | throw new RuntimeException("串口未打开,请检查是否执行了open()方法"); 167 | } 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/SerialReader.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.TooManyListenersException; 7 | 8 | import gnu.io.NoSuchPortException; 9 | import gnu.io.PortInUseException; 10 | import gnu.io.SerialPortEventListener; 11 | import gnu.io.UnsupportedCommOperationException; 12 | 13 | /** 14 | *
15 | *

简介

串口通讯的常规读取器 16 | *
17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | *
文件修改记录
修改日期修改人修改内容
2016年12月29日linchunsen新建文件,并实现基本功能
32 | */ 33 | public class SerialReader { 34 | 35 | private SerialContext serialContext; 36 | private MessageParseAble messageParse; 37 | 38 | /** 39 | * 根据传入的串口配置上下文和报文解析器来构建报文读取器 40 | * 41 | * @param serialContext 42 | * 串口配置上下文 43 | * @param messageParse 44 | * 报文解析器 45 | */ 46 | public SerialReader(SerialContext serialContext, MessageParseAble messageParse) { 47 | super(); 48 | this.serialContext = serialContext; 49 | this.messageParse = messageParse; 50 | } 51 | 52 | /** 53 | * 启动串口的读监听器 无返回 无参数 54 | * 55 | * @author linchunsen 56 | * @throws UnsupportedCommOperationException 57 | * @throws TooManyListenersException 58 | * @throws IOException 59 | * @throws PortInUseException 60 | * @throws NoSuchPortException 61 | */ 62 | public void startReaderListener() throws NoSuchPortException, PortInUseException, IOException, TooManyListenersException, UnsupportedCommOperationException { 63 | SerialPortRxtx serialPortRxtx = new SerialPortRxtx(this.serialContext); 64 | serialPortRxtx.open(); 65 | SerialPortEventListener listener = new SerialAbstarctListener(serialPortRxtx) { 66 | 67 | private byte[] datas = new byte[1024]; 68 | 69 | @Override 70 | public void readerAndWriter(InputStream inputStream, OutputStream outputStream) { 71 | try { 72 | if (inputStream.available() > 0) { 73 | int size = inputStream.read(datas); 74 | StringBuilder dataBuilder = new StringBuilder(); 75 | String iString; 76 | for (int i = 0; i < size; i++) { 77 | iString = Integer.toHexString(datas[i] & 0xFF); 78 | if (iString.length() == 1) { 79 | iString = "0" + iString; 80 | } 81 | dataBuilder.append(iString); 82 | } 83 | String message = dataBuilder.toString().toUpperCase(); 84 | messageParse.messageParse(message); 85 | } 86 | } catch (IOException e) { 87 | // TODO Auto-generated catch block 88 | e.printStackTrace(); 89 | } catch (Exception e) { 90 | // TODO Auto-generated catch block 91 | e.printStackTrace(); 92 | } 93 | } 94 | }; 95 | serialPortRxtx.addEventListener(listener); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/SerialStarter.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.util.List; 4 | import java.io.IOException; 5 | import java.util.ArrayList; 6 | import java.util.HashSet; 7 | import java.util.Properties; 8 | import java.util.Set; 9 | import java.util.TooManyListenersException; 10 | 11 | import gnu.io.NoSuchPortException; 12 | import gnu.io.PortInUseException; 13 | import gnu.io.UnsupportedCommOperationException; 14 | 15 | /** 16 | *
17 | *

简介

串口通讯的启动类 18 | *
19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | *
文件修改记录
修改日期修改人修改内容
2016年12月29日linchunsen新建文件,并实现基本功能
34 | */ 35 | public class SerialStarter { 36 | 37 | private Properties properties; 38 | 39 | /** 40 | * 根据传入的系统配置来定义串口通讯的启动类 41 | */ 42 | public SerialStarter(Properties properties) { 43 | super(); 44 | this.properties = properties; 45 | } 46 | 47 | private List serialWriters = null; 48 | 49 | /** 50 | * 将传入的消息逐次发给各个串口 51 | * @throws IOException 52 | * @throws UnsupportedCommOperationException 53 | * @throws TooManyListenersException 54 | * @throws PortInUseException 55 | * @throws NoSuchPortException 56 | */ 57 | public void wirte(String message) throws IOException, NoSuchPortException, PortInUseException, TooManyListenersException, UnsupportedCommOperationException { 58 | //如果写串口器列表还未初始化,则初始化 59 | if (serialWriters == null) { 60 | serialWriters = new ArrayList<>(); 61 | Set keys = properties.keySet(); 62 | Set baseKeys = new HashSet<>(); 63 | String key; 64 | String[] keyPace; 65 | // 过滤前缀 66 | for (Object object : keys) { 67 | key = object.toString(); 68 | if (key.startsWith("serial.rxtx.")) { 69 | keyPace = key.split("\\."); 70 | key = keyPace[2]; 71 | baseKeys.add(key); 72 | } 73 | } 74 | for (String baseKey : baseKeys) { 75 | SerialContext serialContext = new SerialContext(properties, baseKey); 76 | serialWriters.add(new SerialWriter(serialContext).init()); 77 | } 78 | } 79 | //将消息逐个写到串口 80 | for (SerialWriter serialWriter : serialWriters) { 81 | serialWriter.write(message); 82 | } 83 | 84 | } 85 | 86 | /** 87 | * 根据传入的报文解析器,以后台进程的形式启动串口读取器 88 | * 89 | * @param messageParser 90 | * 传入的报文解析器 91 | */ 92 | public void startReader(MessageParseAble messageParser) { 93 | final MessageParseAble messageParse = messageParser; 94 | Set keys = properties.keySet(); 95 | Set baseKeys = new HashSet<>(); 96 | String key; 97 | String[] keyPace; 98 | // 过滤前缀 99 | for (Object object : keys) { 100 | key = object.toString(); 101 | if (key.startsWith("serial.rxtx.")) { 102 | keyPace = key.split("\\."); 103 | key = keyPace[2]; 104 | baseKeys.add(key); 105 | } 106 | } 107 | for (String baseKey : baseKeys) { 108 | SerialContext serialContext = new SerialContext(properties, baseKey); 109 | new Thread() { 110 | SerialReader serialTask = new SerialReader(serialContext, messageParse); 111 | 112 | @Override 113 | public void run() { 114 | try { 115 | serialTask.startReaderListener(); 116 | } catch (NoSuchPortException e) { 117 | // TODO Auto-generated catch block 118 | e.printStackTrace(); 119 | } catch (PortInUseException e) { 120 | // TODO Auto-generated catch block 121 | e.printStackTrace(); 122 | } catch (IOException e) { 123 | // TODO Auto-generated catch block 124 | e.printStackTrace(); 125 | } catch (TooManyListenersException e) { 126 | // TODO Auto-generated catch block 127 | e.printStackTrace(); 128 | } catch (UnsupportedCommOperationException e) { 129 | // TODO Auto-generated catch block 130 | e.printStackTrace(); 131 | } 132 | } 133 | 134 | }.start(); 135 | System.out.println("正在监听串口 " + baseKey.toUpperCase()); 136 | } 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/linchunsen/rxtx/SerialWriter.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.util.TooManyListenersException; 6 | 7 | import gnu.io.NoSuchPortException; 8 | import gnu.io.PortInUseException; 9 | import gnu.io.UnsupportedCommOperationException; 10 | 11 | /** 12 | *
13 | *

简介

串口通讯的常规读取器 14 | *
15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | *
文件修改记录
修改日期修改人修改内容
2016年12月29日linchunsen新建文件,并实现基本功能
30 | */ 31 | public class SerialWriter { 32 | 33 | private SerialContext serialContext; 34 | private OutputStream outputStream; 35 | 36 | public SerialWriter(SerialContext serialContext) { 37 | super(); 38 | this.serialContext = serialContext; 39 | } 40 | 41 | // 标识串口是否已经初始化 42 | private boolean isInited = false; 43 | 44 | /** 45 | * 初始化写串口器 46 | * 47 | * @return 初始化后的写串口器对象 48 | * @throws UnsupportedCommOperationException 49 | * @throws TooManyListenersException 50 | * @throws IOException 51 | * @throws PortInUseException 52 | * @throws NoSuchPortException 53 | */ 54 | public SerialWriter init() throws NoSuchPortException, PortInUseException, IOException, TooManyListenersException, 55 | UnsupportedCommOperationException { 56 | SerialPortRxtx serialPortRxtx = new SerialPortRxtx(this.serialContext); 57 | serialPortRxtx.open(); 58 | this.outputStream = serialPortRxtx.getOutputStream(); 59 | this.isInited = true; 60 | return this; 61 | } 62 | 63 | /** 64 | * 在串口初始化后,向串口中写入字符串 65 | * 66 | * @param message 67 | * 需要写入的字符串 68 | * @throws IOException 69 | */ 70 | public void write(String message) throws IOException { 71 | if (isInited) { 72 | int length = message.length(); 73 | byte[] bytes = new byte[length / 2]; 74 | for (int i = 0; i < length; i++) { 75 | bytes[i / 2] = (byte) (((Character.digit(message.charAt(i), 16) << 4) 76 | + Character.digit(message.charAt(++i), 16))); 77 | } 78 | outputStream.write(bytes); 79 | } else { 80 | throw new RuntimeException("写串口器尚未初始化,请执行init()方法后重试"); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/com/linchunsen/rxtx/example/Main.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx.example; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.sql.Connection; 7 | import java.sql.SQLException; 8 | import java.util.Properties; 9 | import java.util.TooManyListenersException; 10 | 11 | import com.linchunsen.rxtx.JdbcUtil; 12 | import com.linchunsen.rxtx.MessageParseAble; 13 | import com.linchunsen.rxtx.SerialStarter; 14 | 15 | import gnu.io.NoSuchPortException; 16 | import gnu.io.PortInUseException; 17 | import gnu.io.UnsupportedCommOperationException; 18 | 19 | /** 20 | *
21 | *

简介

项目的启动类,第一个参数为配置文件,并且是必须的参数 22 | *
23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | *
文件修改记录
修改日期修改人修改内容
2016年12月29日linchunsen新建文件,并实现基本功能
38 | */ 39 | public class Main { 40 | public static void main(String[] args) { 41 | reader(args); 42 | } 43 | 44 | /** 45 | * 使用rxtx循环100次向配置文件中的串口写入数据 46 | * */ 47 | public static void writer(String[] args) { 48 | String filePath=args[0]; 49 | try { 50 | //加载配置文件对象 51 | FileInputStream fileInputStream = new FileInputStream(filePath); 52 | Properties properties = new Properties(); 53 | properties.load(fileInputStream); 54 | //循环100次向配置文件中的串口写入数据 55 | SerialStarter serialStarter = new SerialStarter(properties); 56 | for (int i = 0; i < 100; i++) { 57 | Thread.sleep(500); 58 | serialStarter.wirte("6801A10B16"); 59 | } 60 | } catch (FileNotFoundException e) { 61 | e.printStackTrace(); 62 | } catch (IOException e) { 63 | // TODO Auto-generated catch block 64 | e.printStackTrace(); 65 | } catch (NoSuchPortException e) { 66 | // TODO Auto-generated catch block 67 | e.printStackTrace(); 68 | } catch (PortInUseException e) { 69 | // TODO Auto-generated catch block 70 | e.printStackTrace(); 71 | } catch (TooManyListenersException e) { 72 | // TODO Auto-generated catch block 73 | e.printStackTrace(); 74 | } catch (UnsupportedCommOperationException e) { 75 | // TODO Auto-generated catch block 76 | e.printStackTrace(); 77 | } catch (InterruptedException e) { 78 | // TODO Auto-generated catch block 79 | e.printStackTrace(); 80 | } 81 | } 82 | 83 | /** 84 | * 使用rxtx监听读取配置文件中的串口发送来的数据,并将其解析并发送到数据库 85 | * */ 86 | public static void reader(String[] args) { 87 | String filePath=args[0]; 88 | try { 89 | //加载配置文件对象 90 | FileInputStream fileInputStream = new FileInputStream(filePath); 91 | Properties properties = new Properties(); 92 | properties.load(fileInputStream); 93 | //根据配置文件实例化JDBC工具 94 | JdbcUtil myJdbcUtil=new JdbcUtil(); 95 | myJdbcUtil.load(properties); 96 | Connection connection=myJdbcUtil.getConnection(); 97 | //新建渲染器 98 | MessageParseAble messageParse = new MessageParse(connection); 99 | //监听读取配置文件中的串口发送来的数据,并将其解析并发送到数据库 100 | SerialStarter serialStarter = new SerialStarter(properties); 101 | serialStarter.startReader(messageParse); 102 | } catch (FileNotFoundException e) { 103 | e.printStackTrace(); 104 | } catch (IOException e) { 105 | // TODO Auto-generated catch block 106 | e.printStackTrace(); 107 | } catch (ClassNotFoundException e) { 108 | // TODO Auto-generated catch block 109 | e.printStackTrace(); 110 | } catch (SQLException e) { 111 | // TODO Auto-generated catch block 112 | e.printStackTrace(); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/linchunsen/rxtx/example/MessageParse.java: -------------------------------------------------------------------------------- 1 | package com.linchunsen.rxtx.example; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.SQLException; 6 | 7 | import com.linchunsen.rxtx.MessageParseAble; 8 | 9 | /** 10 | *
11 | *

简介

报文解析接口的实现类,该类能够解析报文并将报文解析的内容提交到数据库 12 | *
13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | *
文件修改记录
修改日期修改人修改内容
2017年1月4日linchunsen新建文件,并实现基本功能
28 | */ 29 | public class MessageParse implements MessageParseAble { 30 | 31 | private Connection connection; 32 | 33 | public MessageParse(Connection connection) throws ClassNotFoundException, SQLException { 34 | super(); 35 | this.connection=connection; 36 | } 37 | 38 | /** 39 | * 将接收到的数据添加到数据库Productive Process表 40 | * 41 | * @return 返回行数 42 | * @throws SQLException 43 | */ 44 | public int insertProductiveProcess(String machineId, String testType) throws SQLException { 45 | String resultFlag = testType.equals("A1") ? "00" : "01"; 46 | String sql = null; 47 | if (resultFlag.equals("00")) { 48 | sql = "INSERT INTO A_PRODUCTIVE_PROCESS(METERID,DATAFLAG,TASKID,FINISH_DATE,THREADID,RESULTFLAG) VALUES('73301','" 49 | + machineId + "','73301',getdate(),'73301','" + resultFlag + "')"; 50 | } else if (resultFlag.equals("01")) { 51 | sql = "INSERT INTO A_PRODUCTIVE_PROCESS(METERID,DATAFLAG,TASKID,FINISH_DATE,THREADID,RESULTFLAG,REASON_CODE) VALUES('73301','" 52 | + machineId + "','73301',getdate(),'73301','" + resultFlag + "','" + testType + "')"; 53 | } else { 54 | return 0; 55 | } 56 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 57 | int num = preparedStatement.executeUpdate(); 58 | preparedStatement.close(); 59 | if (machineId.equals("02") && resultFlag.equals("00")) { 60 | insertYieldTotal(); 61 | } 62 | connection.commit(); 63 | return num; 64 | } 65 | 66 | /** 67 | * 将接收到的数据添加到数据库Yield Total表,只有设备2返回成功时插入 68 | * 69 | * @return 返回行数 70 | * @throws SQLException 71 | */ 72 | public int insertYieldTotal() throws SQLException { 73 | String sql = "INSERT INTO A_YIELD_TOTAL(TASK_ID,FINISH_DATE,QUANTITY,THREAD_ID) VALUES('73301',getdate(),1,'73301')"; 74 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 75 | int num = preparedStatement.executeUpdate(); 76 | preparedStatement.close(); 77 | return num; 78 | } 79 | /** 80 | * 报文解析接口的抽象方法实现 81 | * @param message 接收到的报文 82 | * @throws SQLException 83 | * */ 84 | @Override 85 | public void messageParse(String message) throws SQLException { 86 | if (message.startsWith("68") && message.endsWith("16")) { 87 | String machineId = message.substring(2, 4); 88 | String testType = message.substring(4, 6); 89 | System.out.println("设备号:"+machineId+" 状态:"+testType); 90 | insertProductiveProcess(machineId, testType); 91 | } else { 92 | throw new RuntimeException("报文格式错误,非法的头部和尾部"); 93 | } 94 | } 95 | } 96 | --------------------------------------------------------------------------------