Simple message broadcast and unicast of Websocket using Spring

Recently, I am doing my graduation project. I need to use Websocket to push messages.

Looking at the documents on the Spring official website, I found that Spring has extended the functions of Websocket too much, and introduced the concepts of STOMP and Broker( https://spring.io/guides/gs/messaging-stomp-websocket/ ).

But my project doesn't use such advanced functions at all. All I need is a simple websocket connection. Finally, the corresponding configuration method is found in the document( https://docs.spring.io/spring/docs/5.2.5.RELEASE/spring-framework-reference/web.html#websocket).

Of course, we also need to modify the corresponding code according to the needs of our own project.

  1. Create configuration class

Before Websocket establishes the connection, it will shake hands through HTTP protocol.

If you want to deny an unauthenticated user a Websocket connection to the server, you can create a new interceptor and authenticate the user in the beforeHandshake method

Add the HttpSessionHandshakeInterceptor interceptor provided by Spring to copy the properties of HttpSession to the WebsocketSession. We can use this method to identify users.

First, create a WebSocketConfig.class file as the configuration class of Websocket. The content of the file is as follows.

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    MyHandler myHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry
                .addHandler(myHandler, "/myHandler") // Specify websocket path / myHandler to process
                 //. addInterceptors() add your own interceptors
                 //.addInterceptors(new HttpSessionHandshakeInterceptor())
                .setAllowedOrigins("*"); // Set the allowed connection source, and make adjustment when it is officially Online
    }
}
  1. Processing message

Create the MyHandler.class file to process the Websocket request, because we only need to process the text content at present, so we inherit the TextWebSocketHandler.

If you want to process binary content, you can override the handleBinaryMessage method or inherit the parent class AbstractWebSocketHandler of TextWebSocketHandler


@Component
public class MyHandler extends TextWebSocketHandler {

    @Autowired
    WebSocketService service;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // After the connection is established
        super.afterConnectionEstablished(session);
        service.addWebSocketSession(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
         // After connection is closed
        super.afterConnectionClosed(session, status);
        service.removeWebSocketSession(session);
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
	// Process messages sent from the other end
        logger.debug("id: " +session.getId());
        logger.debug("attributes: " + session.getAttributes());
        logger.debug("message: " + message.getPayload());
	service.handleTextMessage(session, message)
    }

}

Create WebsocketService class for business processing


@Service
public class WebSocketService {
    // Use synchronized or ConcurrentHashMap to ensure multithreading safety, because we also need to implement broadcasting, so here I use synchronized to achieve thread safety
    Map<String,WebSocketSession> sessionMap = new HashMap<>(); 

    public synchronized void addWebSocketSession(WebSocketSession session) {
        String id = "";// Unique ID obtained from session
        // In session, you can also obtain various properties of http before handshake, such as URL, request header, which can also be used as a unique identifier
        sessionMap.put(id, session); //Save session
    }

    public synchronized void removeWebSocketSession(WebSocketSession session) {
        String id = "";
        sessionMap.remove(id); // Delete session
    }
    public synchronized void broadcast(String message) {
        for(WebSocketSession session: sessionMap.values()) {
            TextMessage tm = new TextMessage("" /*The data you want to broadcast*/);
            try {
                session.sendMessage(tm);
            } catch (IOException e) {
                // After sending fails, you need to continue broadcasting to other people, so try to catch exceptions in the loop
            }
        }
    }
    public synchronized void unicast(String id, String message) {
        WebSocketSession session = sessionMap.get(id);
        TextMessage tm = new TextMessage("" /*Data you want to send*/);
        try {
            session.sendMessage(tm);
        } catch (IOException e) {
        }
    }

    public synchronized void handleTextMessage(WebSocketSession session, TextMessage message) {
        // Process messages sent from the other end
    }
}

Tags: Programming Session Spring

Posted on Wed, 25 Mar 2020 10:09:00 -0400 by gman-03