Search code examples
springspring-bootspring-websocket

access websocket from a desktop application


I have a project with spring-websocket with this setup:

SocketHandler.java

@Component
public class SocketHandler extends TextWebSocketHandler {
    List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException {
        Map<String, String> value = new Gson().fromJson(message.getPayload(), Map.class);
        session.sendMessage(new TextMessage("Hello " + value.get("name") + " !"));
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
    }
}

WebSocketConfig.java

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new SocketHandler(), "/name");
    }
}

index.html

  <table>
    <tr>
      <td>
        <button id="connect" type="button" onclick="connect();">Connect</button>
        <button id="disconnect" type="button" disabled="disabled" onclick="disconnect();">Disconnect</button>
      </td>
      <td>
        <label for="name">What is your name?</label>
        <input type="text" id="name" placeholder="Your name here...">
        <button id="send" type="button" onclick="send();">Send</button>
      </td>
    </tr>
  </table>

  <hr>

  <table id="conversation" border="2">
      <thead>
      <tr>
          <th>Greetings</th>
      </tr>
      </thead>
      <tbody id="greetings">
      </tbody>
  </table>

script.js

var ws;

function setConnected(connected) {
    var connect = document.querySelector("#connect");
    var disconnect = document.querySelector("#disconnect");
    var conversation = document.querySelector("#conversation");
    var greetings = document.querySelector("#greetings");

    if(connected) {
      connect.setAttribute("disabled", "disabled");
      disconnect.removeAttribute("disabled");
      conversation.style.display = 'block';
    } else {
      connect.removeAttribute("disabled");
      disconnect.setAttribute("disabled", "disabled");
      conversation.style.display = 'none';
    }

    greetings.innerHTML = "";
}

function connect() {
    ws = new WebSocket('ws://localhost:8080/name');
    ws.onmessage = function(text) {
        showGreeting(text.data);
    }
    setConnected(true);
}

function disconnect() {
    if (ws != null) {
        ws.close();
    }
    setConnected(false);
}

function send() {
  var name = document.querySelector("#name");
    var data = JSON.stringify({'name': name.value});
  ws.send(data);
}

function showGreeting(message) {
  var greeting = document.querySelector("#greetings");
  var tr = document.createElement("tr");
  var td = document.createElement("td");
  td.innerText = message;
  tr.appendChild(td);
  greeting.appendChild(tr);
}

I wonder if it's possible develop a desktop client application, for example, with Java/Swing or C++/Qt, which could communicate with this application as if it was a server, receiving the data from the desktop application and broadcast to all clients connected to it.


Solution

  • Here's a minimal, non-GUI version of Java based WebSocket client.


    Server

    SocketHandler.java

    import com.google.gson.Gson;
    import java.io.IOException;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.CopyOnWriteArrayList;
    import org.springframework.stereotype.Component;
    import org.springframework.web.socket.TextMessage;
    import org.springframework.web.socket.WebSocketSession;
    import org.springframework.web.socket.handler.TextWebSocketHandler;
    
    @Component
    public class SocketHandler extends TextWebSocketHandler {
        List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
    
        @Override
        public void handleTextMessage(WebSocketSession currentSession, TextMessage message) throws InterruptedException, IOException {
            Map<String, String> value = new Gson().fromJson(message.getPayload(), Map.class);
            TextMessage textMessage = new TextMessage("Hello from " + value.get("name") + "!");
    
            for (WebSocketSession session : sessions) {
                if (session.isOpen()) {
                    session.sendMessage(textMessage);
                }
            }
        }
    
        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            sessions.add(session);
        }
    }
    

    Client

    MyWebSocketClient.java

    package com.example;
    
    import java.net.URI;
    import java.util.Scanner;
    import javax.websocket.*;
    import javax.websocket.RemoteEndpoint.Basic;
    
    @ClientEndpoint
    public class MyWebSocketClient {
        @OnMessage
        public void onMessage(String message) {
            System.out.println("[Greetings] " + message + "\n");
        }
    
        public static void main(String[] args) {
            WebSocketContainer container = null;
            Session session = null;
            Basic basicRemote = null;
            Scanner inputScanner = null;
    
            try {
                container = ContainerProvider.getWebSocketContainer();
                session = container.connectToServer(MyWebSocketClient.class, URI.create("ws://localhost:8080/name"));
                basicRemote = session.getBasicRemote();
                inputScanner = new Scanner(System.in);
    
                while (true) {
                    String input = inputScanner.nextLine();
                    basicRemote.sendText("{ \"name\": \"" + input + "\" }");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    pom.xml

    <dependencies>
        <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-client-api</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus.bundles</groupId>
            <artifactId>tyrus-standalone-client</artifactId>
            <version>1.15</version>
        </dependency>
    </dependencies>
    

    Result:

    enter image description here