websocket——javaX版本玩法与springboot玩法,广播案例

总结:

1.推荐在线测试:在线websocket测试-在线工具-postjson,或写个简单页面(H5或socket.js)

2.两种玩法没多大区别,似乎Javax版本还更easy,但是springboot版本感觉贴近websocket协议本质

3.websocket协议本质—借助HTTP打开TCP长连接通道的全双工的通信协议,避免前端定时器去获取后端数据

4.两者的session都得自己写个并发容器copyOnArraySet /concurrentHashMap等来存放,发送消息时根据条件如uid去并发容器中找到该session进行后端消息往前端实时推送。

普通玩法

1.依赖

普通玩法可以只导这个包,比较小,也可以导springboot的spring-boot-start-websocket,间接引入的前者

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

2.javaX版本处理器

@ServerEndpoint("/ws/javax/{uid}")
@Component
public class JavaXWebSocket {

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "uid")String uid) throws IOException {
        System.out.println("websocket已经连接" + session);
        session.getBasicRemote().sendText(uid+",你好!欢迎登陆系统");
    }

    @OnClose
    public void onClose(Session session){
        System.out.println("websocket已经关闭" + session);
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        System.out.println("收到客户端发来的消息 --> " + message);
        session.getBasicRemote().sendText("消息已收到");
    }

}

3.还需要配置一个bean-端点导出器,在启动类或专门写个配置类丢进去就好了

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        
        return new ServerEndpointExporter();
    }

springboot玩法

1.依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2..JavaX是path上获取参数,springboot是通过拦截器request对象获取到参数,再将这个参数存入websocketSession对象

@Component
public class MyHandshakeInterceptor implements HandshakeInterceptor {

    /**
     * 握手之前,若返回false,则不建立链接
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse
            response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        //将用户id放入socket处理器的会话(WebSocketSession)中
        attributes.put("uid", ((ServletServerHttpRequest) request).getServletRequest().getParameter("uid"));
        System.out.println("开始握手。。。。。。。");
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse
            response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("握手成功啦。。。。。。");
    }
}

3.springboot版本处理器,需继承TextWebSocketHandler,参数从WebSocketSession获取

@Component
public class MyHandler extends TextWebSocketHandler {


   private static final Map<Long,WebSocketSession> sessions = new HashMap<>();


    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message)
            throws IOException {
        System.out.println("获取到消息 >> " + message.getPayload());
        if(toSession != null && toSession.isOpen()){ //有session且open状态
         session.sendMessage(new TextMessage("消息已收到"));
       }
        

    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws
            Exception {
        String uid = (String)session.getAttributes().get("uid");
        session.sendMessage(new TextMessage(uid+", 你好!欢迎连接到ws服务"));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status)
            throws Exception {
        System.out.println("断开连接!");
    }
}

4.配置类

@Configuration
@EnableWebSocket 
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MyHandler myHandler;

    @Autowired
    private MyHandshakeInterceptor myHandshakeInterceptor;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(this.myHandler, "/ws/springboot")  //相等于@ServerEndPoint
                .setAllowedOrigins("*") //跨域支持
                .addInterceptors(this.myHandshakeInterceptor) //添加拦截器
                .withSockJS();  //支持socket.js
    }
}

# 优化

1.前端STOMP协议才需要开启SOCKJS

2.Handler实现不需要放入spring容器

3.只是粗糙的广播,使用SET来存储session即可,(session有绑定id...),如果需要发给指定User的场景可以使用Map<Long,WebSocketSession>存储,K为userId.

```java

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {



    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyHandler2(), "/ws/springboot2")  //相等于@ServerEndPoint
                .setAllowedOrigins("*"); //跨域支持
                //.withSockJS();  //支持socket.js  前端
    }

}

```

广播案例

```java

package com.example.demo.websocket;

import lombok.SneakyThrows;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.*;

public class MyHandler2 extends TextWebSocketHandler {


   private static final Set<WebSocketSession> sessions =  Collections.synchronizedSet(new HashSet<>());

   @SneakyThrows
    public static void sendAll(WebSocketSession selfSession){
        sessions.stream().parallel().forEach(webSocketSession -> {
            if (!webSocketSession.getId().equals(selfSession.getId())) {
                try {
                    webSocketSession.sendMessage(new TextMessage("XXXX"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }


    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message)
            throws Exception {
        //super.handleTextMessage(session,message);
        sendAll(session);

    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws
            Exception {
        sessions.add(session);
        super.afterConnectionEstablished(session);

    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        super.handleMessage(session, message);
    }

    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        super.handlePongMessage(session, message);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        exception.printStackTrace();
        super.handleTransportError(session, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);
        super.afterConnectionClosed(session, status);
    }
}

```

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是使用Netty实现WebSocket协议的示例代码,配合使用Spring Boot中的WebSocketController: ``` // Netty中WebSocket协议实现示例代码 public class WebSocketServer extends ChannelInboundHandlerAdapter { private WebSocketServerHandshaker handshaker; private static final String WEB_SOCKET_URL = "ws://localhost:8888/websocket"; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { // 处理HTTP请求,完成WebSocket握手 handleHttpRequest(ctx, (FullHttpRequest) msg); } else if (msg instanceof WebSocketFrame) { // 处理WebSocket请求 handleWebSocketFrame(ctx, (WebSocketFrame) msg); } } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { if (!req.decoderResult().isSuccess() || !"websocket".equals(req.headers().get("Upgrade"))) { // 如果不是WebSocket请求,则返回400 Bad Request响应 sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); return; } // 构造握手响应返回,本机测试 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(WEB_SOCKET_URL, null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } } private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame 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)) { throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass().getName())); } // 处理WebSocket消息,这里会调用Spring Boot中的WebSocketController String request = ((TextWebSocketFrame) frame).text(); WebSocketController.handleWebSocketMessage(ctx, request); } private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) { // 返回应答给客户端 if (res.status().code() != 200) { ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8); res.content().writeBytes(buf); buf.release(); HttpUtil.setContentLength(res, res.content().readableBytes()); } // 如果是非Keep-Alive,关闭连接 ChannelFuture f = ctx.channel().writeAndFlush(res); if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } } // Spring Boot中的WebSocketController示例代码 @Controller public class WebSocketController { @OnOpen public void onOpen(Session session) { // 连接建立时触发 } @OnClose public void onClose(Session session) { // 连接关闭时触发 } @OnMessage public void onMessage(String message, Session session) { // 接收到客户端消息时触发 } public static void handleWebSocketMessage(ChannelHandlerContext ctx, String message) { // 处理WebSocket消息 // 将WebSocket消息发送到Spring Boot中的WebSocketController中处理 // 这里使用Spring BootWebSocketTemplate发送消息 WebSocketSessionManager.getInstance().getSession().sendMessage(new TextMessage(message)); } } ``` 以上是一个简单的使用Netty实现WebSocket协议,配合使用Spring Boot中的WebSocketController的示例代码,具体实现方法可能会因需求不同有所变化。其中,`WebSocketController`类可以根据具体的需求进行修改,例如添加消息广播等功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值