├── .color ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main └── java └── sample ├── Application.java ├── ClientMessage.java └── ServerMessage.java /.color: -------------------------------------------------------------------------------- 1 | #402D2B 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 jaysridhar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring WebSocket Chat Client 2 | 3 | A sample implementation demonstrating usage of Spring WebSockets for 4 | the client. For a compatible server implementation, see 5 | [https://github.com/jaysridhar/spring-websocket-server]. The server 6 | includes a web-based client (HTML/JS), however this client 7 | demonstrates usage of WebSockets from Java in the Spring context. 8 | 9 | Build the project using: 10 | 11 | mvn clean package 12 | 13 | And run it as follows: 14 | 15 | java -jar target/chat-client-0.1.0.jar 16 | 17 | The client connects to the server on the localhost at port 9090, send 18 | a starting message and shows a prompt on the console which can be used 19 | to send further messages. Any messages sent to the server (maybe from 20 | a second console or the web client) is also received and echoed on the 21 | console. 22 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | sample 8 | chat-client 9 | 0.1.0 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 1.4.3.RELEASE 15 | 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-websocket 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter 29 | 30 | 31 | org.springframework 32 | spring-messaging 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-maven-plugin 41 | 42 | 43 | maven-clean-plugin 44 | 2.5 45 | 46 | 47 | 48 | . 49 | 50 | **/*~ 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/main/java/sample/Application.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | 6 | import java.util.List; 7 | import java.util.ArrayList; 8 | import java.util.Map; 9 | import java.util.HashMap; 10 | 11 | import java.util.concurrent.ThreadLocalRandom; 12 | 13 | import java.lang.reflect.Type; 14 | 15 | import org.springframework.web.socket.client.WebSocketConnectionManager; 16 | import org.springframework.web.socket.client.WebSocketClient; 17 | import org.springframework.web.socket.client.standard.StandardWebSocketClient; 18 | import org.springframework.web.socket.sockjs.client.WebSocketTransport; 19 | import org.springframework.web.socket.sockjs.client.Transport; 20 | import org.springframework.web.socket.sockjs.client.SockJsClient; 21 | import org.springframework.web.socket.sockjs.frame.Jackson2SockJsMessageCodec; 22 | import org.springframework.messaging.converter.StringMessageConverter; 23 | import org.springframework.messaging.converter.MappingJackson2MessageConverter; 24 | import org.springframework.web.socket.messaging.WebSocketStompClient; 25 | 26 | import org.springframework.messaging.simp.stomp.StompSessionHandler; 27 | import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; 28 | import org.springframework.messaging.simp.stomp.StompSession; 29 | import org.springframework.messaging.simp.stomp.StompHeaders; 30 | import org.springframework.messaging.simp.stomp.StompFrameHandler; 31 | 32 | import com.fasterxml.jackson.databind.ObjectMapper; 33 | 34 | /* 35 | * WebSocket client application. Performs client side setup and sends 36 | * messages. 37 | * 38 | * @Author Jay Sridhar 39 | */ 40 | public class Application 41 | { 42 | static public class MyStompSessionHandler 43 | extends StompSessionHandlerAdapter 44 | { 45 | private String userId; 46 | 47 | public MyStompSessionHandler(String userId) 48 | { 49 | this.userId = userId; 50 | } 51 | 52 | private void showHeaders(StompHeaders headers) 53 | { 54 | for (Map.Entry> e:headers.entrySet()) { 55 | System.err.print(" " + e.getKey() + ": "); 56 | boolean first = true; 57 | for (String v : e.getValue()) { 58 | if ( ! first ) System.err.print(", "); 59 | System.err.print(v); 60 | first = false; 61 | } 62 | System.err.println(); 63 | } 64 | } 65 | 66 | private void sendJsonMessage(StompSession session) 67 | { 68 | ClientMessage msg = new ClientMessage(userId, 69 | "hello from spring"); 70 | session.send("/app/chat/java", msg); 71 | } 72 | 73 | private void subscribeTopic(String topic,StompSession session) 74 | { 75 | session.subscribe(topic, new StompFrameHandler() { 76 | 77 | @Override 78 | public Type getPayloadType(StompHeaders headers) { 79 | return ServerMessage.class; 80 | } 81 | 82 | @Override 83 | public void handleFrame(StompHeaders headers, 84 | Object payload) 85 | { 86 | System.err.println(payload.toString()); 87 | } 88 | }); 89 | } 90 | 91 | @Override 92 | public void afterConnected(StompSession session, 93 | StompHeaders connectedHeaders) 94 | { 95 | System.err.println("Connected! Headers:"); 96 | showHeaders(connectedHeaders); 97 | 98 | subscribeTopic("/topic/messages", session); 99 | sendJsonMessage(session); 100 | } 101 | } 102 | 103 | public static void main(String args[]) throws Exception 104 | { 105 | WebSocketClient simpleWebSocketClient = 106 | new StandardWebSocketClient(); 107 | List transports = new ArrayList<>(1); 108 | transports.add(new WebSocketTransport(simpleWebSocketClient)); 109 | 110 | SockJsClient sockJsClient = new SockJsClient(transports); 111 | WebSocketStompClient stompClient = 112 | new WebSocketStompClient(sockJsClient); 113 | stompClient.setMessageConverter(new MappingJackson2MessageConverter()); 114 | 115 | String url = "ws://localhost:9090/chat"; 116 | String userId = "spring-" + 117 | ThreadLocalRandom.current().nextInt(1, 99); 118 | StompSessionHandler sessionHandler = new MyStompSessionHandler(userId); 119 | StompSession session = stompClient.connect(url, sessionHandler) 120 | .get(); 121 | BufferedReader in = 122 | new BufferedReader(new InputStreamReader(System.in)); 123 | for (;;) { 124 | System.out.print(userId + " >> "); 125 | System.out.flush(); 126 | String line = in.readLine(); 127 | if ( line == null ) break; 128 | if ( line.length() == 0 ) continue; 129 | ClientMessage msg = new ClientMessage(userId, line); 130 | session.send("/app/chat/java", msg); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/sample/ClientMessage.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | /* 4 | * Message sent to server. 5 | * 6 | * @Author Jay Sridhar 7 | */ 8 | public class ClientMessage 9 | { 10 | private String from; 11 | private String text; 12 | 13 | public ClientMessage() {} 14 | 15 | public ClientMessage(String from,String text) 16 | { 17 | this.from = from; 18 | this.text = text; 19 | } 20 | 21 | public String getFrom() 22 | { 23 | return from; 24 | } 25 | 26 | public void setFrom(String from) 27 | { 28 | this.from = from; 29 | } 30 | 31 | public String getText() 32 | { 33 | return text; 34 | } 35 | 36 | public void setText(String text) 37 | { 38 | this.text = text; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/sample/ServerMessage.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import java.util.Date; 4 | 5 | /* 6 | * Message received from server. 7 | * 8 | * @Author Jay Sridhar 9 | */ 10 | public class ServerMessage 11 | { 12 | private String from; 13 | private String message; 14 | private String topic; 15 | private Date time = new Date(); 16 | 17 | public ServerMessage() {} 18 | 19 | public ServerMessage(String from,String message,String topic) 20 | { 21 | this.from = from; 22 | this.message = message; 23 | this.topic = topic; 24 | } 25 | 26 | public String getFrom() 27 | { 28 | return from; 29 | } 30 | 31 | public void setFrom(String from) 32 | { 33 | this.from = from; 34 | } 35 | 36 | public String getMessage() 37 | { 38 | return message; 39 | } 40 | 41 | public void setMessage(String message) 42 | { 43 | this.message = message; 44 | } 45 | 46 | public String getTopic() 47 | { 48 | return topic; 49 | } 50 | 51 | public void setTopic(String topic) 52 | { 53 | this.topic = topic; 54 | } 55 | 56 | public Date getTime() 57 | { 58 | return time; 59 | } 60 | 61 | public String toString() 62 | { 63 | return String 64 | .format("{from: %1$-10s | topic: %2$-10s | time: %4$-15d | mesg: %3$s}", 65 | getFrom(), getTopic(), 66 | getMessage(), getTime().getTime()); 67 | } 68 | } 69 | --------------------------------------------------------------------------------