Commit 7de29276fc9114a4f4b57c9ff8f4cf20735b22b5

Authored by Thomas Ziemer
1 parent 9144b122

feature: WebSockets um ein exemplarisches JSON-Marshalling erweitert

src/main/java/net/ziemers/swxercise/ui/ws/WebSocketController.java
@@ -4,7 +4,13 @@ import org.slf4j.Logger; @@ -4,7 +4,13 @@ import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory; 4 import org.slf4j.LoggerFactory;
5 5
6 import javax.annotation.PostConstruct; 6 import javax.annotation.PostConstruct;
7 -import javax.websocket.*; 7 +import javax.websocket.CloseReason;
  8 +import javax.websocket.EncodeException;
  9 +import javax.websocket.OnClose;
  10 +import javax.websocket.OnError;
  11 +import javax.websocket.OnMessage;
  12 +import javax.websocket.OnOpen;
  13 +import javax.websocket.Session;
8 import javax.websocket.server.PathParam; 14 import javax.websocket.server.PathParam;
9 import javax.websocket.server.ServerEndpoint; 15 import javax.websocket.server.ServerEndpoint;
10 import java.io.IOException; 16 import java.io.IOException;
@@ -15,16 +21,18 @@ import java.util.Set; @@ -15,16 +21,18 @@ import java.util.Set;
15 /** 21 /**
16 * Stub für die WebSocket-Unterstützung. 22 * Stub für die WebSocket-Unterstützung.
17 * 23 *
18 - * Muss bei Bedarf noch um ein JSON-Marshalling erweitert werden.  
19 - *  
20 * Aufgepasst: Mittels CDI kann nur @ApplicationScoped injiziert werden, 24 * Aufgepasst: Mittels CDI kann nur @ApplicationScoped injiziert werden,
21 * da während eines WebSocket-Callbacks kein Session-Kontext aktiv ist. 25 * da während eines WebSocket-Callbacks kein Session-Kontext aktiv ist.
22 */ 26 */
23 -@ServerEndpoint(WebSocketController.serverEndpointPath) 27 +@ServerEndpoint(value = WebSocketController.serverEndpointPath,
  28 + encoders = { WebSocketJson.MessageEncoder.class },
  29 + decoders = { WebSocketJson.MessageDecoder.class } )
24 public class WebSocketController { 30 public class WebSocketController {
25 31
26 static final String serverEndpointPath = "/ws/api/v1/anEndpoint/{aParameter}"; 32 static final String serverEndpointPath = "/ws/api/v1/anEndpoint/{aParameter}";
27 33
  34 + // Eine Verknüpfung zwischen der WebSocket-Session und dem SessionContext des per REST
  35 + // angemeldeten Benutzers muss irgendwie auch noch realisiert werden. :)
28 private static Set<Session> peers = Collections.synchronizedSet(new HashSet<>()); 36 private static Set<Session> peers = Collections.synchronizedSet(new HashSet<>());
29 37
30 private Logger logger; 38 private Logger logger;
@@ -48,15 +56,18 @@ public class WebSocketController { @@ -48,15 +56,18 @@ public class WebSocketController {
48 /** 56 /**
49 * Callback-Methode, die den Empfang einer neuen WebSocket-Nachricht signalisiert. 57 * Callback-Methode, die den Empfang einer neuen WebSocket-Nachricht signalisiert.
50 * 58 *
51 - * @param message der Inhalt der WebSocket-Nachricht 59 + * @param json der JSON-strukturierte Inhalt der WebSocket-Nachricht
52 * @param session das {@link Session}-Objekt der sendenden WebSocket-Verbindung 60 * @param session das {@link Session}-Objekt der sendenden WebSocket-Verbindung
53 */ 61 */
54 @OnMessage 62 @OnMessage
55 - public void onMessage(String message, Session session, @PathParam("aParameter") String param) {  
56 - logger.info("WebSocket Message '{}/{}' received by session id #{}", message, param, session.getId()); 63 + public void onMessage(WebSocketJson json,
  64 + Session session,
  65 + @PathParam("aParameter") String param) throws IOException, EncodeException {
  66 + logger.info("WebSocket Message '{}/{}' received by session id #{}",
  67 + json.getMessage(), param, session.getId());
57 try { 68 try {
58 - // wir senden die empfangene Nachricht gleich wieder zurück  
59 - session.getBasicRemote().sendText(String.format("%s/%s", message, param)); 69 + // Wir senden die empfangene Nachricht gleich wieder zurück. Das Marshalling geschieht automatisch.
  70 + session.getBasicRemote().sendObject(json);
60 } catch (IOException e) { 71 } catch (IOException e) {
61 e.printStackTrace(); 72 e.printStackTrace();
62 } 73 }
src/main/java/net/ziemers/swxercise/ui/ws/WebSocketJson.java 0 → 100644
  1 +package net.ziemers.swxercise.ui.ws;
  2 +
  3 +import javax.json.Json;
  4 +import javax.json.JsonObject;
  5 +import javax.json.JsonReader;
  6 +import javax.json.JsonReaderFactory;
  7 +import javax.websocket.DecodeException;
  8 +import javax.websocket.Decoder;
  9 +import javax.websocket.EncodeException;
  10 +import javax.websocket.Encoder;
  11 +import javax.websocket.EndpointConfig;
  12 +import java.io.StringReader;
  13 +import java.util.Collections;
  14 +
  15 +/**
  16 + * Ein Beispiel-JSON zur Übertragung durch den WebSocket.
  17 + */
  18 +public class WebSocketJson {
  19 +
  20 + /**
  21 + * Wandelt ein Objekt der Klasse in einen JSON-String um.
  22 + */
  23 + public static class MessageEncoder implements Encoder.Text<WebSocketJson> {
  24 +
  25 + @Override
  26 + public void init(EndpointConfig config) {
  27 + }
  28 +
  29 + @Override
  30 + public String encode(WebSocketJson message) throws EncodeException {
  31 + return Json.createObjectBuilder()
  32 + .add("username", message.getUsername())
  33 + .add("message", message.getMessage())
  34 + .build()
  35 + .toString();
  36 + }
  37 +
  38 + @Override
  39 + public void destroy() {
  40 + }
  41 +
  42 + }
  43 +
  44 + /**
  45 + * Wandelt einen JSON-String in ein Objekt der Klasse um.
  46 + */
  47 + public static class MessageDecoder implements Decoder.Text<WebSocketJson> {
  48 +
  49 + private JsonReaderFactory factory = Json.createReaderFactory(Collections.emptyMap());
  50 +
  51 + @Override
  52 + public void init(EndpointConfig config) {
  53 + }
  54 +
  55 + @Override
  56 + public WebSocketJson decode(String str) throws DecodeException {
  57 + WebSocketJson message = new WebSocketJson();
  58 + JsonReader reader = factory.createReader(new StringReader(str));
  59 + JsonObject json = reader.readObject();
  60 +
  61 + message.setUsername(json.getString("username"));
  62 + message.setMessage(json.getString("message"));
  63 +
  64 + return message;
  65 + }
  66 +
  67 + @Override
  68 + public boolean willDecode(String str) {
  69 + return true;
  70 + }
  71 +
  72 + @Override
  73 + public void destroy() {
  74 + }
  75 +
  76 + }
  77 +
  78 + /*
  79 + * Payload der JSON-Nachricht
  80 + */
  81 + private String username;
  82 +
  83 + private String message;
  84 +
  85 + private WebSocketJson() {}
  86 +
  87 + public String getUsername() {
  88 + return username;
  89 + }
  90 +
  91 + private void setUsername(String username) {
  92 + this.username = username;
  93 + }
  94 +
  95 + public String getMessage() {
  96 + return message;
  97 + }
  98 +
  99 + private void setMessage(String message) {
  100 + this.message = message;
  101 + }
  102 +
  103 +}
src/main/webapp/websockets.html
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 -<html lang="en">  
3 -<head>  
4 - <meta charset="UTF-8">  
5 - <title>Test WebSockets</title>  
6 -</head>  
7 -<body>  
8 - <script>  
9 - var url = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint/4711";  
10 - var webSocket = new WebSocket(url);  
11 -  
12 - // Callback-Methoden für die WebSocket-Kommunikation  
13 - webSocket.onopen = function(e) { onWebSocketOpen(e) };  
14 - webSocket.onclose = function(e) { onWebSocketClose(e) };  
15 - webSocket.onmessage = function(e) { onWebSocketMessage(e) };  
16 - webSocket.onerror = function(e) { onWebSocketError(e) };  
17 -  
18 - function onWebSocketOpen(e) {  
19 - console.log("WebSocket has been opened.");  
20 - }  
21 -  
22 - function onWebSocketClose(e) {  
23 - console.log("WebSocket has been closed.");  
24 - }  
25 -  
26 - function onWebSocketMessage(e) {  
27 - console.log("WebSocket Message '" + e.data + "' has been received.");  
28 - }  
29 -  
30 - function onWebSocketError(e) {  
31 - alert("WebSocket Error " + e + " has been thrown!");  
32 - }  
33 -  
34 - function sendWebSocketMessage() {  
35 - webSocket.send('Hello World!');  
36 - console.log("Tried to send WebSocket Message.");  
37 - }  
38 - </script>  
39 - <button onclick="sendWebSocketMessage()">Klick mich.</button>  
40 -</body> 2 +<html lang="de">
  3 + <head>
  4 + <meta charset="UTF-8">
  5 + <title>Test WebSockets</title>
  6 + </head>
  7 +
  8 + <body>
  9 + <script>
  10 + var url = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint/4711";
  11 + var webSocket = new WebSocket(url);
  12 +
  13 + // Callback-Methoden für die WebSocket-Kommunikation
  14 + webSocket.onopen = function(e) { onWebSocketOpen(e) };
  15 + webSocket.onclose = function(e) { onWebSocketClose(e) };
  16 + webSocket.onmessage = function(e) { onWebSocketMessage(e) };
  17 + webSocket.onerror = function(e) { onWebSocketError(e) };
  18 +
  19 + function onWebSocketOpen(e) {
  20 + console.log("WebSocket has been opened.");
  21 + }
  22 +
  23 + function onWebSocketClose(e) {
  24 + console.log("WebSocket has been closed.");
  25 + }
  26 +
  27 + function onWebSocketMessage(e) {
  28 + // JSON-String in ein JavaScript-Objekt konvertieren
  29 + var json = JSON.parse(e.data);
  30 +
  31 + console.log("WebSocket Message '" + json.message + "' has been received.");
  32 + }
  33 +
  34 + function onWebSocketError(e) {
  35 + alert("WebSocket Error " + e + " has been thrown!");
  36 + }
  37 +
  38 + function sendWebSocketMessage() {
  39 + var json = {
  40 + "username": "admin",
  41 + "message": "Hello World!"
  42 + }
  43 +
  44 + // JavaScript-Objekt in einen JSON-String konvertieren
  45 + webSocket.send(JSON.stringify(json));
  46 +
  47 + console.log("Tried to send WebSocket Message.");
  48 + }
  49 + </script>
  50 + <button onclick="sendWebSocketMessage()">Klick mich.</button>
  51 + </body>
41 </html> 52 </html>
42 \ No newline at end of file 53 \ No newline at end of file