主要项目框架采用的事若依的框架,就不做多介绍
下面主要贴代码和部分注释
在pom.xml文件中引入netty包
-
- <dependency>
- <groupId>io.nettygroupId>
- <artifactId>netty-allartifactId>
- <version>4.1.53.Finalversion>
- 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
() { - @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、后续有增加的功能时候,再进行更新