原創 叫我長安吧 最后發布於2019-08-12 14:26:13 閱讀數 2349 收藏
展開
引入依賴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(9898).sync();//開啟需要監聽 的端口
ChannelFuture future1 = b.bind(9899).sync();//開啟需要監聽 的端口 多開端口
if (future.isSuccess()) {
System.out.println("啟動 9898 成功");
}
if (future1.isSuccess()) {
System.out.println("啟動 9899 成功");
}
}
/**
* 銷毀
*/
@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)
if(map.get(url)!=null){//如果不為空就不存
}else{//否則就將當前的設備ip+端口存進map 當做下發設備的標識的key
map.put(url, ctx);
}
int users=0;
//設備請求的 服務器端的地址 用作監聽設備請求的那個端口
String servicePort=ctx.channel().localAddress().toString();
//判斷端口如果客戶端請求的端口號為9898 就是寫入第一張表 這樣可以實現 設備傳遞數據參數不一致
System.out.println("向:"+servicePort.substring(servicePort.length()-4, servicePort.length())+" 端口寫入數據");
if(servicePort.substring(servicePort.length()-4, servicePort.length()).equals("9898")){
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地址 +9898(個人開的9898端口 )就可以發送數據了
**控制設備 **
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;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@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地址 實現下發
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、 啟動
在這里插入圖片描述

2、客戶端發起連接 並發送數據
在這里插入圖片描述
3、服務端接到數據 打印
在這里插入圖片描述

4、服務器向客戶端發送數據 實現設備控制 直接調用最后controller中的請求地址 然后客戶端會打印接收到的數據
在這里插入圖片描述

**結束、 有疑問請留言 **
**注: 僅為個人開發時遇到的整合問題 僅作參考 **
————————————————
版權聲明:本文為CSDN博主「叫我長安吧」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_42754347/article/details/99297982
