From e13552b6922c7cea3edfa20f8c14040ebdd9de48 Mon Sep 17 00:00:00 2001 From: haozq <1611483981@qq.com> Date: Wed, 31 Jul 2024 09:35:32 +0800 Subject: [PATCH] =?UTF-8?q?TCP=20=E6=9C=8D=E5=8A=A1=E7=AB=AF=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=A7=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 12 ++ .../aqd/SpringBootSecurityApplication.java | 2 + .../com/bonus/aqd/base/dao/DevDataMapper.java | 32 +++++ .../java/com/bonus/aqd/base/entity/DevVO.java | 33 +++++ ...BootNettyChannelInboundHandlerAdapter.java | 31 ++++- .../BootNettyChannelInitializer.java | 8 +- .../bonus/aqd/tcpservice/BootNettyServer.java | 2 +- .../com/bonus/aqd/tcpservice/ByteUtil.java | 34 ++++++ .../com/bonus/aqd/tcpservice/HexDecoder.java | 20 +++ .../aqd/tcpservice/NettyServerHandler.java | 3 - .../bonus/aqd/tcpservice/ServerHandler.java | 25 ++++ .../com/bonus/aqd/tcpservice/SpringUtils.java | 114 ++++++++++++++++++ src/main/resources/application.yml | 2 +- .../resources/mappers/base/DevDataMapper.xml | 34 ++++++ 14 files changed, 339 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/bonus/aqd/base/dao/DevDataMapper.java create mode 100644 src/main/java/com/bonus/aqd/base/entity/DevVO.java create mode 100644 src/main/java/com/bonus/aqd/tcpservice/ByteUtil.java create mode 100644 src/main/java/com/bonus/aqd/tcpservice/HexDecoder.java create mode 100644 src/main/java/com/bonus/aqd/tcpservice/ServerHandler.java create mode 100644 src/main/java/com/bonus/aqd/tcpservice/SpringUtils.java create mode 100644 src/main/resources/mappers/base/DevDataMapper.xml diff --git a/pom.xml b/pom.xml index e760cbc..969b022 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,18 @@ mapper 4.1.5 + + org.apache.mina + mina-core + 2.2.3 + + + + + io.netty + netty-all + 4.1.68.Final + org.apache.poi diff --git a/src/main/java/com/bonus/aqd/SpringBootSecurityApplication.java b/src/main/java/com/bonus/aqd/SpringBootSecurityApplication.java index 51f1229..3d56d57 100644 --- a/src/main/java/com/bonus/aqd/SpringBootSecurityApplication.java +++ b/src/main/java/com/bonus/aqd/SpringBootSecurityApplication.java @@ -8,12 +8,14 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; /** * @author 黑子 */ @MapperScan({"com.bonus.aqd.*.*.dao", "com.bonus.aqd.*.dao"}) @SpringBootApplication(exclude={MongoAutoConfiguration.class}) +@EnableAsync public class SpringBootSecurityApplication implements CommandLineRunner { diff --git a/src/main/java/com/bonus/aqd/base/dao/DevDataMapper.java b/src/main/java/com/bonus/aqd/base/dao/DevDataMapper.java new file mode 100644 index 0000000..db1be78 --- /dev/null +++ b/src/main/java/com/bonus/aqd/base/dao/DevDataMapper.java @@ -0,0 +1,32 @@ +package com.bonus.aqd.base.dao; + +import com.bonus.aqd.base.entity.DevVO; +import org.springframework.stereotype.Repository; + +/** + * @author 黑子 + */ +@Repository(value = "DevDataMapper") +public interface DevDataMapper { + + + /** + * 更新双沟状态 + * @param devVO + */ + void updateData(DevVO devVO); + + /** + * 更新在线状态 + * @param devVO + */ + void updateDevStatus(DevVO devVO); + + + /** + * 更新在线状态 + * @param devVO + */ + void downDevStatus(DevVO devVO); + +} diff --git a/src/main/java/com/bonus/aqd/base/entity/DevVO.java b/src/main/java/com/bonus/aqd/base/entity/DevVO.java new file mode 100644 index 0000000..e74c029 --- /dev/null +++ b/src/main/java/com/bonus/aqd/base/entity/DevVO.java @@ -0,0 +1,33 @@ +package com.bonus.aqd.base.entity; + +import lombok.Data; + +/** + * 设备实体类 + * @author 黑子 + */ +@Data +public class DevVO { + + private String devCode; + + private String devA; + + private String devB; + + private String devStatus; + + private String devAtime; + + private String devBtime; + + private String startTime; + + private String devTime; + /** + * 通道id + */ + private String channId; + + +} diff --git a/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInboundHandlerAdapter.java b/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInboundHandlerAdapter.java index 3b8f5ad..89883c2 100644 --- a/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInboundHandlerAdapter.java +++ b/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInboundHandlerAdapter.java @@ -1,10 +1,16 @@ package com.bonus.aqd.tcpservice; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; import java.io.IOException; import java.net.InetSocketAddress; @@ -13,8 +19,16 @@ import java.net.InetSocketAddress; * @author 黑子 */ @ChannelHandler.Sharable +@Component +@Slf4j public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandlerAdapter { + + + + public SaveDataService service = SpringUtils.getBean(SaveDataService.class); + + /** * 注册时执行 */ @@ -22,7 +36,7 @@ public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandler public void channelRegistered(ChannelHandlerContext ctx) throws Exception { //注册通道 super.channelRegistered(ctx); - System.out.println("--channelRegistered--" + ctx.channel().id().toString()); + System.out.println("--通道号注册--" + ctx.channel().id().toString()); } /** @@ -32,7 +46,8 @@ public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandler public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { //通道离线 super.channelUnregistered(ctx); - System.out.println("--channelUnregistered--" + ctx.channel().id().toString()); + System.out.println("--通道号离线--" + ctx.channel().id().toString()); + service.downDevStatus(ctx.channel().id().toString()); } /** @@ -44,18 +59,24 @@ public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandler if (msg == null) { return; } + ByteBuf in = (ByteBuf) msg; + byte[] bs = new byte[in.readableBytes()]; + in.readBytes(bs); + String order = ByteUtil.bytesToHexString(bs); + service.addDataInfo(order.trim()); //转成String - String data = (String) msg; + String data =order; //替换掉 换行 和 空格 data = data.replaceAll("\r|\n", ""); //获取通道ID 并打印 String channelId = ctx.channel().id().toString(); - System.out.println("channelId=" + channelId + "data=" + data); - + System.err.println("通道号---> " + channelId + "--->数据---> " + data); // 这里我将通道id作为code来使用,实际是需要msg里来摘取的客户端数据里的唯一值的 // 如果没有则创建 如果有,更新data值 BootNettyChannel b = BootNettyChannelCache.get("server:" + channelId); if (b == null) { + // 第一次更新状态 + service.updateDataStatus(order.trim(),channelId); //创建通道 BootNettyChannel bnc = new BootNettyChannel(); bnc.setChannel(ctx.channel()); diff --git a/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInitializer.java b/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInitializer.java index 1821668..a61b4f2 100644 --- a/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInitializer.java +++ b/src/main/java/com/bonus/aqd/tcpservice/BootNettyChannelInitializer.java @@ -29,9 +29,11 @@ public class BootNettyChannelInitializer extends ChannelInitializ ch.pipeline().addLast(new IdleStateHandler(READ_TIME_OUT, WRITE_TIME_OUT, ALL_TIME_OUT, TimeUnit.SECONDS)); // 带编码 - ch.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); - ch.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); - +// ch.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); +// ch.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); +// 在Netty的pipeline中添加 + ch.pipeline().addLast(new HexDecoder()); + // ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8)); // // ChannelOutboundHandler,依照逆序执行 // ch.pipeline().addLast("encoder", new StringEncoder()); // diff --git a/src/main/java/com/bonus/aqd/tcpservice/BootNettyServer.java b/src/main/java/com/bonus/aqd/tcpservice/BootNettyServer.java index c95cb40..769a3ba 100644 --- a/src/main/java/com/bonus/aqd/tcpservice/BootNettyServer.java +++ b/src/main/java/com/bonus/aqd/tcpservice/BootNettyServer.java @@ -9,7 +9,7 @@ import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; /** - * + * 蚂蚁舞 * @author 黑子 */ public class BootNettyServer { diff --git a/src/main/java/com/bonus/aqd/tcpservice/ByteUtil.java b/src/main/java/com/bonus/aqd/tcpservice/ByteUtil.java new file mode 100644 index 0000000..6d253fd --- /dev/null +++ b/src/main/java/com/bonus/aqd/tcpservice/ByteUtil.java @@ -0,0 +1,34 @@ +package com.bonus.aqd.tcpservice; + +/** + * @author 黑子 + */ +public class ByteUtil { + + public static byte[] hexString2Bytes(String src) { + + int l = src.length() / 2; + + byte[] ret = new byte[l]; + + for (int i = 0; i < l; i++) { + ret[i] = (byte) Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue(); + } + return ret; + } + public static String bytesToHexString(byte[] src) { + StringBuilder stringBuilder = new StringBuilder(""); + if (src == null || src.length <= 0) { + return null; + } + for (int i = 0; i < src.length; i++) { + int v = src[i] & 0xFF; + String hv = Integer.toHexString(v); + if (hv.length() < 2) { + stringBuilder.append(0); + } + stringBuilder.append(hv); + } + return stringBuilder.toString(); + } +} diff --git a/src/main/java/com/bonus/aqd/tcpservice/HexDecoder.java b/src/main/java/com/bonus/aqd/tcpservice/HexDecoder.java new file mode 100644 index 0000000..afa7110 --- /dev/null +++ b/src/main/java/com/bonus/aqd/tcpservice/HexDecoder.java @@ -0,0 +1,20 @@ +package com.bonus.aqd.tcpservice; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +public class HexDecoder extends ByteToMessageDecoder { + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + ByteBuf buffer = ctx.alloc().buffer(); + while (in.isReadable()) { + byte b = in.readByte(); + buffer.writeBytes(new byte[]{b}); + } + out.add(buffer); + } +} + diff --git a/src/main/java/com/bonus/aqd/tcpservice/NettyServerHandler.java b/src/main/java/com/bonus/aqd/tcpservice/NettyServerHandler.java index 54c29a2..b155574 100644 --- a/src/main/java/com/bonus/aqd/tcpservice/NettyServerHandler.java +++ b/src/main/java/com/bonus/aqd/tcpservice/NettyServerHandler.java @@ -4,9 +4,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import lombok.extern.slf4j.Slf4j; -/** - * @author 黑子 - */ @Slf4j public class NettyServerHandler extends ChannelInboundHandlerAdapter { /** diff --git a/src/main/java/com/bonus/aqd/tcpservice/ServerHandler.java b/src/main/java/com/bonus/aqd/tcpservice/ServerHandler.java new file mode 100644 index 0000000..ce8a4c7 --- /dev/null +++ b/src/main/java/com/bonus/aqd/tcpservice/ServerHandler.java @@ -0,0 +1,25 @@ +package com.bonus.aqd.tcpservice; + +import org.apache.mina.core.service.IoHandlerAdapter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * @author 黑子 + */ +@Component +public class ServerHandler extends IoHandlerAdapter { + + @Autowired + protected SaveDataService service; + private static ServerHandler serverHandler ; + @PostConstruct //通过@PostConstruct实现初始化bean之前进行的操作 + public void init() { + serverHandler = this; + serverHandler.service = this.service; + // 初使化时将已静态化的testService实例化 + } + +} diff --git a/src/main/java/com/bonus/aqd/tcpservice/SpringUtils.java b/src/main/java/com/bonus/aqd/tcpservice/SpringUtils.java new file mode 100644 index 0000000..cea8c74 --- /dev/null +++ b/src/main/java/com/bonus/aqd/tcpservice/SpringUtils.java @@ -0,0 +1,114 @@ +package com.bonus.aqd.tcpservice; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.stereotype.Component; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author bonus + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + SpringUtils.beanFactory = beanFactory; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException + { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws BeansException + * + */ + public static T getBean(Class clz) throws BeansException + { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) + { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) + { + return (T) AopContext.currentProxy(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ce9adb7..cb09c44 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -37,5 +37,5 @@ zhly: enable: false netty: - port: 6665 + port: 6666 diff --git a/src/main/resources/mappers/base/DevDataMapper.xml b/src/main/resources/mappers/base/DevDataMapper.xml new file mode 100644 index 0000000..42376b9 --- /dev/null +++ b/src/main/resources/mappers/base/DevDataMapper.xml @@ -0,0 +1,34 @@ + + + + + + + update tb_device + set dev_a=#{devA} ,dev_b=#{devB} + + , dev_a_time=#{devAtime} + + + , dev_b_time= #{devBtime} + + ,dev_time=now() + where dev_code=#{devCode} + + + update tb_device + set dev_status=#{devStatus}, + + chann_id= #{channId}, + + state_time=now(), + dev_time=now() + where dev_code=#{devCode} + + + update tb_device + set dev_status=0, chann_id= #{channId} + where chann_id=#{channId} + + \ No newline at end of file