-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat($STOMP): support STOMP over WebSocket
- Loading branch information
1 parent
3976af1
commit be76707
Showing
17 changed files
with
656 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
common/src/main/java/com/jmsoftware/maf/common/websocket/WebSocketMessagePayload.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.jmsoftware.maf.common.websocket; | ||
|
||
import lombok.Data; | ||
|
||
/** | ||
* Description: WebSocketMessagePayload, change description here. | ||
* | ||
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/15/2021 5:35 PM | ||
**/ | ||
@Data | ||
public class WebSocketMessagePayload { | ||
private String sender; | ||
private String receiver; | ||
private Object content; | ||
} |
18 changes: 18 additions & 0 deletions
18
common/src/main/java/com/jmsoftware/maf/common/websocket/WebSocketMessageResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.jmsoftware.maf.common.websocket; | ||
|
||
import lombok.Data; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
/** | ||
* Description: WebSocketMessagePayload, change description here. | ||
* | ||
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/15/2021 5:35 PM | ||
**/ | ||
@Data | ||
public class WebSocketMessageResponse { | ||
private final LocalDateTime timestamp = LocalDateTime.now(); | ||
private String sender; | ||
private String receiver; | ||
private Object content; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
...ter/src/main/java/com/jmsoftware/maf/springcloudstarter/websocket/GreetingController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.jmsoftware.maf.springcloudstarter.websocket; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.jmsoftware.maf.common.websocket.WebSocketMessagePayload; | ||
import com.jmsoftware.maf.common.websocket.WebSocketMessageResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.SneakyThrows; | ||
import lombok.extern.slf4j.Slf4j; | ||
import lombok.val; | ||
import org.springframework.messaging.handler.annotation.Headers; | ||
import org.springframework.messaging.handler.annotation.MessageMapping; | ||
import org.springframework.messaging.handler.annotation.Payload; | ||
import org.springframework.messaging.simp.SimpMessagingTemplate; | ||
import org.springframework.stereotype.Controller; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* Description: GreetingController, change description here. | ||
* | ||
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/15/2021 5:24 PM | ||
**/ | ||
@Slf4j | ||
@Controller | ||
@RequiredArgsConstructor | ||
public class GreetingController { | ||
private final SimpMessagingTemplate simpMessagingTemplate; | ||
private final ObjectMapper objectMapper; | ||
|
||
@SneakyThrows | ||
@MessageMapping("/send-message") | ||
public void sendMessage(@Payload WebSocketMessagePayload payload, @Headers Map<String, Object> headers) { | ||
val response = new WebSocketMessageResponse(); | ||
response.setSender(payload.getSender()); | ||
response.setReceiver(payload.getReceiver()); | ||
response.setContent(headers.get("simpSessionId").toString() + "---" + payload.getContent()); | ||
this.simpMessagingTemplate.convertAndSend("/topic/public/broadcast", | ||
this.objectMapper.writeValueAsString(response)); | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
...src/main/java/com/jmsoftware/maf/springcloudstarter/websocket/WebSocketConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.jmsoftware.maf.springcloudstarter.websocket; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.messaging.simp.SimpMessagingTemplate; | ||
import org.springframework.messaging.simp.config.MessageBrokerRegistry; | ||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; | ||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry; | ||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; | ||
import org.springframework.web.socket.server.standard.ServerEndpointExporter; | ||
|
||
import static org.springframework.web.cors.CorsConfiguration.ALL; | ||
|
||
/** | ||
* Description: WebSocketConfiguration, change description here. | ||
* | ||
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/15/2021 12:15 AM | ||
* @see | ||
* <a href='https://www.toptal.com/java/stomp-spring-boot-websocket'>Using Spring Boot for WebSocket Implementation with STOMP</a> | ||
**/ | ||
@Slf4j | ||
@EnableWebSocketMessageBroker | ||
@ConditionalOnClass({ServerEndpointExporter.class}) | ||
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer { | ||
@Bean | ||
public ServerEndpointExporter serverEndpointExporter() { | ||
log.warn("Initial bean: '{}'", ServerEndpointExporter.class.getSimpleName()); | ||
return new ServerEndpointExporter(); | ||
} | ||
|
||
@Bean | ||
public GreetingController greetingController(SimpMessagingTemplate simpMessagingTemplate, | ||
ObjectMapper objectMapper) { | ||
log.warn("Initial bean: '{}'", GreetingController.class.getSimpleName()); | ||
return new GreetingController(simpMessagingTemplate, objectMapper); | ||
} | ||
|
||
@Override | ||
public void registerStompEndpoints(StompEndpointRegistry registry) { | ||
registry.addEndpoint("/web-socket", "/ws") | ||
.setAllowedOriginPatterns(ALL) | ||
.withSockJS(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void configureMessageBroker(MessageBrokerRegistry registry) { | ||
// In-memory message broker with one or more destinations for sending and receiving messages | ||
|
||
// There are two destination prefixes defined: topic and queue. They follow the convention that destinations | ||
// for messages to be carried on to all subscribed clients via the pub-sub model should be prefixed with | ||
// "topic". | ||
// On the other hand, destinations for private messages are typically prefixed by "queue". | ||
registry.enableSimpleBroker("/topic/", "/queue/"); | ||
// Defines the prefix app that is used to filter destinations handled by methods annotated with | ||
// @MessageMapping which you will implement in a controller. The controller, after processing the message, | ||
// will send it to the broker. | ||
registry.setApplicationDestinationPrefixes("/app"); | ||
|
||
// Use this for enabling a Full featured broker like RabbitMQ | ||
/* | ||
registry.enableStompBrokerRelay("/topic") | ||
.setRelayHost("localhost") | ||
.setRelayPort(61613) | ||
.setClientLogin("guest") | ||
.setClientPasscode("guest"); | ||
*/ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
universal-ui/src/main/resources/static/script/websocket.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
'use strict'; | ||
|
||
var usernamePage = document.querySelector('#username-page'); | ||
var chatPage = document.querySelector('#chat-page'); | ||
var usernameForm = document.querySelector('#usernameForm'); | ||
var messageForm = document.querySelector('#messageForm'); | ||
var messageInput = document.querySelector('#message'); | ||
var messageArea = document.querySelector('#messageArea'); | ||
var connectingElement = document.querySelector('.connecting'); | ||
|
||
var stompClient = null; | ||
var username = null; | ||
|
||
var colors = [ | ||
'#2196F3', '#32c787', '#00BCD4', '#ff5652', | ||
'#ffc107', '#ff85af', '#FF9800', '#39bbb0' | ||
]; | ||
|
||
function connect(event) { | ||
username = document.querySelector('#name').value.trim(); | ||
|
||
if (username) { | ||
usernamePage.classList.add('hidden'); | ||
chatPage.classList.remove('hidden'); | ||
|
||
var socket = new SockJS('/web-socket'); | ||
stompClient = Stomp.over(socket); | ||
|
||
stompClient.connect({}, onConnected, onError); | ||
} | ||
event.preventDefault(); | ||
} | ||
|
||
|
||
function onConnected() { | ||
// Subscribe to the Public Topic | ||
stompClient.subscribe('/topic/public/broadcast', onMessageReceived); | ||
|
||
// Tell your username to the server | ||
// stompClient.send(`/app/join/${username}`, {},) | ||
|
||
connectingElement.classList.add('hidden'); | ||
} | ||
|
||
|
||
function onError(error) { | ||
connectingElement.textContent = 'Could not connect to WebSocket server. Please refresh this page to try again!'; | ||
connectingElement.style.color = 'red'; | ||
} | ||
|
||
|
||
function sendMessage(event) { | ||
var messageContent = messageInput.value.trim(); | ||
|
||
if (messageContent && stompClient) { | ||
var chatMessage = { | ||
sender: username, | ||
receiver: null, | ||
content: messageInput.value | ||
}; | ||
|
||
stompClient.send("/app/send-message", {}, JSON.stringify(chatMessage)); | ||
messageInput.value = ''; | ||
} | ||
event.preventDefault(); | ||
} | ||
|
||
|
||
function onMessageReceived(payload) { | ||
var body = JSON.parse(payload.body); | ||
console.info('body', body); | ||
|
||
var messageElement = document.createElement('li'); | ||
|
||
if (body.type === 'JOIN') { | ||
messageElement.classList.add('event-message'); | ||
body.content = body.sender + ' joined!'; | ||
} else if (body.type === 'LEAVE') { | ||
messageElement.classList.add('event-message'); | ||
body.content = body.sender + ' left!'; | ||
} else { | ||
messageElement.classList.add('chat-message'); | ||
|
||
var avatarElement = document.createElement('i'); | ||
var avatarText = document.createTextNode(body.sender[0]); | ||
avatarElement.appendChild(avatarText); | ||
avatarElement.style['background-color'] = getAvatarColor(body.sender); | ||
|
||
messageElement.appendChild(avatarElement); | ||
|
||
var usernameElement = document.createElement('span'); | ||
var usernameText = document.createTextNode(body.sender); | ||
usernameElement.appendChild(usernameText); | ||
messageElement.appendChild(usernameElement); | ||
} | ||
|
||
var textElement = document.createElement('p'); | ||
var messageText = document.createTextNode(body.content); | ||
textElement.appendChild(messageText); | ||
|
||
messageElement.appendChild(textElement); | ||
|
||
messageArea.appendChild(messageElement); | ||
messageArea.scrollTop = messageArea.scrollHeight; | ||
} | ||
|
||
|
||
function getAvatarColor(messageSender) { | ||
var hash = 0; | ||
for (var i = 0; i < messageSender.length; i++) { | ||
hash = 31 * hash + messageSender.charCodeAt(i); | ||
} | ||
|
||
var index = Math.abs(hash % colors.length); | ||
return colors[index]; | ||
} | ||
|
||
usernameForm.addEventListener('submit', connect, true) | ||
messageForm.addEventListener('submit', sendMessage, true) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.