Enterprise Java
Web socket Java client for Stomp-Spring server side
Problem :
As an analysis for an issue I had to write a simple java web socket client site code connecting to a Spring based application on the server side with a stomp based web socket broker .
Solution :
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.rnd</groupId> <artifactId>SockWebsocketClient</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-websocket</artifactId> <version>9.0.8</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.2.RELEASE</version> <type>pom</type> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>5.0.7.RELEASE</version> </dependency> </dependencies> </project>
Sock JS Client
Its the main class , a simple one doing the basic job . As most of the web sockets these days are meant to use SSL , so tried to by pass the trust manager issue by creating a dummy TrustManager .
The input to this code is the topic string you want to subscribe to .
Also dont miss to change the <URL> string in the code before you run , pointing to your web socket url.
package com.client; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.converter.MessageConverter; import org.springframework.messaging.converter.SimpleMessageConverter; import org.springframework.messaging.converter.StringMessageConverter; import org.springframework.messaging.simp.stomp.StompHeaders; import org.springframework.web.socket.WebSocketHttpHeaders; import org.springframework.web.socket.client.standard.StandardWebSocketClient; import org.springframework.web.socket.messaging.WebSocketStompClient; import org.springframework.web.socket.sockjs.client.Transport; import org.springframework.web.socket.sockjs.client.WebSocketTransport; import org.springframework.web.socket.sockjs.frame.Jackson2SockJsMessageCodec; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.net.URI; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class SockJsClient { public static void main(String[] args) { try { StandardWebSocketClient simpleWebSocketClient = new StandardWebSocketClient(); TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); Map<String, Object> properties = new HashMap<>(); properties.put("org.apache.tomcat.websocket.SSL_CONTEXT", sc); simpleWebSocketClient.setUserProperties(properties); List<Transport> transports = new ArrayList(); transports.add(new WebSocketTransport(simpleWebSocketClient)); org.springframework.web.socket.sockjs.client.SockJsClient sockJsClient = new org.springframework.web.socket.sockjs.client.SockJsClient(transports); sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec()); WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient); stompClient.setMessageConverter(new MessageConverter() { @Override public Object fromMessage(Message<?> message, Class<?> aClass) { return new String((byte[])message.getPayload()); } @Override public Message<?> toMessage(Object o, MessageHeaders messageHeaders) { return null; } }); // url : pointing to websocket as sockJs first tries to get info by sending a HTTP request // and then sends an upgrade request to ws or wss. So your url should be some thing like htttp:// URI stompUrlEndpoint = new URI("<url>"); WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders(); StompHeaders connectHeaders = new StompHeaders(); /*Can set connection header like login , passcode in connectHeaders */ stompClient.connect(stompUrlEndpoint.toString(), handshakeHeaders, connectHeaders, new SessionHandler(args[0]), new Object[0]); Thread.sleep(30000); stompClient.stop(); } catch (Exception e) { e.printStackTrace(); } } }
Session Handler
Every socket connection need a session handler and here is one which takes care of connection setup and in-coming messages.
package com.client; import org.springframework.messaging.simp.stomp.StompCommand; import org.springframework.messaging.simp.stomp.StompFrameHandler; import org.springframework.messaging.simp.stomp.StompHeaders; import org.springframework.messaging.simp.stomp.StompSession; import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; import java.lang.reflect.Type; public class SessionHandler extends StompSessionHandlerAdapter { private final String topicName ; public SessionHandler(String topicName) { this.topicName = topicName; } @Override public void afterConnected(StompSession session, StompHeaders connectedHeaders) { this.subscribeTo(session); } @Override public void handleException(StompSession session,StompCommand command,StompHeaders headers,byte[] payload,Throwable exception ) { exception.printStackTrace(); } public void handleFrame(StompHeaders headers, Object payload) { System.out.println(payload.toString()); } @Override public void handleTransportError(StompSession session, Throwable exception) { exception.printStackTrace(); } private void subscribeTo(StompSession session) { StompHeaders headers = new StompHeaders(); headers.add("id","websocket-session-standalone-0"); headers.add("destination",topicName); session.subscribe(headers, new StompFrameHandler() { @Override public Type getPayloadType(StompHeaders stompHeaders) { return String.class; } @Override public void handleFrame(StompHeaders stompHeaders, Object o) { System.out.println( " Message is " + o.toString() ); } }); } }
Published on Java Code Geeks with permission by Abhijeet Iyengar, partner at our JCG program. See the original article here: Web socket java client for Stomp-Spring server side.
Opinions expressed by Java Code Geeks contributors are their own. |