spring使用websocket 的两种方式

方式一 (使用stomp协议)

使用spring-websocket:
springboot websocket 默认是stomp协议, js连接需要使用sockJs。
本示例仅包括订阅发布模式:

后端

引入依赖:

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

配置websocket:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket").withSockJS();
    }

}

定时发布消息:

	@Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    @Scheduled(fixedDelay = 1000L)
    public void send() {
        Greeting greeting = new Greeting("Hello, ");
        simpMessagingTemplate.convertAndSend("/topic/greetings", greeting);
    }

前端

function connect() {
    // var socket = new SockJS('/gs-guide-websocket');
    var socket = new SockJS('http://localhost:8080/websocket1');
    stompClient = Stomp.over(socket);

    stompClient.connect({}, function (frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        // 订阅/topic/greetings的消息
        stompClient.subscribe('/topic/greetings', function (greeting) {
            showGreeting(JSON.parse(greeting.body).content);
        });
    });
}

该示例也是springwebsocket官方文档推荐的写法。

方式二 (使用websocket协议)

使用传统websocket方式:

后端

引入依赖:

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

配置websocket

@ServerEndpoint("/websocket")
@Component
public class WebSocketServer {

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

    private Session session;

    /*    <sessionId, WebSocketServer> 用于存储websocket连接,key为sessionId  */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketServerConcurrentHashMap = new ConcurrentHashMap();

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketServerConcurrentHashMap.put(session.getId(), this);
        System.out.println("WebSocket opened: " + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("WebSocket message received: " + message);
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
        try {
            //发送的消息也返回给当前连接,用于展示
            session.getBasicRemote().sendText(dateStr + "发送消息:" + message);

            //写入DB或者其他存储系统中。。。

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        webSocketServerConcurrentHashMap.remove(session.getId());
        System.out.println("WebSocket closed: " + closeReason);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        System.out.println("WebSocket error: " + throwable);
    }

    /**
     * 模拟服务端消息推送,5s推送一次(服务端 -> 客户端)
     */
    @Scheduled(fixedRate = 5000)
    public void sendMessageToClient() {
        //没有连接时不做任何事情
        if (CollectionUtils.isEmpty(webSocketServerConcurrentHashMap)){
            return;
        }

        System.out.println("服务端发送消息到客户端");
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
        long number = new Random().nextInt(10000);
        webSocketServerConcurrentHashMap.forEach((k, v) -> {
            try {
                v.session.getBasicRemote().sendText(dateStr + "收到消息:" + number);

                //写入DB或者其他存储系统中。。。

            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
}

前端

前端需要用原生websocket方式连接, 使用sockJs无法通信。

//建立websocket连接
        function connect() {
            var endpoint = "ws://localhost:8080/websocket";
            socket = new WebSocket(endpoint);

            socket.onopen = function (event) {
                console.log("WebSocket opened: " + endpoint);
            }

            socket.onmessage = function (event) {
                console.log("WebSocket message received: " + event.data);
                addMessageToList(event.data);
            }

            socket.onclose = function (event) {
                console.log("WebSocket closed");
            }
        }

Stomp 与 webSocket区别

stomp

STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。

它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互,类似于OpenWire(一种二进制协议)。
由于其设计简单,很容易开发客户端,因此在多种语言和多种平台上得到广泛应用。其中最流行的STOMP消息代理是Apache ActiveMQ

websocket

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

总结:

直接使用WebSocket就很类似于使用TCP套接字来编写Web应用。因为没有高层级的线路协议,因此就需要我们定义应用之间所发送消息的语义,还需要确保连接的两端都能遵循这些语义。

就像HTTP在TCP套接字之上添加了请求-响应模型层一样,STOMP在WebSocket之上提供了一个基于帧的线路格式(frame-based wire format)层,用来定义消息的语义。与HTTP请求和响应类似,STOMP帧由命令、一个或多个头信息以及负载所组成。

因此对于stomp协议,前端需要使用stompClient 的方式进行通信。
对于websocket协议,前端使用websocket 的方式通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一点博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值