Administrator
2022-06-16 2ebca060a47784db76369a4aa84f63293da9be33
src/main/java/org/springblade/modules/webscoket/WebSocketHandler.java
@@ -1,193 +1,193 @@
package org.springblade.modules.webscoket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.AttributeKey;
import io.netty.util.CharsetUtil;
import org.springblade.modules.nettyServer.NettyConfig;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class WebSocketHandler extends SimpleChannelInboundHandler<Object> {
   private WebSocketServerHandshaker handshaker;
   private  String on=null;
   @Autowired
   private IUserService userService;
   private static WebSocketHandler webSocketHandler;
   @PostConstruct
   public void init() {
      webSocketHandler = this;
   }
   @Override
   protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
      if (msg instanceof FullHttpRequest) {
         //以http请求形式接入,但是走的是websocket
         handleHttpRequest(ctx, (FullHttpRequest) msg);
      } else if (msg instanceof WebSocketFrame) {
         //处理websocket客户端的消息
         handlerWebSocketFrame(ctx, (WebSocketFrame) msg);
      }
   }
   /**
    * 客户端加入连接
    * @param ctx
    * @throws Exception
    */
   @Override
   public void channelActive(ChannelHandlerContext ctx) throws Exception {
      //添加连接
      System.out.println("客户端加入连接:" + ctx.channel());
      //ChannelSupervise.addChannel(ctx.channel());
   }
   /**
    * 客户端离开连接
    * @param ctx
    * @throws Exception
    */
   @Override
   public void channelInactive(ChannelHandlerContext ctx) throws Exception {
      //断开连接
      System.out.println("客户端断开连接:" + ctx.channel());
      //用户离线状态
      String name = ChannelSupervise.findName(ctx.channel().id().asShortText());
      if ( name != null &&!name.equals("ping") ){
         String num="0";
         //工作状态(0闲置,1工作中)
         String workSt = "0";
//         webSocketHandler.userService.updateUser(num,name,workSt);
         //ChannelSupervise.removeChannel(ctx.channel());
         NettyConfig.getChannelGroup().remove(ctx.channel());
         removeUserId(ctx);
      }
   }
   @Override
   public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
      ctx.flush();
   }
   private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws NumberFormatException, Exception {
      System.out.println("ctx = " + ctx);
      System.out.println("frame = " + frame);
      // 判断是否关闭链路的指令
      if (frame instanceof CloseWebSocketFrame) {
         handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
         return;
      }
      // 判断是否ping消息
      if (frame instanceof PingWebSocketFrame) {
         ctx.channel().write(
            new PongWebSocketFrame(frame.content().retain()));
         return;
      }
      // 本例程仅支持文本消息,不支持二进制消息
      if (!(frame instanceof TextWebSocketFrame)) {
         System.out.println("本例程仅支持文本消息,不支持二进制消息");
         throw new UnsupportedOperationException(String.format(
            "%s frame types not supported", frame.getClass().getName()));
      }
      // 返回应答消息
      String request = ((TextWebSocketFrame) frame).text();
      if (!request.equals("ping")){
         NettyConfig.getUserChannelMap().put(request,ctx.channel());
         //将用户id作为自定义属性加入到channel 中,方便随时channel中获取用户id
         AttributeKey<String> key = AttributeKey.valueOf("userId");
         ctx.channel().attr(key).setIfAbsent(request);
         //把用户信息添加到通道里
         ChannelSupervise.addChannel(ctx.channel(),request);
         //用户在线状态
         this.on=request;
         //在线状态(0掉线,1在线)
         String num="1";
         //工作状态(0闲置,1工作中)
         String workSt = "0";
//         webSocketHandler.userService.updateUser(num,request,workSt);
      }
   }
   /**
    * 唯一的一次http请求,用于创建websocket
    *
    * @throws InterruptedException
    */
   private void handleHttpRequest(final ChannelHandlerContext ctx,
                           FullHttpRequest req) throws InterruptedException {
      //要求Upgrade为websocket,过滤掉get/Post
      if (!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {
         //若不是websocket方式,则创建BAD_REQUEST的req,返回给客户端
         sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
         return;
      }
      //握手
      WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
         "ws://localhost:9034/websocket", null, false);
      handshaker = wsFactory.newHandshaker(req);
      if (handshaker == null) {
         WebSocketServerHandshakerFactory
            .sendUnsupportedVersionResponse(ctx.channel());
      } else {
         handshaker.handshake(ctx.channel(), req);
      }
   }
   /**
    * 拒绝不合法的请求,并返回错误信息
    */
   private static void sendHttpResponse(ChannelHandlerContext ctx,
                                         FullHttpRequest req, DefaultFullHttpResponse res) {
      // 返回应答给客户端
      if (res.status().code() != 200) {
         ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(),
            CharsetUtil.UTF_8);
         res.content().writeBytes(buf);
         buf.release();
      }
      ChannelFuture f = ctx.channel().writeAndFlush(res);
      // 如果是非Keep-Alive,关闭连接
//      if (!isKeepAlive(req) || res.status().code() != 200) {
//         f.addListener(ChannelFutureListener.CLOSE);
//package org.springblade.modules.webscoket;
//
//import io.netty.buffer.ByteBuf;
//import io.netty.buffer.Unpooled;
//import io.netty.channel.ChannelFuture;
//import io.netty.channel.ChannelHandlerContext;
//import io.netty.channel.SimpleChannelInboundHandler;
//import io.netty.handler.codec.http.DefaultFullHttpResponse;
//import io.netty.handler.codec.http.FullHttpRequest;
//import io.netty.handler.codec.http.HttpResponseStatus;
//import io.netty.handler.codec.http.HttpVersion;
//import io.netty.handler.codec.http.websocketx.*;
//import io.netty.util.AttributeKey;
//import io.netty.util.CharsetUtil;
//import org.springblade.modules.nettyServer.NettyConfig;
//import org.springblade.modules.system.service.IUserService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//
//import javax.annotation.PostConstruct;
//
//@Component
//public class WebSocketHandler extends SimpleChannelInboundHandler<Object> {
//
//   private WebSocketServerHandshaker handshaker;
//
//   private  String on=null;
//
//   @Autowired
//   private IUserService userService;
//
//   private static WebSocketHandler webSocketHandler;
//
//   @PostConstruct
//   public void init() {
//      webSocketHandler = this;
//   }
//
//   @Override
//   protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
//      if (msg instanceof FullHttpRequest) {
//         //以http请求形式接入,但是走的是websocket
//         handleHttpRequest(ctx, (FullHttpRequest) msg);
//      } else if (msg instanceof WebSocketFrame) {
//         //处理websocket客户端的消息
//         handlerWebSocketFrame(ctx, (WebSocketFrame) msg);
//      }
   }
   @Override
   public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
      cause.printStackTrace();
      ctx.close();
   }
   /**
    * 删除用户与channel 对应关系
    * @param ctx
    */
   private void removeUserId(ChannelHandlerContext ctx){
      AttributeKey<String> key = AttributeKey.valueOf("userId");
      String userId = ctx.channel().attr(key).get();
      NettyConfig.getUserChannelMap().remove(userId);
   }
}
//   }
//
//   /**
//    * 客户端加入连接
//    * @param ctx
//    * @throws Exception
//    */
//   @Override
//   public void channelActive(ChannelHandlerContext ctx) throws Exception {
//      //添加连接
//      System.out.println("客户端加入连接:" + ctx.channel());
//      //ChannelSupervise.addChannel(ctx.channel());
//   }
//
//   /**
//    * 客户端离开连接
//    * @param ctx
//    * @throws Exception
//    */
//   @Override
//   public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//      //断开连接
//      System.out.println("客户端断开连接:" + ctx.channel());
//      //用户离线状态
//      String name = ChannelSupervise.findName(ctx.channel().id().asShortText());
//      if ( name != null &&!name.equals("ping") ){
//         String num="0";
//         //工作状态(0闲置,1工作中)
//         String workSt = "0";
////         webSocketHandler.userService.updateUser(num,name,workSt);
//         //ChannelSupervise.removeChannel(ctx.channel());
//
//         NettyConfig.getChannelGroup().remove(ctx.channel());
//         removeUserId(ctx);
//      }
//   }
//
//   @Override
//   public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//      ctx.flush();
//   }
//
//   private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws NumberFormatException, Exception {
//      System.out.println("ctx = " + ctx);
//      System.out.println("frame = " + frame);
//      // 判断是否关闭链路的指令
//      if (frame instanceof CloseWebSocketFrame) {
//         handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
//         return;
//      }
//      // 判断是否ping消息
//      if (frame instanceof PingWebSocketFrame) {
//         ctx.channel().write(
//            new PongWebSocketFrame(frame.content().retain()));
//         return;
//      }
//      // 本例程仅支持文本消息,不支持二进制消息
//      if (!(frame instanceof TextWebSocketFrame)) {
//         System.out.println("本例程仅支持文本消息,不支持二进制消息");
//         throw new UnsupportedOperationException(String.format(
//            "%s frame types not supported", frame.getClass().getName()));
//      }
//      // 返回应答消息
//      String request = ((TextWebSocketFrame) frame).text();
//
//      if (!request.equals("ping")){
//
//         NettyConfig.getUserChannelMap().put(request,ctx.channel());
//
//         //将用户id作为自定义属性加入到channel 中,方便随时channel中获取用户id
//         AttributeKey<String> key = AttributeKey.valueOf("userId");
//         ctx.channel().attr(key).setIfAbsent(request);
//
//         //把用户信息添加到通道里
//         ChannelSupervise.addChannel(ctx.channel(),request);
//         //用户在线状态
//         this.on=request;
//         //在线状态(0掉线,1在线)
//         String num="1";
//         //工作状态(0闲置,1工作中)
//         String workSt = "0";
////         webSocketHandler.userService.updateUser(num,request,workSt);
//      }
//
//   }
//
//   /**
//    * 唯一的一次http请求,用于创建websocket
//    *
//    * @throws InterruptedException
//    */
//   private void handleHttpRequest(final ChannelHandlerContext ctx,
//                           FullHttpRequest req) throws InterruptedException {
//      //要求Upgrade为websocket,过滤掉get/Post
//      if (!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {
//         //若不是websocket方式,则创建BAD_REQUEST的req,返回给客户端
//         sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
//         return;
//      }
//      //握手
//      WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
//         "ws://localhost:9034/websocket", null, false);
//      handshaker = wsFactory.newHandshaker(req);
//      if (handshaker == null) {
//         WebSocketServerHandshakerFactory
//            .sendUnsupportedVersionResponse(ctx.channel());
//      } else {
//         handshaker.handshake(ctx.channel(), req);
//      }
//   }
//
//   /**
//    * 拒绝不合法的请求,并返回错误信息
//    */
//   private static void sendHttpResponse(ChannelHandlerContext ctx,
//                                         FullHttpRequest req, DefaultFullHttpResponse res) {
//      // 返回应答给客户端
//      if (res.status().code() != 200) {
//         ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(),
//            CharsetUtil.UTF_8);
//         res.content().writeBytes(buf);
//         buf.release();
//      }
//      ChannelFuture f = ctx.channel().writeAndFlush(res);
//      // 如果是非Keep-Alive,关闭连接
////      if (!isKeepAlive(req) || res.status().code() != 200) {
////         f.addListener(ChannelFutureListener.CLOSE);
////      }
//   }
//   @Override
//   public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//      cause.printStackTrace();
//      ctx.close();
//   }
//
//   /**
//    * 删除用户与channel 对应关系
//    * @param ctx
//    */
//   private void removeUserId(ChannelHandlerContext ctx){
//      AttributeKey<String> key = AttributeKey.valueOf("userId");
//      String userId = ctx.channel().attr(key).get();
//      NettyConfig.getUserChannelMap().remove(userId);
//   }
//
//}