项目工作日志(十五)

webSocket前后端

后端

相关依赖

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>


		<dependency>
			<groupId>jakarta.websocket</groupId>
			<artifactId>jakarta.websocket-api</artifactId>
		</dependency>

相关配置

后来由于无法注入spring boot依赖,修改过多次,但是最终还是没有成功,最后还是保持了原本状态

@Configuration
public class WebSocketConfig extends ServerEndpointConfig.Configurator {

    /*private final ApplicationContext applicationContext;

    public WebSocketConfig(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
*/
    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的WebSocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

WebSocket

@onOpen, @onclose,@onerror,@message等都是直接按照教程写的,改变成本项目适配的,对于接收信息写了一个函数sendmessage(),主要是这些

package com.mental.mental.utils;


import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.mental.mental.config.WebSocketConfig;
import com.mental.mental.service.ChatService;
import jakarta.annotation.PostConstruct;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;


import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * WebSocket实现类
 * @author 周恒
 * @date 24/5/18
 */

@ServerEndpoint(value = "/websocket/{username}")
@Component
public class WebSocket {

    //private static ApplicationContext applicationContext;
   //@Autowired
   //private ChatService chatService;
   //@Autowired
   //public void setChatService(ChatService chatService){
   //    this.chatService = chatService;
  // }

  // @Autowired
  // public void setApplicationContext(ApplicationContext applicationContext) {
     //  WebSocket.applicationContext = applicationContext;
   //}

   //@PostConstruct
 //  public void init() {
    //   chatService = applicationContext.getBean(ChatService.class);
  // }



   private static final Logger log = LoggerFactory.getLogger(WebSocket.class);

    /**
     * 记录当前在线连接数
     */
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();//适用于多线程

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username){
        sessionMap.put(username,session);
        log.info("有新用户加入,username={}, 当前在线人数为:{}",username,sessionMap.size());
        JSONObject result = new JSONObject();
        JSONArray array = new JSONArray();
        result.set("users",array);

        for(Object key : sessionMap.keySet()){
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("username",key);
            array.add(jsonObject);
        }
        sendAllMessage(JSONUtil.toJsonStr(result));//后台发送消息给所有的客户端
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session,@PathParam("username") String username){
        sessionMap.remove(username);
        log.info("有一连接关闭,移除username={}的用户session, 当前在线人数为:{}",username,sessionMap.size());
    }

    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     * @param message
     * @param session
     * @param username
     */
    @OnMessage
    public void onMessage(String message,Session session,@PathParam("username") String username){
        log.info("服务器收到用户username={}的消息:{}",username,message);



        JSONObject obj = JSONUtil.parseObj(message);
        String toUsername = obj.getStr("to");
        String text = obj.getStr("content");//发送的消息文本

        //chatService.saveMessage(username,toUsername,text);


        Session toSession = sessionMap.get(toUsername);//根据to用户名获取session,再通过session发送消息文本
        //{"to":"user2","text":" "}
        if(toSession!=null){
            //服务器端,再把消息组装一下,组装后的消息包含发送人和发送的文本内容
            //{"from":"user1","text":""}
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("from",username);
            jsonObject.set("to", toUsername);
            jsonObject.set("text",text);
            this.sendMessage(jsonObject.toString(),toSession);
            log.info("发送给用户username={},消息:{}", toUsername, jsonObject.toString());
        } else {
            log.info("发送失败,未找到用户username={}的session", toUsername);
        }
    }

    @OnError
    public void onError(Session session, Throwable error){
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 服务端发送消息给客户端
     * @param message
     * @param toSession
     */
    private void sendMessage(String message,Session toSession){
        try{
            log.info("服务端给客户端[{}]发送消息{}",toSession.getId(),message);
            toSession.getBasicRemote().sendText(message);
        }catch (Exception e){
            log.error("服务端发送消息给客户端失败",e);
        }
    }

    /**
     * 服务器端发送消息给所有客户端
     * @param message
     */
    private void sendAllMessage(String message){
        try{
            for(Session session : sessionMap.values()){
                log.info("服务端给客户端[{}]发送消息{}",session.getId(),message);
                session.getBasicRemote().sendText(message);
            }
        }catch (Exception e){
            log.error("服务器发送消息给客户端失败",e);
        }
    }
}

前端

EventBus

监听全局事件,这里我主要是用来获取webSocket返回值

在store.js里面加上

// 监听 WebSocketService 的全局事件并更新 Vuex 状态  
EventBus.$on('messageReceived', (message) => {
    store.commit('addChatMessage', message);
});

新建一个文件EventBus.js


import Vue from 'vue'

export const EventBus = new Vue()

WebSocketService.js

// WebSocketService.js
import { EventBus } from './EventBus'; // 你可以使用 EventBus 或 Vue.prototype.$emit 来触发全局事件

class WebSocketService {
    constructor() {
        this.socket = null;
        this.connect();
    }

    connect() {
        const user = JSON.parse(localStorage.getItem('user'));
        this.socket = new WebSocket('ws://localhost:9966/websocket/' + user.uname);

        this.socket.onopen = () => {
            console.log('WebSocket Connection Opened');
            // 这里可以发送认证信息或初始化消息  
        };

        this.socket.onmessage = (event) => {
            const message = JSON.parse(event.data);
            console.log('Received Message:', message);
            EventBus.$emit('messageReceived', message); // 触发全局事件  
        };

        this.socket.onerror = (error) => {
            console.error('WebSocket Error:', error);
        };

        this.socket.onclose = (event) => {
            if (event.wasClean) {
                console.log('WebSocket Connection Closed Cleanly');
            } else {
                console.error('WebSocket Connection Died');
                // 可以在这里尝试重新连接  
            }
        };
    }

    sendMessage(message) {
        if (this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(JSON.stringify(message));
        } else {
            console.error('WebSocket is not open. ReadyState:', this.socket.readyState);
        }
    }
}

export default new WebSocketService(); // 导出单例

仍然是固定套路,连接和发送信息,主要是将实例改成自己需要的形式

总结

本周和之前的vuex那一周一样,主要还是学习为主,一个以前没有接触过的东西,学习的时候有点难,但一旦学会了用的时候就很简单

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值