From c83c449fa5a7ac2462fabf0ed26969f1b037aa12 Mon Sep 17 00:00:00 2001 From: Alex Vargas Date: Sun, 5 Mar 2017 02:09:37 -0800 Subject: [PATCH] Bael 389 - Chat-like app using the Java API for WebSocket (#1265) * Project for " A Guide to the Java API for WebSocket" article * Setting dependencies correctly * Formatting adjustments * Removing tomcat7 maven plugin * Applying formatt - No spaces --- java-websocket/pom.xml | 41 ++++++ .../main/java/com/baeldung/model/Message.java | 36 +++++ .../com/baeldung/websocket/ChatEndpoint.java | 71 +++++++++ .../baeldung/websocket/MessageDecoder.java | 32 +++++ .../baeldung/websocket/MessageEncoder.java | 27 ++++ .../src/main/webapp/WEB-INF/beans.xml | 5 + .../src/main/webapp/WEB-INF/web.xml | 7 + java-websocket/src/main/webapp/index.html | 30 ++++ java-websocket/src/main/webapp/style.css | 136 ++++++++++++++++++ java-websocket/src/main/webapp/websocket.js | 23 +++ 10 files changed, 408 insertions(+) create mode 100644 java-websocket/pom.xml create mode 100644 java-websocket/src/main/java/com/baeldung/model/Message.java create mode 100644 java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java create mode 100644 java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java create mode 100644 java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java create mode 100644 java-websocket/src/main/webapp/WEB-INF/beans.xml create mode 100644 java-websocket/src/main/webapp/WEB-INF/web.xml create mode 100644 java-websocket/src/main/webapp/index.html create mode 100644 java-websocket/src/main/webapp/style.css create mode 100644 java-websocket/src/main/webapp/websocket.js diff --git a/java-websocket/pom.xml b/java-websocket/pom.xml new file mode 100644 index 0000000000..929e6491fd --- /dev/null +++ b/java-websocket/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + com.baeldung + java-websocket + war + 0.0.1-SNAPSHOT + java-websocket Maven Webapp + http://maven.apache.org + + + UTF-8 + + + + + javax.websocket + javax.websocket-api + 1.1 + + + com.google.code.gson + gson + 2.8.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + diff --git a/java-websocket/src/main/java/com/baeldung/model/Message.java b/java-websocket/src/main/java/com/baeldung/model/Message.java new file mode 100644 index 0000000000..3d5bbcbc5d --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/model/Message.java @@ -0,0 +1,36 @@ +package com.baeldung.model; + +public class Message { + private String from; + private String to; + private String content; + + @Override + public String toString() { + return super.toString(); + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java b/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java new file mode 100644 index 0000000000..c4e20f4b27 --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java @@ -0,0 +1,71 @@ +package com.baeldung.websocket; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.websocket.EncodeException; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +import com.baeldung.model.Message; + +@ServerEndpoint(value = "/chat/{username}", decoders = MessageDecoder.class, encoders = MessageEncoder.class) +public class ChatEndpoint { + private Session session; + private static final Set chatEndpoints = new CopyOnWriteArraySet<>(); + private static HashMap users = new HashMap<>(); + + @OnOpen + public void onOpen(Session session, @PathParam("username") String username) throws IOException, EncodeException { + + this.session = session; + chatEndpoints.add(this); + users.put(session.getId(), username); + + Message message = new Message(); + message.setFrom(username); + message.setContent("Connected!"); + broadcast(message); + } + + @OnMessage + public void onMessage(Session session, Message message) throws IOException, EncodeException { + message.setFrom(users.get(session.getId())); + broadcast(message); + } + + @OnClose + public void onClose(Session session) throws IOException, EncodeException { + chatEndpoints.remove(this); + Message message = new Message(); + message.setFrom(users.get(session.getId())); + message.setContent("Disconnected!"); + broadcast(message); + } + + @OnError + public void onError(Session session, Throwable throwable) { + // Do error handling here + } + + private static void broadcast(Message message) throws IOException, EncodeException { + chatEndpoints.forEach(endpoint -> { + synchronized (endpoint) { + try { + endpoint.session.getBasicRemote() + .sendObject(message); + } catch (IOException | EncodeException e) { + e.printStackTrace(); + } + } + }); + } + +} diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java new file mode 100644 index 0000000000..29ae5b93e6 --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java @@ -0,0 +1,32 @@ +package com.baeldung.websocket; + +import javax.websocket.DecodeException; +import javax.websocket.Decoder; +import javax.websocket.EndpointConfig; + +import com.baeldung.model.Message; +import com.google.gson.Gson; + +public class MessageDecoder implements Decoder.Text { + @Override + public Message decode(String s) throws DecodeException { + Gson gson = new Gson(); + Message message = gson.fromJson(s, Message.class); + return message; + } + + @Override + public boolean willDecode(String s) { + return (s != null); + } + + @Override + public void init(EndpointConfig endpointConfig) { + // Custom initialization logic + } + + @Override + public void destroy() { + // Close resources + } +} diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java new file mode 100644 index 0000000000..bfecc87a96 --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java @@ -0,0 +1,27 @@ +package com.baeldung.websocket; + +import javax.websocket.EncodeException; +import javax.websocket.Encoder; +import javax.websocket.EndpointConfig; + +import com.baeldung.model.Message; +import com.google.gson.Gson; + +public class MessageEncoder implements Encoder.Text { + @Override + public String encode(Message message) throws EncodeException { + Gson gson = new Gson(); + String json = gson.toJson(message); + return json; + } + + @Override + public void init(EndpointConfig endpointConfig) { + // Custom initialization logic + } + + @Override + public void destroy() { + // Close resources + } +} diff --git a/java-websocket/src/main/webapp/WEB-INF/beans.xml b/java-websocket/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..73cd0d8e10 --- /dev/null +++ b/java-websocket/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/java-websocket/src/main/webapp/WEB-INF/web.xml b/java-websocket/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..9f88c1f963 --- /dev/null +++ b/java-websocket/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/java-websocket/src/main/webapp/index.html b/java-websocket/src/main/webapp/index.html new file mode 100644 index 0000000000..2b76fb1e49 --- /dev/null +++ b/java-websocket/src/main/webapp/index.html @@ -0,0 +1,30 @@ + + + Chat + + + + + + + + + + + + + +
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/java-websocket/src/main/webapp/style.css b/java-websocket/src/main/webapp/style.css new file mode 100644 index 0000000000..ec0982005a --- /dev/null +++ b/java-websocket/src/main/webapp/style.css @@ -0,0 +1,136 @@ +body { + font-family: Arial, Helvetica, sans-serif; + font-size: 80%; + background-color: #1f1f1f; +} + +#wrapper { + width: 960px; + margin: auto; + text-align: left; + color: #d9d9d9; +} + +p { + text-align: left; +} + +.button { + display: inline; + color: #fff; + background-color: #f2791d; + padding: 8px; + margin: auto; + border-radius: 8px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + box-shadow: none; + border: none; +} + +.button:hover { + background-color: #ffb15e; +} +.button a, a:visited, a:hover, a:active { + color: #fff; + text-decoration: none; +} + +#addDevice { + text-align: center; + width: 960px; + margin: auto; + margin-bottom: 10px; +} + +#addDeviceForm { + text-align: left; + width: 400px; + margin: auto; + padding: 10px; +} + +#addDeviceForm span { + display: block; +} + +#content { + margin: auto; + width: 960px; +} + +.device { + width: 180px; + height: 110px; + margin: 10px; + padding: 16px; + color: #fff; + vertical-align: top; + border-radius: 8px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + display: inline-block; +} + +.device.off { + background-color: #c8cccf; +} + +.device span { + display: block; +} + +.deviceName { + text-align: center; + font-weight: bold; + margin-bottom: 12px; +} + +.removeDevice { + margin-top: 12px; + text-align: center; +} + +.device.Appliance { + background-color: #5eb85e; +} + +.device.Appliance a:hover { + color: #a1ed82; +} + +.device.Electronics { + background-color: #0f90d1; +} + +.device.Electronics a:hover { + color: #4badd1; +} + +.device.Lights { + background-color: #c2a00c; +} + +.device.Lights a:hover { + color: #fad232; +} + +.device.Other { + background-color: #db524d; +} + +.device.Other a:hover { + color: #ff907d; +} + +.device a { + text-decoration: none; +} + +.device a:visited, a:active, a:hover { + color: #fff; +} + +.device a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/java-websocket/src/main/webapp/websocket.js b/java-websocket/src/main/webapp/websocket.js new file mode 100644 index 0000000000..39e5687f0c --- /dev/null +++ b/java-websocket/src/main/webapp/websocket.js @@ -0,0 +1,23 @@ +var ws; + +function connect() { + var username = document.getElementById("username").value; + ws = new WebSocket("ws://" + document.location.host + "/java-websocket/chat/" + username); + + + ws.onmessage = function(event) { + var log = document.getElementById("log"); + console.log(event.data); + var message = JSON.parse(event.data); + log.innerHTML += message.from + " : " + message.content + "\n"; + }; +} + +function send() { + var content = document.getElementById("msg").value; + var json = JSON.stringify({ + "content":content + }); + + ws.send(json); +} \ No newline at end of file