10
之前做的需求都是客户端请求服务器响应,新需求是服务器主动推送信息到客户端.百度之后有流、长轮询、websoket等方式进行.但是目前更加推崇且合理的显然是websocket.

从springboot官网翻译了一些资料,再加上百度简单实现了springboot使用websocekt与客户端的双工通信.

1.首先搭建一个简单的springboot环境

<!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>

    <!-- Add typical dependencies for a web application -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

2.引入springboot整合websocket依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>

3.创建启动springboot的核心类

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GlobalConfig {
    public static void main(String[] args) {
        SpringApplication.run(GlobalConfig.class, args);
    }
}

4.创建websocket服务器

正如springboot 官网推荐的websocket案例,需要实现WebSocketHandler或者继承TextWebSocketHandler/BinaryWebSocketHandler当中的任意一个.

package com.xiaoer.handler;

import com.alibaba.fastjson.JSONObject;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.HashMap;
import java.util.Map;

/**
 * 相当于controller的处理器
 */
public class MyHandler extends TextWebSocketHandler {
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        Map<String, String> map = JSONObject.parseObject(payload, HashMap.class);
        System.out.println("=====接受到的数据"+map);
        session.sendMessage(new TextMessage("服务器返回收到的信息," + payload));
    }
}

5.注册处理器

package com.xiaoer.config;

import com.xiaoer.handler.MyHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "myHandler/{ID}");
    }
    public WebSocketHandler myHandler() {
        return new MyHandler();
    }

}

6.运行访问

clipboard.png
出现如上图是因为不能直接通过http协议访问,需要通过html5的ws://协议进行访问.

7.创建Html5 客户端

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input id="text" type="text" />
        <button onclick="send()">Send</button>    
        <button onclick="closeWebSocket()">Close</button>
        <div id="message">
        </div>
        <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
        <script>
            
            var userID="888";
            var websocket=null;

            $(function(){
                connectWebSocket();
            })
            
            //建立WebSocket连接
            function connectWebSocket(){

                console.log("开始...");
              
              //建立webSocket连接
               websocket = new WebSocket("ws://127.0.0.1:8080/myHandler/ID="+userID);
              
              //打开webSokcet连接时,回调该函数
               websocket.onopen = function () {      
                    console.log("onpen");  
               }
               
               //关闭webSocket连接时,回调该函数
               websocket.onclose = function () {
               //关闭连接    
                    console.log("onclose");
               }

               //接收信息
               websocket.onmessage = function (msg) {
                    console.log(msg.data);
               }

            }
            //发送消息
            function send(){
                var postValue={};
                postValue.id=userID;
                postValue.message=$("#text").val();          
                websocket.send(JSON.stringify(postValue));
            }
            //关闭连接
            function closeWebSocket(){
                if(websocket != null) {
                    websocket.close();
                }
            }
        </script>
    </body>
</html>

8.运行

clipboard.png
利用客户端运行之后仍然会出现上图中的一连接就中断了websocket连接.
这是因为spring默认不接受跨域访问:

As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept only same origin requests.

需要在WebSocketConfig中设置setAllowedOrigins.

package com.xiaoer.config;

import com.xiaoer.handler.MyHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "myHandler/{ID}")
            .setAllowedOrigins("*");
    }
    public WebSocketHandler myHandler() {
        return new MyHandler();
    }

}

如下图,并未输出中断,说明连接成功.
clipboard.png

9.服务器和客户端的相互通信

服务器端收到消息
clipboard.png
客户端收到服务器主动推送消息
clipboard.png

以上就是一个最基础的springboot简单应用.还可以通过拦截器、重写WebSocketConfigurer中的方法进行更为复杂的属性操作.具体可以参考SpringBoot集成WebSocket【基于纯H5】进行点对点[一对一]和广播[一对多]实时推送


王强劲
104 声望0 粉丝