Spring Boot + WebSocket 学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Wyx_wx/article/details/83480263

WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信--允许服务器主动发送信息给客户端,实现客户端之间的交互。

WebSocket 是从 Html5 中演化而出,但是相对于 HTTP的 不支持持久性连接,WebSocket 是一个持久化的协议。

实现 WebSocket 协议后,服务端只要与客户端进行过一次连接之后,就不需要再次连接,并且可以一直向客户端发送信息,即服务端主动向客户端发送消息。

由于 WebSocket 协议在握手阶段采用了 HTTP 协议,能通过各种 HTTP 代理服务器。

目前并不是所有的浏览器都实现了 WebSocket,对于没有实现该协议的浏览器,还需要通过 STOMP 协议来完成兼容。

要想在 Spring Boot 项目中应用 WebSocket,首先要在 pom.xml 中加入依赖

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

     <!-- Spring security 主要为了点对点时的安全登录,可以不使用 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.0.4.RELEASE</version>
    </dependency>

下面开发一个简单的 WebSocket 服务

· 创建 java 配置文件

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

    //创建服务器端点
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

}

· 定义 WebSocket 服务端站点


import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;

//创建 WebSocket 服务站点, 参数: 请求地址
@ServerEndpoint("/ws")
@Service
public class WebSocketServiceImpl {

    //用来记录当前在线连接数,应该设置为线程安全
    private static int onlineCount = 0;
    //保证线程安全的 WebSocketServiceImpl 对象的 Set
    private static CopyOnWriteArrayList<WebSocketServiceImpl> webSocketServices = new CopyOnWriteArrayList<>();
    //与客户端的连接会话
    private Session session;

    public Session getSession() {
        return session;
    }

    /**
     * 连接建立成功调用的方法
     * @param session
     */
    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        webSocketServices.add(this);
        addOnlineCount();
        System.out.println("有新连接加入, 当前在线人数: " + getOnlineCount());
        try {
            sendMessage("有新连接加入了");
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        webSocketServices.remove(this);
        subOnlineCount();
        System.out.println("有一个连接关闭, 当前在线人数: " + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送来的消息
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session){
        System.out.println("收到客户端消息: " + message);
        //群发消息
        for(WebSocketServiceImpl service : webSocketServices){
            try {
                //获取当前用户名称
                String userName = service.getSession().getUserPrincipal().getName();
                System.out.println(userName);
                service.sendMessage(message);
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    /**
     *发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("发生错误");
        error.printStackTrace();
    }

    /**
     * 发送消息
     * @param message 客户端消息
     * @throws IOException
     */
    private void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
    }

    //返回在线数
    private static synchronized int getOnlineCount(){
        return onlineCount;
    }

    //增加连接人数
    private static synchronized void addOnlineCount(){
        WebSocketServiceImpl.onlineCount++;
    }

    //减少连接人数
    private static synchronized void subOnlineCount(){
        WebSocketServiceImpl.onlineCount--;
    }

}

· WebSocket 页面(websocket.jsp)

若是资源路径出问题,报404错误时,请移步此篇文章

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>My WebSocket</title>
	<script type="text/javascript" src="/jquery-1.8.3.min.js"></script>
	<script type="text/javascript" src="/websocket.js"></script>
</head>
<body>

	测试 WebSocket 站点
	<br>
	<input id = "message" type="text">
	<button onclick="sendMessage()">发送消息</button>
	<button onclick="closeWebSocket()">关闭 WebSocket 连接</button>
	<div id="context"></div>

</body>

</html>

· WebSocket 客户端脚本(websocket.js)

var websocket = null;
//判断当前浏览器是否支持 WebSocket
if('WebSocket' in window){
    //创建 WebSocket 对象,连接服务器端点
    websocket = new WebSocket("ws://localhost:8080/ws");
}else{
    alert('Not support webSocket')
}

//连接发生错误的回调方法
websocket.onerror = function () {
    appendMessage("error");
};

//连接成功建立的回调方法
websocket.onopen = function (event) {
    appendMessage("open");
};

//接收到消息的回调方法
websocket.onmessage = function (event) {
    appendMessage(event.data);
};

//连接关闭的回调方法
websocket.onclose = function () {
    appendMessage("close");
};

//监听窗口关闭事件,当窗口关闭时,主动关闭 websocket 连接
//防止连接还没断开就关闭窗口, server 端会抛异常
window.onbeforeunload = function () {
    websocket.close();
};

//将消息显示在网页上
function appendMessage(message) {
    var context = $("#context").html() + "<br/>" + message;
    $("#context").html(context);
};

//关闭连接
function closeWebSocket() {
    websocket.close();
}

//发送消息
function sendMessage() {
    var message = $("#message").val();
    websocket.send(message);
}

· WebSocket 控制器


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping(value = "/websocket")
@RestController
public class WebSocketController {

    @GetMapping(value = "/index")
    public String websocket(){
        return "websocket";
    }

}

启动控制器,跳转去客户端,打开两个页面发送消息

猜你喜欢

转载自blog.csdn.net/Wyx_wx/article/details/83480263