SpringBoot-Vue项目整合WebSocket

SpringBoot-Vue项目整合WebSocket

首发在公众号【全栈开发日记】



介绍

WebSocket是一种网络通信协议。和HTTP协议一样,都是基于TCP协议来传输数据。

为什么需要WebSocket?因为有一些功能HTTP无法满足。

HTTP协议是一种无状态的、无连接的、单项的应用层协议。基于HTTP协议的通信请求只能由客户端发起,服务端对请求做出处理。这种通信模型有一个弊端,它无法实现服务器主动向客户端发起请求。

以微信举例,张三给李四发了一条消息,这条消息来到了服务器后无法给李四的客户端推送,只能等待李四去刷新客户端来询问服务器是否有新的消息。

怎么解决这种问题呢?

1、轮询:客户端定时向服务器发送请求,服务器会马上进行处理,并关闭连接。

2、长轮询:客户端向服务器发送HTTP请求,服务器接到请求后暂不返回响应信息,这时连接会一直保持,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。

3、长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。对于服务器的要求太高了。

4、WebSocket:在WebSocket出来之前,服务器想要给客户端主动推送消息的话,需要一直保持连接。而现在服务器已经知道的客户端的门牌号了,那么它们就不需要再保持联系了,服务器直接根据门牌号送货上门。

实现

客户端实现:

1、WebSocket对象
let ws=new WebSocket(url);

参数url格式说明:ws://IP地址:端口号/资源名称

2、WebSocket事件
事件事件处理程序描述
openwebsocket对象.onopen连接建立时触发
messagewebsocket对象.onmessage客户端接收服务端数据时触发
errorwebsocket对象.onerror通信发生错误时触发
closewebsocket对象.onclose连接关闭时触发
3、WebSocket方法

WebSocket对象的相关方法:

方法描述
send()使用连接发送数据
具体编程:

如下为Vue示例代码:

① 创建websocket对象
let ws=new WebSocket('ws://IP地址/接口');
② 给ws绑定事件
  data() {
    return {
      socket:''
    }
  },

  methods:{
      init(){
          // 实例化socket
          this.socket = new WebSocket(this.$ws+'/news')
          // 监听socket连接
          this.socket.onopen = this.open
          // 监听socket错误信息
          this.socket.onerror = this.error
          // 监听socket消息
          this.socket.onmessage = this.getMessage
		 // 监听socket断开连接的消息
          this.socket.close=this.close
      },
      open(){
        console.log("socket连接成功")
      },
      error(){
        console.log("连接错误")
      },
      getMessage(message){
        console.log("收到消息");
        console.log(message);
      },
      close(){
        console.log("连接关闭");
      },

  },
  mounted(){
      setTimeout(()=>{
          this.$root.loading=false
      }, 1500);
      this.init();
  },

服务端实现:

1、编程式:

继承类javax.websocket.Endpoint并实现其方法。

2、注解式:

定义一个POJO,并添加ServerEndpoint相关注解。

3、几个问题

① 服务端如何接收客户端发送的数据?

通过为Session添加MessageHandler消息处理器来接收消息,当采用注解方式定义Endpoint时,我们还可以通过OnMessage注解指定接收消息的方法。

② 服务端如何推送数据给客户端?

发送消息由RemoteEndpoint完成,其实例由Session维护,根据使用情况,我们可以通过Session.getBasicRemote获取同步消息发送的实例,然后调用其sendXxx()方法就可以发送消息,可以通过Session.getAsyncRemote获取异步消息发送实例。

具体编程:
① POM依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
② 创建HttpSession配置
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        // 获取HttpSession对象
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        // 将httpSession对象存储到配置对象中
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}
③ 创建配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    /**
     * 这个Bean的作用是自动注册使用了@ServerEndpoint注解的Bean
     * @author 二饭
     * @email 1786705138@qq.com
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
④ 创建接口
import cn.tworice.blog.ws.GetHttpSessionConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/news",configurator = GetHttpSessionConfig.class)
@Component
@Slf4j
public class WsController {

    // 用来存储每一个客户端对象对应的WsController对象
    private static Map<String, WsController> onlineUsers = new ConcurrentHashMap<>();

    // 声明Session对象,通过该对象可以给指定的用户发送请求
    private Session session;

    // 声明一个HttpSession对象,之前在HttpSession中存储了用户名
    private HttpSession httpSession;

    /**
     * 连接建立时被调用
     * @author 二饭
     * @email 1786705138@qq.com
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config){
        // 将局部的session对象赋值给成员session对象
        this.session=session;
        // 获取httpSession对象
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        this.httpSession = httpSession;

        String username = (String) httpSession.getAttribute("user");

        // 将当前对象存储到容器中
        onlineUsers.put(username, this);

        // 将当前在线用户的用户名推送给所有客户端

    }
    
    /**
     * 接收到客户端消息时被调用
     * @author 二饭
     * @email 1786705138@qq.com
     */
    @OnMessage
    public void onMessage(String message,Session session){

    }

    /**
     * 连接被关闭时调用
     * @author 二饭
     * @email 1786705138@qq.com
     */
    @OnClose
    public void onClose(Session session){

    }


    /**
     * 将消息广播给所有用户
     * 将对象转为json字符串传递
     * @author 二饭
     * @email 1786705138@qq.com
     */
    public void broadcastAllUser(String message){
        try {
            Set<String> strings = onlineUsers.keySet();
            for(String name:strings){
                WsController wsController = onlineUsers.get(name);
                wsController.session.getBasicRemote().sendText(message);
            }
        }catch (Exception ex){
            log.error("广播消息出现异常");
            ex.printStackTrace();

        }

    }

}

消息格式

  • 客户端 => 服务端
{"toName":"张三","message":"你好"}
  • 服务端 => 客户端

系统消息格式:

{"isSystem":true,"fromName":null,"message":{"李四","王五"}}

推送给某一个的消息格式:

{"isSystem":true,"fromName":"张三","message":"你好"}
### SpringBootVue整合WebSocket的实现方法 #### 1. SpringBoot 配置 WebSocketSpringBoot 中配置 WebSocket 的关键步骤包括引入依赖、创建配置类以及定义自定义 Endpoint。 - **引入依赖** 在项目的 `pom.xml` 文件中添加 WebSocket 的启动器依赖[^1]: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` - **创建 WebSocketConfig 配置类** 创建一个名为 `WebSocketConfig` 的配置类,用于注册 WebSocket 的服务器端点。该类通过 `ServerEndpointExporter` 将注解方式的 WebSocket 端点暴露出来[^2]: ```java @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } ``` - **定义自定义 WebSocket Endpoint** 创建一个类并使用 `@ServerEndpoint` 注解来定义 WebSocket 的通信路径。例如: ```java @ServerEndpoint("/websocket/{userId}") public class WebSocketServer { private static final Set<WebSocketServer> webSocketSet = Collections.synchronizedSet(new HashSet<>()); @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { // 处理客户端连接 webSocketSet.add(this); } @OnMessage public void onMessage(String message, Session session) { // 处理客户端消息 } @OnClose public void onClose(Session session) { // 处理客户端断开连接 webSocketSet.remove(this); } @OnError public void onError(Session session, Throwable throwable) { // 处理错误 } } ``` #### 2. Vue 前端实现 WebSocketVue 项目中,可以通过原生 JavaScript 的 `WebSocket` API 或第三方库(如 `sockjs-client` 和 `stompjs`)实现 WebSocket 的连接和消息交互。 - **创建 WebSocket 连接** 在 Vue 组件或 Vuex 中初始化 WebSocket 连接: ```javascript export default { data() { return { socket: null, }; }, created() { this.initWebSocket(); }, beforeDestroy() { this.closeWebSocket(); }, methods: { initWebSocket() { const wsUrl = `ws://localhost:8080/websocket/${this.userId}`; this.socket = new WebSocket(wsUrl); this.socket.onopen = () => { console.log("WebSocket 已连接"); }; this.socket.onmessage = (event) => { console.log("收到消息:", event.data); }; this.socket.onclose = () => { console.log("WebSocket 已关闭"); }; this.socket.onerror = () => { console.error("WebSocket 错误"); }; }, closeWebSocket() { if (this.socket && this.socket.readyState === WebSocket.OPEN) { this.socket.close(); } }, }, }; ``` - **发送消息到后端** 使用 `send` 方法向后端发送消息: ```javascript this.socket.send(JSON.stringify({ type: "message", content: "Hello from Vue" })); ``` #### 3. 注意事项 - 确保前后端的 WebSocket 路径一致,例如 `/websocket/{userId}`。 - 如果需要跨域支持,可以在 SpringBoot 的配置中添加 CORS 支持[^1]。 - 在生产环境中,建议使用更稳定的协议(如 SockJS 或 STOMP)替代原生 WebSocket。 ### 示例代码总结 - SpringBoot 后端 WebSocket 配置类和自定义 Endpoint[^1]。 - Vue 前端 WebSocket 初始化和消息处理逻辑[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值