前言

早期,很多网站为了实现推送技术,所用的技术都是轮询。轮询是指由浏览器每隔一段时间(如每秒)向服务器发出HTTP请求,然后服务器返回最新的数据给客户端。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求与回复可能会包含较长的头部,其中真正有效的数据可能只是很小的一部分,所以这样会消耗很多带宽资源。比较新的轮询技术是Comet。这种技术虽然可以实现双向通信,但仍然需要反复发出请求。而且在Comet中普遍采用的HTTP长连接也会消耗服务器资源。在这种情况下,HTML5定义了WebSocket协议,在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输,这样能更好的节省服务器资源和带宽,并且能够更实时地进行通讯(以上内容来自维基百科)。

Websocket使用wswss统一资源标志符(URI)。其中wss表示使用了TLSWebsocket。如:

ws://example.com/wsapi
wss://secure.example.com/wsapi

下面就通过一个简单的例子介绍如何在SpringBoot中集成WebSocket,只展示WebSocket的核心配置,完整代码已上传到GitHub由于下篇博客对本文的代码有改造,在测试的时候需要输入 https://localhost 而不是 http://localhost:8080,同时本地需要先创建一个 blog 数据库和 user 表并添加测试数据):

效果展示

在展示代码配置前,先展示一下效果(已提前登录了三个用户):

spring长轮询 springboot轮询_spring长轮询

具体的代码配置

  1. 引入依赖
    首先需要在pom.xml中引入以下依赖:
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  1. 配置ServerEndpointExporterBean
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
  1. 配置服务器终端
@Component
@ServerEndpoint("/websocket")
public class WebSocketServer {

    private Session session;
    // 保存所有的客户端连接
    private static final Map<String, WebSocketServer> connections = new LinkedHashMap<>();

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        connections.put(session.getId(), this);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            sendMessage(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnError
    public void onError(Throwable error, Session session) throws Throwable {
        throw error;
    }

    @OnClose
    public void onClose() {
        connections.remove(session.getId());
    }

    public void sendMessage(String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }

    // 广播方法(实现消息群发)
    public static void broadcast(String message) {
        connections.forEach((k, v) -> {
            try {
                v.sendMessage(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}
  1. 配置群发通知接口
@RestController
public class BroadcastController {

    @PostMapping("/broadcast")
    public void broadcast(@RequestBody String msg){
        WebSocketServer.broadcast(msg);
    }
}
  1. 客户端配置
    客户端简单使用Vue框架,没有使用单文件组件形式,客户端连接代码如下:
let socket = new WebSocket("ws://localhost:8080/websocket")
socket.onerror = err => {
    console.log(err)
}

socket.onopen = event => {
    console.log(event)
}

socket.onmessage = event => {
    // 这里接受服务端发送的信息
    vue.$data.toast = {
        isShow: true,
        msg: JSON.parse(event.data).msg
    }
}

socket.onclose = () => {
    console.log("连接关闭")
}

完成以上简单配置后,只要调用了群发信息的接口,客户端就可以通过onmessage函数来处理接收到的信息。

  1. 浏览器控制台测试
    如果想要尽快测试结果,不想写前端代码,可以直接在控制台中输入以下代码(对5中的代码稍作修改):

spring长轮询 springboot轮询_websocket_02

然后在新建一个页面并地址栏中输入http://localhost:8080/broadcast?msg=1234567并回车(记得将4中的PostMapping改为GetMapping,并删掉@RequestBody),输完回车后,在返回上一个界面查看控制台,即可发现接收信息:

spring长轮询 springboot轮询_websocket_03

总结

本文简单介绍了如何通过SpringBoot集成WebSocket实现群发信息的功能,本文只讲解了WebSocket的基本使用,也只使用了ws,在下篇文章将会介绍如何使用加密的wss协议。