Spring Websocket Client (Without STOMP) – Example

In this brief post, let’s see how we can implement a simple web socket client for a non-stomp based websocket service.

In this example, we will be implementing the client for the demo echo test websocket service.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.idodevjobs</groupId>
    <artifactId>spring-websocket-without-stomp-client-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>spring-websocket-without-stomp-client-example</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
    </parent>

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

</project>

We have inherited the spring-boot-starter-parent pom and added the only dependency spring-boot-starter-websocket which will bring in all the required dependencies.

App.java


package com.idodevjobs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
    public static void main( String[] args ) {
        SpringApplication.run(App.class, args);
    }
}

A pretty straight forward spring boot start-up class.

SpringWebsocketWithoutStompClient.java


package com.idodevjobs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.concurrent.TimeUnit;

import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;

@Service
public class SpringWebsocketWithoutStompClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringWebsocketWithoutStompClient.class);

    @PostConstruct
    public void connect() {
        try {
            WebSocketClient webSocketClient = new StandardWebSocketClient();

            WebSocketSession webSocketSession = webSocketClient.doHandshake(new TextWebSocketHandler() {
                @Override
                public void handleTextMessage(WebSocketSession session, TextMessage message) {
                    LOGGER.info("received message - " + message.getPayload());
                }

                @Override
                public void afterConnectionEstablished(WebSocketSession session) {
                    LOGGER.info("established connection - " + session);
                }
            }, new WebSocketHttpHeaders(), URI.create("ws://echo.websocket.org")).get();

            newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
                try {
                    TextMessage message = new TextMessage("Hello !!");
                    webSocketSession.sendMessage(message);
                    LOGGER.info("sent message - " + message.getPayload());
                } catch (Exception e) {
                    LOGGER.error("Exception while sending a message", e);
                }
            }, 1, 10, TimeUnit.SECONDS);
        } catch (Exception e) {
            LOGGER.error("Exception while accessing websockets", e);
        }
    }
}

In this simple service class, we have a void method and configured it to get executed once the bean gets initiated.

There are 3 important things to pay attention to –

  • StandardWebSocketClient
  • An instance of StandardWebSocketClient – the basic WebSocketClient based on Java Websocket API.

  • TextWebSocketHandler
  • An anonymous extension of TextWebSocketHandler where we have overridden event handlers – handleTextMessage and afterConnectionEstablished to log the messages.

  • ScheduledExecutorService
  • A scheduler to send a message to the existing websocket connection at a regular interval of 10 seconds.

Running the App.java class will start the application and once SpringWebsocketWithoutStompClient gets instantiated, we can see the logs about websocket connection, send and receive messages.

Logs

2019-02-06 20:06:23.678 INFO 670 --- [cTaskExecutor-1] c.i.SpringWebsocketWithoutStompClient : established connection - StandardWebSocketSession[id=20372fd5-304f-7a23-a61c-47009d0aacbb, uri=null]
2019-02-06 20:06:23.958 INFO 670 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-02-06 20:06:24.285 INFO 670 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-02-06 20:06:24.295 INFO 670 --- [ main] com.idodevjobs.App : Started App in 4.842 seconds (JVM running for 5.507)
2019-02-06 20:06:24.702 INFO 670 --- [pool-1-thread-1] c.i.SpringWebsocketWithoutStompClient : sent message - Hello !!
2019-02-06 20:06:24.751 INFO 670 --- [lient-AsyncIO-1] c.i.SpringWebsocketWithoutStompClient : received message - Hello !!

This entry was posted in java and tagged , , , , . Bookmark the permalink.

3 Responses to Spring Websocket Client (Without STOMP) – Example

  1. Eugeny says:

    Hello! Thank you for this interesting and simple to understanding article.
    I have one question: how to make auto reconnection when any error occurred (websocket-server is being unreached or websocket-server breaks connection or etc)?

    Like

    • idodevjobs says:

      In the anonymous implementation for TextWebSocketHandler, you can override other methods such as afterConnectionClosed and handleTransportError to check and reconnect to the server.

      Like

  2. Anonymous says:

    please write the unit/integration test cases as well

    Like

Leave a comment