Я реализую чат с веб-скотчем при загрузке Spring
Это код
ChatMessage.Class
public class ChatMessage {
private MessageType type;
private String content;
private String sender;
public enum MessageType {
CHAT,
JOIN,
LEAVE
}
public MessageType getType() {
return type;
}
public void setType(MessageType type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
}
Мой WebSocketConfig.Class
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
WebSocketListener.Class
@Component
public class WebSocketEventListener {
@Autowired
private SimpMessageSendingOperations messagingTemplate;
@EventListener
public void handleWebSocketConnectListener(SessionConnectedEvent event) {
System.out.println("Received a new web socket connection");
}
@EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
String username = (String) headerAccessor.getSessionAttributes().get("username");
if (username != null) {
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessage.MessageType.LEAVE);
chatMessage.setSender(username);
messagingTemplate.convertAndSend("/topic/public", chatMessage);
}
}
}
ChatController:
@Controller
public class ChatController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/chat.sendMessage/{room}")
public void sendMessage(@Payload ChatMessage chatMessage, @DestinationVariable String room) {
simpMessagingTemplate.convertAndSend("/topic/public/"+room, chatMessage);
}
@MessageMapping("/chat.addUser/{room}")
public void addUser(@Payload ChatMessage chatMessage,
SimpMessageHeaderAccessor headerAccessor, @DestinationVariable String room) {
// Add username in web socket session
headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
simpMessagingTemplate.convertAndSend("/topic/public/"+room, chatMessage);
}
}
Мой индекс. html:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Spring Boot WebSocket Chat Application</title>
<link rel="stylesheet" href="/css/main.css" />
</head>
<body>
<noscript>
<h2>Sorry! Your browser doesn't support Javascript</h2>
</noscript>
<div id="username-page">
<div class="username-page-container">
<h1 class="title">Type your username</h1>
<form id="usernameForm" name="usernameForm">
<div class="form-group">
<input type="text" id="name" placeholder="Username" autocomplete="off" class="form-control" />
</div>
<div class="form-group">
<input type="text" id="room_num" placeholder="RoomNum" autocomplete="off" class="form-control"/>
</div>
<div class="form-group">
<button type="submit" class="accent username-submit">Start Chatting</button>
</div>
</form>
</div>
</div>
<div id="chat-page" class="hidden">
<div class="chat-container">
<div class="chat-header">
<h2>Spring WebSocket Chat Demo</h2>
</div>
<div class="connecting">
Connecting...
</div>
<ul id="messageArea">
</ul>
<form id="messageForm" name="messageForm">
<div class="form-group">
<div class="input-group clearfix">
<input type="text" id="message" placeholder="Type a message..." autocomplete="off" class="form-control"/>
<button type="submit" class="primary">Send</button>
</div>
</div>
</form>
</div>
</div>
<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
main. js:
'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 room_num = null;
var colors = [
'#2196F3', '#32c787', '#00BCD4', '#ff5652',
'#ffc107', '#ff85af', '#FF9800', '#39bbb0'
];
function connect(event) {
username = document.querySelector('#name').value.trim();
room_num = document.querySelector('#room_num').value.trim();
if(username) {
usernamePage.classList.add('hidden');
chatPage.classList.remove('hidden');
var socket = new SockJS('/ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, onConnected, onError);
}
event.preventDefault();
}
function onConnected() {
// Subscribe to the Public Topic
stompClient.subscribe('/topic/public/'+room_num, onMessageReceived);
// Tell your username to the server
stompClient.send("/app/chat.addUser/"+room_num,
{},
JSON.stringify({sender: username, type: 'JOIN'})
);
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,
content: messageInput.value,
type: 'CHAT'
};
stompClient.send("/app/chat.sendMessage/"+room_num, {}, JSON.stringify(chatMessage));
messageInput.value = '';
}
event.preventDefault();
}
function onMessageReceived(payload) {
var message = JSON.parse(payload.body);
var messageElement = document.createElement('li');
if(message.type === 'JOIN') {
messageElement.classList.add('event-message');
message.content = message.sender + ' joined!';
} else if (message.type === 'LEAVE') {
messageElement.classList.add('event-message');
message.content = message.sender + ' left!';
} else {
messageElement.classList.add('chat-message');
var avatarElement = document.createElement('i');
var avatarText = document.createTextNode(message.sender[0]);
avatarElement.appendChild(avatarText);
avatarElement.style['background-color'] = getAvatarColor(message.sender);
messageElement.appendChild(avatarElement);
var usernameElement = document.createElement('span');
var usernameText = document.createTextNode(message.sender);
usernameElement.appendChild(usernameText);
messageElement.appendChild(usernameElement);
}
var textElement = document.createElement('p');
var messageText = document.createTextNode(message.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)
Я хочу понять, что несколько чатов существуют одновременно, поэтому я не использую @ Sendto
Я определяю input room_num, чтобы указать номер комнаты чата.
В js файле используйте stompClient.send("/app/chat.sendMessage/"+room_num, {}, JSON.stringify(chatMessage));
для отправки сообщения.
В Контроллере используйте simpMessagingTemplate.convertAndSend("/topic/public/"+room, chatMessage);
получение сообщения из другого чата
Но этот способ прошивания URL будет выдавать много жесткого кода. Есть ли хорошая альтернатива?
Когда пользователь покидает комнату чата, , handleWebSocketDisconnectListener использует messagingTemplate.convertAndSend("/topic/public", chatMessage);
, чтобы уведомить пользователей в той же комнате чата, кто-то покидает эту комнату,
но URL должен быть / topic / public / room_num. Тем не менее, это DisconnectListener, он будет прослушивать все закрытые соединения. 10
Я хочу понять, что когда пользователь покидает комнату чата, он уведомляет пользователей только в той же комнате чата, что пользователь оставил