springboot集成netty实现物联网设备数据接收、下发指令(控制)、多开监听端口、区分端口

引入依赖jar

		<dependency>
		    <groupId>io.netty</groupId>
		    <artifactId>netty-all</artifactId>
		    <version>4.1.32.Final</version>
		</dependency>
		<dependency>
		   <groupId>org.springframework.boot</groupId>
		   <artifactId>spring-boot-configuration-processor</artifactId>
		   <optional>true</optional>
		</dependency> 

开启要监听的端口

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
//物联网 开启检测 并写入数据库
@Component
public class NettyStart {
		    @Resource
		    private ServerHandler serverHandler;
		    private EventLoopGroup bossGroup = new NioEventLoopGroup();
		    private EventLoopGroup workGroup = new NioEventLoopGroup();
		    
		    /**
		     * 启动netty服务
		     * @throws InterruptedException
		     */
		    @PostConstruct
		    public void start() throws InterruptedException {
		        ServerBootstrap b=new ServerBootstrap();
		        b.group(bossGroup,workGroup)
		                .channel(NioServerSocketChannel.class)
		                .option(ChannelOption.SO_BACKLOG,128)
		                .childHandler(new ChannelInitializer<SocketChannel>()  {
		                    @Override
		                    protected void initChannel(SocketChannel socketChannel) throws Exception {
		                        socketChannel.pipeline().addLast(serverHandler);
		                    }
		                });
		        ChannelFuture future = b.bind(9011).sync();//开启需要监听 的端口  
		        ChannelFuture future1 = b.bind(9012).sync();//开启需要监听 的端口 多开端口
		        if (future.isSuccess()) {
		            	System.out.println("启动 9011成功");
		        }
		        if (future1.isSuccess()) {
		        	System.out.println("启动 9012成功");
		    	}
		    }
		    
		    /**
		     * 销毁
		     */
		    @PreDestroy
		    public void destroy() {
		        bossGroup.shutdownGracefully().syncUninterruptibly();
		        workGroup.shutdownGracefully().syncUninterruptibly();
		        System.out.println("关闭 Netty 成功");
		    }
}

实现类

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.yun.Util.TimeUtile;
import com.yun.admin.entity.Product_data;
import com.yun.admin.service.impl.Product_dataServiceImpl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import net.sf.json.JSONObject;

//物联网 开启检测端口 并写入数据库
@Component
@Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
		    //此处注入数据源操作sql   执行插入设备上传的数据
		    @Resource
		    private Product_dataServiceImpl product_dataServiceImpl;
		    //  将当前客户端连接 存入map   实现控制设备下发 参数
		    public  static Map<String, ChannelHandlerContext> map = new HashMap<String, ChannelHandlerContext>();
		   
		    /**
		     * 获取数据
		     * @param ctx 上下文
		     * @param msg 获取的数据
		     * @throws UnsupportedEncodingException 
		     */
		    @Override
		    public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException{
		    	//msg为接收到的客户端传递的数据   个人这边直接传的json 数据
		    	ByteBuf readMessage= (ByteBuf) msg;
		    	//解析客户端json 数据
		        JSONObject json=JSONObject.fromObject(readMessage.toString(CharsetUtil.UTF_8));
		        System.out.println("接收到的数据"+readMessage.toString(CharsetUtil.UTF_8));
		        
		        //获取客户端的请求地址  取到的值为客户端的 ip+端口号
		        String url=ctx.channel().remoteAddress().toString();//设备请求地址(个人将设备的请求地址当作 map 的key)
		       //将当前的设备ip+端口存进map  当做下发设备的标识的key
		       //如果已经存在就不用重复存入map
		        if(map.get(url)==null){
		        		map.put(url, ctx);
		    	}
		        int users=0; 
		        //设备请求的 服务器端的地址   用作监听设备请求的那个端口  
		        String servicePort=ctx.channel().localAddress().toString();
		        //判断端口如果客户端请求的端口号为9011  
		         System.out.println("向:"+servicePort.substring(servicePort.length()-4, servicePort.length())+" 端口写入数据");
		        if(servicePort.substring(servicePort.length()-4, servicePort.length()).equals("9011")){
				        	Product_data product_data=new Product_data(); 
			        		//设备请求地址  存入数据库  下方controller层 通过设备id查询此地址   取到map种存入的 ChannelHandlerContext 实现数据下发
					        product_data.setUrl(url);
					        product_data.setJson(readMessage.toString(CharsetUtil.UTF_8));//设备请求时原生数据  
					        product_data.setDeviceID(json.get("deviceID").toString());//设备数据1
					        product_data.setPower1(json.get("power1").toString());//设备数据2
					        product_data.setPower2(json.get("power2").toString());//设备数据3
					        product_data.setPower3(json.get("power3").toString());//设备数据4
					        product_data.setAcquisitionTime(TimeUtile.showDate());//时间 (个人整的当前时间工具类  替换成自己获取当前时间的方法即可)
					        //执行写入操作    此处写你们要插入的表操作语句即可
					        users = product_dataServiceImpl.add_Device_shuju(product_data);
		         }else{
		        	 		//否则取另外的值 进行写入 数据库
		        	 		Product_data product_data=new Product_data(); 
		        	 		//设备请求地址  存入数据库  下方controller层 通过设备id查询此地址   取到map种存入的 ChannelHandlerContext 实现数据下发
					        product_data.setUrl(url);
					        product_data.setJson(readMessage.toString(CharsetUtil.UTF_8));//设备请求时原生数据  
					        product_data.setDeviceID(json.get("deviceID").toString());//设备数据1
					        product_data.setData1(json.get("data1").toString());//设备数据2
					        product_data.setData2(json.get("data2").toString());//设备数据3
					        product_data.setData3(json.get("data3").toString());//设备数据4
					        product_data.setAcquisitionTime(TimeUtile.showDate());//时间 (个人整的当前时间工具类  替换成自己获取当前时间的方法即可)
					        //执行写入操作    此处写你们要插入的表操作语句即可
					        users = product_dataServiceImpl.add_Device_data(product_data);
		         }
		        String rmsg;
		        if(users>0){
		        		rmsg="11 02 00 C4 00 16 ";//返回成功的信息
		         }else{
		        	 	rmsg="0";//返回失败的信息
		         }
		        ByteBuf message= Unpooled.copiedBuffer(rmsg.getBytes());//处理返回的信息
		      	 //ctx.write(in2);//返回信息 
		        ctx.writeAndFlush(message);//返回信息 
			   	 //刷新缓存区
			   	ctx.flush();
		    }
		    
		    @Override
		    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		   		 cause.printStackTrace();
		   		 ctx.close();
		    }
}

至此就可以实现 服务器端接受设备传递的数据了 ,服务端 可以根据 当前电脑ip地址 +9011(个人开的9011端口 )就可以发送数据并写入数据库了

接下来是服务端向设备发送指令

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.yun.Util.Result;
import com.yun.Utile.SheBei.ServerHandler;
import com.yun.admin.entity.Product_data;
import com.yun.admin.service.impl.Product_dataServiceImpl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

@Controller
@RequestMapping("/equipmenContro")
public class EquipmentController {
		 
		@Autowired 
		private Product_dataServiceImpl product_dataServiceImpl;
		
		@RequestMapping(value="/equipment",method=RequestMethod.POST)
		public @ResponseBody Result equipment(Product_data product_data){
			 //入参 设备id   根据设备id  查询设备最后一次录入数据时候的 ip(url)地址  实现下发
		     Product_data product=product_dataServiceImpl.select_Product_data_url(product_data);
		     if(product!=null){
		     	//需要给设备发送的 16进制数据
		     	String msg=" 16 27 88 90 12 45 31 15 41 ";
		     	//转码
		    	 ByteBuf message= Unpooled.copiedBuffer(msg.getBytes());
		    	 //执行设备控制    根据product.getUrl() 上个类写入map  的key  取到map中的 ChannelHandlerContext  执行writeAndFlush发送数据
				 ServerHandler.map.get(product.getUrl()).channel().writeAndFlush(message);
				 return Result.toClient(1,"成功");
		     }else{
		    	 return  Result.toClient(0,"失败");
		     }
			
		}
}

**OK完成 附上效果图 **
1、 启动
springboot集成netty实现物联网设备数据接收、下发指令(控制)、多开监听端口、区分端口_第1张图片
2、客户端发起连接 并发送数据
springboot集成netty实现物联网设备数据接收、下发指令(控制)、多开监听端口、区分端口_第2张图片

3、服务端接到数据 打印
springboot集成netty实现物联网设备数据接收、下发指令(控制)、多开监听端口、区分端口_第3张图片4、服务器向客户端发送数据 实现设备控制 直接调用最后controller中的请求地址 然后客户端会打印接收到的数据

springboot集成netty实现物联网设备数据接收、下发指令(控制)、多开监听端口、区分端口_第4张图片
*结束、 有疑问请留言 **
**注: 仅为个人开发时遇到的整合问题 仅作参考 **

你可能感兴趣的:(SpringBoot,Netty,java后端,spring,boot,java,后端)