SpringBoot基于Netty实现对接硬件,接受硬件报文
3、编写自定义处理类MyChannelHandler。主要项目框架采用的事若依的框架,就不做多介绍。在pom.xml文件中引入netty包。5、后续有增加的功能时候,再进行更新。2、编写NettyServer类。4、在启动类上加上该启动配置。下面主要贴代码和部分注释。
·
主要项目框架采用的事若依的框架,就不做多介绍
下面主要贴代码和部分注释
在pom.xml文件中引入netty包
<!--netty-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.53.Final</version>
</dependency>
2、编写NettyServer类
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.stereotype.Component;
/**
* @Author DCXPC
* @Description //TODO 采用netty 监听服务器端口,并处理后面逻辑
* @Date 2023/9/15 9:57
**/
@Component
public class NettyServer {
private final int port = 9007;
public void start() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
// 指定Channel
.channel(NioServerSocketChannel.class)
//使用自定义处理类
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加自定义的ChannelHandler
pipeline.addLast(new MyChannelHandler());
}
})
//服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
.option(ChannelOption.SO_BACKLOG, 128)
//保持长连接,2小时无数据激活心跳机制
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口,开始接收进来的连接
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
3、编写自定义处理类MyChannelHandler
package com.ruoyi.common.netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author DCXPC
* @ClassName MyChannelHandler
* @description: TODO 自定义的数据处理方法,用于处理收到的数据
* @date 2023年09月14日
*/
public class MyChannelHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 处理接收到的数据
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("----------------------------------------------------------------------------------------------------");
System.out.println("Received time: " +sdf.format(new Date()));
/**数据转换**/
// 获取字节数组
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.getBytes(byteBuf.readerIndex(), bytes);
// 将字节数组转换为十六进制字符串
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) {
hexString.append('0'); // 如果得到的十六进制只有一位,则在前面补零
}
hexString.append(hex);
}
String hexStringResult = hexString.toString(); // 转换后的十六进制字符串
System.out.println("Received data:"+hexStringResult);
dealData(hexStringResult);
/**接收到的数据是水文规约,需要翻译成有用的数据*/
// dealData(
// "7e7e" +//4
// "01" +//6
// "0034120201" +//16
// "1234" +//20
// "32" +//22
// "003b" +//26
// "02" +//28
// "0102" +//32
// "230914203800" +//44
// "f1f1" +//48
// "0034120201" +//58
// "49" +//60
// "f0f0" +//64
// "2309142038" +//74
// "3c23" +//水位引导 78
// "00002321" +//水位2.321 86
// "682a" +//表1瞬时流量引导 90
// "0000004644" +//表1瞬时流量46.44 100
// "6033" +//表1累积流量引导 104
// "000012369332" +//表1累积流量12369.332 116
// "692a" +//表2瞬时流量引导 120
// "0000008723" +//表2瞬时流量87.23 130
// "6133" +//表2累积流量引导 134
// "000023223654" +//表2累积流量23223.654 146
// "03ecaf");
byteBuf.release();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 处理异常
cause.printStackTrace();
ctx.close();
}
//处理数据
public void dealData(String hexMsg){
String date = hexMsg.substring(32,44);
System.out.println("发报时间:"+date);
String waterleve = hexMsg.substring(78,86);
System.out.println("水位高度:"+addpoint(waterleve,hexMsg.substring(77,78)));;
String ssll1 = hexMsg.substring(90,100);
System.out.println("表1瞬时流量:"+addpoint(ssll1,"2"));;
String ljll1 = hexMsg.substring(104,116);
System.out.println("表1累积流量:"+addpoint(ljll1,"3"));;
String ssll2 = hexMsg.substring(120,130);
System.out.println("表2瞬时流量:"+addpoint(ssll2,"2"));;
String ljll2 = hexMsg.substring(134,146);
System.out.println("表2累积流量:"+addpoint(ljll2,"3"));;
}
//小数点添加
public float addpoint(String numStr,String locationStr){
int locationNum = Integer.valueOf(locationStr);
StringBuilder sb = new StringBuilder(numStr);
sb.insert(numStr.length()-locationNum,".");
float num = Float.valueOf(sb.toString());
return num;
}
}
4、在启动类上加上该启动配置
import com.ruoyi.common.netty.NettyServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author ruoyi
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class RuoYiApplication implements CommandLineRunner {
@Autowired
private NettyServer nettyServer;
private static final Logger log = LoggerFactory.getLogger(RuoYiApplication.class);
public static void main(String[] args) {
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("---项目启动成功---");
}
@Override
public void run(String... args) throws Exception {
nettyServer.start();
}
}
5、后续有增加的功能时候,再进行更新
更多推荐
已为社区贡献2条内容
所有评论(0)