目录

SpringBoot基于Netty实现对接硬件,接受硬件报文

目录

SpringBoot基于Netty实现对接硬件,接受硬件报文

主要项目框架采用的事若依的框架,就不做多介绍

下面主要贴代码和部分注释

在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、后续有增加的功能时候,再进行更新

文章参考: