Integrating WebSocket in Spring Cloud (Ruoyi Microservice Edition) for Front‑End/Back‑End Message Push
This guide walks through adding the WebSocket starter to a Spring Boot service, configuring a WebSocketConfig class, implementing client and service components, adjusting Nacos gateway rules, testing with a WebSocket client tool, and exposing a REST endpoint to push messages to Vue front‑ends.
Scenario
The article demonstrates how to integrate WebSocket into a SpringBoot+Vue project that runs under Spring Cloud (Ruoyi microservice edition) to achieve real‑time message push between front‑end and back‑end.
Adding the dependency
<!-- WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>The dependency is placed in the service that requires WebSocket support (e.g., the scheduled‑task service).
WebSocket configuration
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();
}
}A config package is created under the project source tree to hold this class.
Client holder class
import javax.websocket.Session;
public class WebSocketClient {
// session used to send data to the client
private Session session;
// connection URI
private String uri;
public Session getSession(){ return session; }
public void setSession(Session session){ this.session = session; }
public String getUri(){ return uri; }
public void setUri(String uri){ this.uri = uri; }
}WebSocket service implementation
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint(value = "/websocket/{userName}")
@Component
public class WebSocketService {
private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);
private static int onlineCount = 0;
private static ConcurrentHashMap<String, WebSocketClient> webSocketMap = new ConcurrentHashMap<>();
private Session session;
private String userName = "";
@OnOpen
public void onOpen(Session session, @PathParam("userName") String userName) {
if(!webSocketMap.containsKey(userName)) { addOnlineCount(); }
this.session = session;
this.userName = userName;
WebSocketClient client = new WebSocketClient();
client.setSession(session);
client.setUri(session.getRequestURI().toString());
webSocketMap.put(userName, client);
log.info("User connected:" + userName + ", online count:" + getOnlineCount());
try { sendMessage("来自后台的反馈:连接成功"); }
catch (IOException e) { log.error("User:" + userName + ", network error"); }
}
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userName)) {
webSocketMap.remove(userName);
if(webSocketMap.size() > 0) { subOnlineCount(); }
}
log.info(userName + " exited, online count:" + getOnlineCount());
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("Received from " + userName + ":" + message);
// optional: broadcast, persist to DB/Redis, etc.
}
@OnError
public void onError(Session session, Throwable error) {
log.error("User error:" + userName + ", reason:" + error.getMessage());
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
synchronized (session) { session.getBasicRemote().sendText(message); }
}
public static void sendMessage(String userName, String message) {
try {
WebSocketClient client = webSocketMap.get(userName);
if(client != null) { client.getSession().getBasicRemote().sendText(message); }
} catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); }
}
public static synchronized int getOnlineCount() { return onlineCount; }
public static synchronized void addOnlineCount() { onlineCount++; }
public static synchronized void subOnlineCount() { onlineCount--; }
}The service tracks online connections with a thread‑safe ConcurrentHashMap and provides methods to push messages to a specific user or broadcast.
Gateway configuration
The Nacos configuration file ruoyi-gateway-dev.xml is edited to whitelist the WebSocket path, e.g.: - /schedule/websocket/** Images in the original article illustrate the modified XML and the placement of the WebSocket service under the scheduled‑task module.
Testing the connection
A WebSocket client tool (download link provided in the article) is used to connect directly to the service without passing through the gateway, using the address: ws://localhost:9203/websocket/badao After clicking “Connect”, the console shows a successful connection, and sending a message displays it on both client and server sides.
REST endpoint for pushing messages
@RestController
@RequestMapping("/schedule/websocket")
public class WebSocketTestController {
@GetMapping("/push")
public void push(SysJobLog sysJobLog) {
WebSocketService.sendMessage("badao", "badao");
}
}Invoking /schedule/websocket/push triggers the service to push a message to the connected client, which is confirmed by the client UI.
Overall, the article provides a complete, reproducible workflow for enabling real‑time WebSocket communication in a Spring Cloud microservice environment, from Maven setup to gateway configuration, server‑side implementation, and client‑side testing.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
The Dominant Programmer
Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
