引入依赖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、 启动
2、客户端发起连接 并发送数据
3、服务端接到数据 打印
4、服务器向客户端发送数据 实现设备控制 直接调用最后controller中的请求地址 然后客户端会打印接收到的数据