栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

【Websocket】JAVA群聊、一对一聊天室

【Websocket】JAVA群聊、一对一聊天室

STOMP协议:STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。

STOMP发送帧如下形式:

>>> SEND
transaction:tx-0
destination:/app/marco
content-length:20

{"message":"Marco!"}
群聊

0、ChatMessage实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChatMessage implements Serializable {
    private MessageType type;
    private String content;
    private String sender;
    private String receiver;
}

MessageType枚举

public enum MessageType {
    CHAT,
    JOIN,
    LEAVE
}

1、webSocketCofig

@Configuration
//开启websocket服务器
@EnableWebSocketMessageBroker
@Slf4j
public class WebSocketConfig extends ServerEndpointConfig.Configurator implements WebSocketMessageBrokerConfigurer {

    
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //注册websocket端点,连接websocket服务器
        //withSockJS() 为了启用不支持websocket的浏览器
        registry.addEndpoint("/ws").withSockJS();
    }

    
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //消息到路由时,处理的方法
//        registry.setApplicationDestinationPrefixes("/app");
        //方法1:
        //路由到消息代理时,向订阅特定主题的客户端广播消息
//        registry.enableSimpleBroker("/topic");
        //方法2:use rabbitmq
        registry.enableStompBrokerRelay("/topic")
                .setRelayHost("localhost")
                //rabbitmq要先开启stomp插件,该插件默认端口为61313
                .setRelayPort(61613)
                .setClientLogin("guest")
                .setClientPasscode("guest");
    }
}

注:如何开启rabbitmq stomp

1.进入到RabbitMQ安装目录下的sbin文件夹内

2.执行命令

rabbitmq-plugins enable rabbitmq_web_stomp
rabbitmq-plugins enable rabbitmq_web_stomp_examples

2、 WebSocketEventListener

@Component
@Slf4j
public class WebSocketEvenListener {
    //实现自由向任意目的地发送消息,并且订阅此目的地的所有用户都能收到消息
    @Autowired
    private SimpMessageSendingOperations messageSendingOperations;
    //建立websocket连接
    @EventListener
    public void handleSocketConnectListener(SessionConnectedEvent event){
        log.info("received a socket connect");
    }
    //断开连接
    public void handleSocketDisconnectListener(SessionConnectedEvent event){
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        String username=(String)headerAccessor.getSessionAttributes().get("username");
        if (StringUtils.isEmpty(username)){
            log.info("user disconnect:{}",username);

            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setType(MessageType.LEAVE);
            chatMessage.setSender(username);
            //广播发送订阅了/topic/public通道的用户
            messageSendingOperations.convertAndSend("/topic/public",chatMessage);
        }
    }
}

3、ChatController

@Controller
@Slf4j
public class ChatController {

    @Autowired
    private SimpMessagingTemplate template;

    
    @MessageMapping("/chat.sendMessage")
    @SendTo("/topic/public")
    public ChatMessage sendMessage(@Payload ChatMessage chatMessage){
        log.info("{}用户对你说{}",chatMessage.getSender(),chatMessage.getContent());
        return chatMessage;
    }

    
    @MessageMapping("/chat.addUser")
    @SendTo("/topic/public")
    public ChatMessage addUser(@Payload ChatMessage chatMessage,
                               SimpMessageHeaderAccessor headerAccessor){
        //保存websocket session
        headerAccessor.getSessionAttributes().put("username",chatMessage.getSender());
        return chatMessage;
    }

}
前端页面

1、index.html




    
    
    Spring Boot WebSocket Chat Application
    Type your username
        
Spring WebSocket Chat Demo Connecting...


2、main.css

* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

html,body {
    height: 100%;
    overflow: hidden;
}

body {
    margin: 0;
    padding: 0;
    font-weight: 400;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 1rem;
    line-height: 1.58;
    color: #333;
    background-color: #f4f4f4;
    height: 100%;
}

body:before {
    height: 50%;
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background: #128ff2;
    content: "";
    z-index: 0;
}

.clearfix:after {
    display: block;
    content: "";
    clear: both;
}

.hidden {
    display: none;
}

.form-control {
    width: 100%;
    min-height: 38px;
    font-size: 15px;
    border: 1px solid #c8c8c8;
}

.form-group {
    margin-bottom: 15px;
}

input {
    padding-left: 10px;
    outline: none;
}

h1, h2, h3, h4, h5, h6 {
    margin-top: 20px;
    margin-bottom: 20px;
}

h1 {
    font-size: 1.7em;
}

a {
    color: #128ff2;
}

button {
    box-shadow: none;
    border: 1px solid transparent;
    font-size: 14px;
    outline: none;
    line-height: 100%;
    white-space: nowrap;
    vertical-align: middle;
    padding: 0.6rem 1rem;
    border-radius: 2px;
    transition: all 0.2s ease-in-out;
    cursor: pointer;
    min-height: 38px;
}

button.default {
    background-color: #e8e8e8;
    color: #333;
    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.12);
}

button.primary {
    background-color: #128ff2;
    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.12);
    color: #fff;
}

button.accent {
    background-color: #ff4743;
    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.12);
    color: #fff;
}

#username-page {
    text-align: center;
}


.username-page-container {
    background: #fff;
    box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);
    border-radius: 2px;
    width: 100%;
    max-width: 500px;
    display: inline-block;
    margin-top: 42px;
    vertical-align: middle;
    position: relative;
    padding: 35px 55px 35px;
    min-height: 250px;
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    margin: 0 auto;
    margin-top: -160px;
}



.usernameusername-page-container .username-submit {
    margin-top: 10px;
}




#chat-page {
    position: relative;
    height: 100%;
}

.chat-container {
    max-width: 700px;
    margin-left: auto;
    margin-right: auto;
    background-color: #fff;
    box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);
    margin-top: 30px;
    height: calc(100% - 60px);
    max-height: 600px;
    position: relative;
}

#chat-page ul {
    list-style-type: none;
    background-color: #FFF;
    margin: 0;
    overflow: auto;
    overflow-y: scroll;
    padding: 0 20px 0px 20px;
    height: calc(100% - 150px);
}

#chat-page #messageForm {
    padding: 20px;
}

#chat-page ul li {
    line-height: 1.5rem;
    padding: 10px 20px;
    margin: 0;
    border-bottom: 1px solid #f4f4f4;
}

#chat-page ul li p {
    margin: 0;
}

#chat-page .event-message {
    width: 100%;
    text-align: center;
    clear: both;
}

#chat-page .event-message p {
    color: #777;
    font-size: 14px;
    word-wrap: break-word;
}

#chat-page .chat-message {
    padding-left: 68px;
    position: relative;
}

#chat-page .chat-message i {
    position: absolute;
    width: 42px;
    height: 42px;
    overflow: hidden;
    left: 10px;
    display: inline-block;
    vertical-align: middle;
    font-size: 18px;
    line-height: 42px;
    color: #fff;
    text-align: center;
    border-radius: 50%;
    font-style: normal;
    text-transform: uppercase;
}

#chat-page .chat-message span {
    color: #333;
    font-weight: 600;
}

#chat-page .chat-message p {
    color: #43464b;
}

#messageForm .input-group input {
    float: left;
    width: calc(100% - 85px);
}

#messageForm .input-group button {
    float: left;
    width: 80px;
    height: 38px;
    margin-left: 5px;
}

.chat-header {
    text-align: center;
    padding: 15px;
    border-bottom: 1px solid #ececec;
}

.chat-header h2 {
    margin: 0;
    font-weight: 500;
}

.connecting {
    padding-top: 5px;
    text-align: center;
    color: #777;
    position: absolute;
    top: 65px;
    width: 100%;
}


@media screen and (max-width: 730px) {

    .chat-container {
        margin-left: 10px;
        margin-right: 10px;
        margin-top: 10px;
    }
}

@media screen and (max-width: 480px) {
    .chat-container {
        height: calc(100% - 30px);
    }

    .username-page-container {
        width: auto;
        margin-left: 15px;
        margin-right: 15px;
        padding: 25px;
    }


    #chat-page ul {
        height: calc(100% - 120px);
    }

    #messageForm .input-group button {
        width: 65px;
    }

    #messageForm .input-group input {
        width: calc(100% - 70px);
    }

    .chat-header {
        padding: 10px;
    }

    .connecting {
        top: 60px;
    }

    .chat-header h2 {
        font-size: 1.1em;
    }
}

3、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 receiverName = 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');
        //建立websocket连接
        var socket = new SockJS('/ws');
        stompClient = Stomp.over(socket);

        stompClient.connect({}, onConnected, onError);
    }
    event.preventDefault();
}


function onConnected() {
    //订阅监听/topic/public通道
    stompClient.subscribe('/topic/public', onMessageReceived);

    //添加用户
    stompClient.send("/chat.addUser",
        {},
        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();
    console.log("messagecontent:"+messageContent);
    if(messageContent && stompClient) {
        var chatMessage = {
            sender: username,
            receiver: receiverName,
            content: messageInput.value,
            type: 'CHAT'
        };
        //发送消息至/app/chat.sendMessage接口
        stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(chatMessage));
        console.log("have send"+ JSON.stringify(chatMessage))
        messageInput.value = '';
    }
    event.preventDefault();
}


//监听
function onMessageReceived(payload){
    console.log("receive success");
    console.log("payload:"+payload);
    var message = JSON.parse(payload.body);
    console.log("message:"+message);
    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)


一对一聊天

前端与群聊相似,下面只介绍JAVA的改变

1、ChatServer 

2、WebSocketEventListener都不用改

3、ChatController

@Controller
@Slf4j
public class ChatController {

    @Autowired
    private SimpMessagingTemplate template;

    //发送消息到通道,同时订阅对方和自己的通道
    @MessageMapping("/one.sendMessage")
    public ChatMessage sendMessage2(@Payload ChatMessage chatMessage){
        //对对方
        this.template.convertAndSend("/topic/"+chatMessage.getReceiver(),chatMessage);
        //对自己
        this.template.convertAndSend("/topic/"+chatMessage.getSender(),chatMessage);
        return chatMessage;
    }

    //添加用户
    @MessageMapping("/one.addUser")
    @SendTo("/user/queue/getResponse")
    public ChatMessage addUser2(@Payload ChatMessage chatMessage,
                               SimpMessageHeaderAccessor headerAccessor){
        //session
        headerAccessor.getSessionAttributes().put("username",chatMessage.getSender());
        return chatMessage;
    }

 }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/784755.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号