Integrating WebSocket in Spring Boot: A Complete Step‑by‑Step Guide with Code Samples

This article explains how to use Spring Boot to add WebSocket support, covering the protocol basics, Maven dependencies, configuration classes, a test controller, a simple HTML client page, and troubleshooting tips, all illustrated with complete Java and JavaScript code examples.

Top Architect
Top Architect
Top Architect
Integrating WebSocket in Spring Boot: A Complete Step‑by‑Step Guide with Code Samples

Introduction

During a recent project we needed to push messages from a Netty‑based backend to the frontend, so we chose WebSocket for its full‑duplex capabilities. This guide records the entire integration process using Spring Boot.

What is WebSocket?

WebSocket is a TCP‑based protocol that enables bidirectional communication between client and server, allowing the server to actively push data to the client—ideal for real‑time notifications and chat applications.

Step 1: Add Maven Dependency

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

Step 2: Enable WebSocket Support in Spring Boot

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

/**
 * @Auther: Ma Chaowei
 * @Date: 2020/06/16
 * @Description: Enable WebSocket support
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

Step 3: Core WebSocket Server Configuration

The WebSocketServer class is annotated with @ServerEndpoint to turn it into a WebSocket endpoint. It maintains a thread‑safe CopyOnWriteArraySet of active sessions, tracks online count, and provides methods for connection lifecycle events, message handling, and server‑initiated pushes.

package cc.mrbird.febs.external.webScoket;

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

@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {
    private static int onlineCount = 0;
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
    private Session session;
    private String sid = "";

    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);
        this.sid = sid;
        addOnlineCount();
        try { sendMessage("conn_success"); } catch (IOException e) { e.printStackTrace(); }
    }

    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        subOnlineCount();
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        for (WebSocketServer item : webSocketSet) {
            try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); }
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

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

    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        for (WebSocketServer item : webSocketSet) {
            if (sid == null || item.sid.equals(sid)) {
                item.sendMessage(message);
            }
        }
    }

    // synchronized counters omitted for brevity
}

Step 4: Test Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Controller("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {
    @GetMapping("/index/{userId}")
    public ModelAndView socket(@PathVariable String userId) {
        ModelAndView mav = new ModelAndView("/socket1");
        mav.addObject("userId", userId);
        return mav;
    }

    @ResponseBody
    @RequestMapping("/socket/push/{cid}")
    public Map<String, Object> pushToWeb(@PathVariable String cid, String message) {
        Map<String, Object> result = new HashMap<>();
        try {
            WebSocketServer.sendInfo(message, cid);
            result.put("code", cid);
            result.put("msg", message);
        } catch (IOException e) { e.printStackTrace(); }
        return result;
    }
}

Step 5: Simple HTML Client (index.html)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Java Backend WebSocket Demo</title>
    <script src="js/jquery.min.js"></script>
</head>
<body>
    <div id="main" style="width:1200px;height:800px;"></div>
    <input id="text" type="text"/>
    <button onclick="send()">Send Message</button>
    <hr/>
    <button onclick="closeWebSocket()">Close WebSocket</button>
    <hr/>
    <div id="message"></div>
<script type="text/javascript">
    var websocket = null;
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://192.168.100.196:8082/api/websocket/100");
    } else {
        alert('Browser does not support WebSocket');
    }
    websocket.onerror = function() { setMessageInnerHTML('WebSocket error'); };
    websocket.onopen = function() { setMessageInnerHTML('WebSocket opened'); };
    websocket.onmessage = function(event) { console.log(event); setMessageInnerHTML(event.data); };
    websocket.onclose = function() { setMessageInnerHTML('WebSocket closed'); };
    window.onbeforeunload = function() { closeWebSocket(); };
    function setMessageInnerHTML(msg) { document.getElementById('message').innerHTML += msg + '<br/>'; }
    function closeWebSocket() { websocket.close(); }
    function send() {
        var message = document.getElementById('text').value;
        websocket.send('{"msg":"' + message + '"}');
        setMessageInnerHTML(message + '&#13;');
    }
</script>
</body>
</html>

Result Display

The backend console shows connection logs when a client connects, and the frontend page displays received messages in real time.

Conclusion

When the WebSocket server starts before the Spring container, injecting Spring services directly can cause NullPointerException. The fix is to obtain required beans statically or configure the server to start after the Spring context.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentmavenSpring BootWebSocketreal-time communication
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.