Desenvolvimento de aplicações de comunicação em tempo real: prática de integração Vue.js, Spring Boot e WebSocket

Índice

1. O que é webSocket 

2. Para que o webSocket pode ser usado?

3. protocolo webSocket

4. Lado do servidor

5. Cliente

6. Teste a comunicação


1. O que é webSocket 

WebSocket é um protocolo para comunicação full-duplex em uma única conexão TCP . O WebSocket facilita a troca de dados entre o cliente e o servidor, permitindo que o servidor envie dados ativamente para o cliente . Na API WebSocket, o navegador e o servidor precisam apenas concluir um aperto de mão, e uma conexão persistente pode ser criada diretamente entre os dois, e a transmissão de dados bidirecional pode ser realizada.

2. Para que o webSocket pode ser usado?

O uso das características da transmissão de dados bidirecional pode ser usado para concluir muitas funções, sem pesquisa de front-end, desperdiçando recursos. Por exemplo: 

  • Aplicativo de bate-papo em tempo real : o WebSocket pode implementar a função de bate-papo em tempo real, permitindo que os usuários enviem e recebam mensagens instantaneamente e realizem uma comunicação rápida e em tempo real.

  • Atualização de dados em tempo real : Para aplicativos que precisam atualizar dados em tempo real, como cotações de ações, previsões do tempo, etc., o WebSocket pode fornecer um mecanismo de push em tempo real, para que os dados possam ser atualizados em tempo real e exibidos para usuários em tempo hábil.

  • Jogos online multijogador : WebSocket fornece recursos de comunicação bidirecional, adequados para cenários de batalha em tempo real de jogos online multijogador, como jogos de cartas em tempo real, jogos de tabuleiro, etc.

  • Ferramentas de colaboração : Com WebSocket, ferramentas de colaboração em tempo real podem ser implementadas, como ferramentas de gerenciamento de tarefas de equipe, ferramentas de edição colaborativa etc., permitindo que os membros da equipe atualizem e sincronizem o conteúdo do trabalho em tempo real.

  • Monitoramento de tráfego de mapa em tempo real : O WebSocket pode ser usado em um sistema de monitoramento de tráfego de mapa em tempo real, permitindo que os usuários obtenham informações como condições da estrada e congestionamento de tráfego em tempo real.

  • Atendimento e suporte ao cliente online : por meio do WebSocket, o pessoal de atendimento ao cliente pode se comunicar com os clientes em tempo real, fornecendo respostas oportunas a perguntas e serviços de suporte.

  • Votação e pesquisa em tempo real : usando o WebSocket, você pode implementar um sistema de votação e pesquisa em tempo real, exibir os resultados da votação em tempo real e receber e contar os votos dos usuários. etc......

3. protocolo webSocket

Este protocolo tem duas partes: handshake e transferência de dados. O handshake é baseado no protocolo http. 

  • O aperto de mão do cliente fica assim:
GET ws://localhost/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat,superchat
Sec-WebSocket-Version: 13
  • O handshake do servidor fica assim:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

4. Lado do servidor

  • dependências do pom.xml
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  • Classe de configuração WebSocketConfig (diretório do pacote de configuração)
package com.jmh.demo03.websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    /**
     * 	注入ServerEndpointExporter,
     * 	这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}
  •  Classe de operação WebSocket (diretório do pacote de configuração)
package com.jmh.demo03.websocket.config;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
//接口路径 ws://localhost:8087/webSocket/userId;
@ServerEndpoint("/websocket/{userId}")

public class WebSocket {

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 用户ID
     */
    private String userId;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    //虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
    //  注:底下WebSocket是当前类名
    private static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();

    /**
     * 用来存在线连接用户信息
     */
    private static ConcurrentHashMap<String,Session> sessionPool = new ConcurrentHashMap<String,Session>();


    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId")String userId) {
        try {
            this.session = session;
            this.userId = userId;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("【websocket消息】用户{}连接成功,在线人数为{}",userId,webSockets.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(this.userId);
            log.info("【websocket消息】用户{}连接断开,在线人数为{}",userId,webSockets.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 消息
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("【websocket消息】收到客户端用户{},消息:{}",userId,message);
    }

    /**
     * 发送错误时的处理
     * @param session 会话
     * @param error 错误
     */
    @OnError
    public void onError(Session session, Throwable error) {

        log.error("用户错误,原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 此为广播消息
     * @param message 消息内容
     */
    public void sendAllMessage(String message) {
        log.info("【websocket消息】广播消息:"+message);
        for(WebSocket webSocket : webSockets) {
            try {
                if(webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 此为单点消息
     * @param userId 用户编号
     * @param message 消息内容
     */
    public void sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null&&session.isOpen()) {
            try {
                log.info("【websocket消息】 单点消息:"+message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 此为单点消息(多人)
     * @param userIds 用户编号组
     * @param message 消息内容
     */
    public void sendMoreMessage(String[] userIds, String message) {
        for(String userId:userIds) {
            Session session = sessionPool.get(userId);
            if (session != null&&session.isOpen()) {
                try {
                    log.info("【websocket消息】 单点消息:"+message);
                    session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

}
  • SendMessageController chama a classe de instância (diretório do pacote do controlador)
package com.jmh.demo03.websocket.controller;

import com.alibaba.fastjson2.JSONObject;
import com.jmh.demo03.websocket.config.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author 蒋明辉
 * @data 2023/8/7 14:43
 */
@RestController
@RequestMapping("/ws")
public class SendMessageController {

    @Autowired
    private WebSocket webSocket;

    /**
     * 广播消息
     */
    @PostMapping("/sendAllMessage")
    public void sendAllMessage(){
        //发送内容
        JSONObject jsonObject=new JSONObject();
        String message="【今日话题】:早睡早起,多喝开水,要爱自己多一点~";
        jsonObject.put("message",message);
        //全体发送
        webSocket.sendAllMessage(jsonObject.toString());
    }

    /**
     * 单个用户发送
     */
    @PostMapping("/sendOneMessage")
    public void sendOneMessage(){
        //发送内容
        JSONObject jsonObject=new JSONObject();
        String message="【今日话题】:早睡早起,多喝开水,要爱自己多一点~";
        jsonObject.put("abc",message);
        //单个用户发送 (userId为用户id)
        webSocket.sendOneMessage("1", jsonObject.toString());
    }

    /**
     * 多个用户发送
     */
    @PostMapping("/sendMoreMessage")
    public void sendMoreMessage(){
        //发送内容
        JSONObject jsonObject=new JSONObject();
        String message="【今日话题】:早睡早起,多喝开水,要爱自己多一点~";
        jsonObject.put("message",message);
        //多个用户发送 (userIds为多个用户id,逗号‘,’分隔)
        String str="1,2,3";
        String[] split = str.split(",");
        webSocket.sendMoreMessage(split, jsonObject.toString());
    }




}

5. Cliente

  • código  vue.js
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
		<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
		<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.js"></script>
	</head>
	<body>
		<div id="demo">
			<h1>Web Socket 正式发版</h1>
			
			<hr/>
			
			<button @click="sendKh()">发送消息(客户端)</button>
			<button @click="sendFwq()">发送消息(服务器端)</button>
			
		</div>
	</body>
	
	<script>
		new Vue({
			el: '#demo',
			data() {
				return {
					
				}
			},
			mounted() { 
				  //初始化websocket
				  this.initWebSocket()
			},
			destroyed: function () { // 离开页面生命周期函数
				  this.websocketclose();
			},
			methods: {
				initWebSocket: function () { // 建立连接
					// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
					this.websock = new WebSocket("ws://127.0.0.1:8080/websocket/1");
					this.websock.onopen = this.websocketonopen;
					//this.websock.send = this.websocketsend;
					this.websock.onerror = this.websocketonerror;
					this.websock.onmessage = this.websocketonmessage;
					this.websock.onclose = this.websocketclose;
					
				  },
				  // 连接成功后调用
				  websocketonopen: function () {
					 console.log("WebSocket连接成功");
				  },
				  // 发生错误时调用
				  websocketonerror: function (e) {
					console.log("WebSocket连接发生错误");
				  },
				  // 给后端发消息时调用
				  websocketsend: function (e) {
					console.log("WebSocket连接发生错误");
				  },
				  // 接收后端消息(服务器端发送)
				  // vue 客户端根据返回的cmd类型处理不同的业务响应
				  websocketonmessage: function (e) {
					console.info(e)
					var data = eval("(" + e.data + ")"); 
					console.info(data)
				  },
				  // 关闭连接时调用
				  websocketclose: function (e) {
					console.log("connection closed (" + e.code + ")");
				  },
				   //向服务器发送消息(客户端发送)
				  sendKh(){
					  let data={
						  message: '小明你好!我想和你成为朋友~',
						  sendData: new Date()
					  }
					  this.websock.send("尊嘟假嘟")
				  },
				  //向客户端发送消息(服务器端发送)
				  sendFwq(){
					  axios.post('http://localhost:8080/ws/sendOneMessage').then((resp)=>{
					  	console.info(resp)
					  })
				  }
			}
		})
	</script>
</html>

6. Teste a comunicação

1. Conecte-se à comunicação (abra os serviços de acesso front-end e back-end para entrar em contato com a comunicação)

2. O cliente envia uma mensagem ao servidor

  •  O cliente envia uma mensagem para o servidor

  • A mensagem recebida pelo servidor 

3. O servidor envia uma mensagem ao cliente

  • O servidor envia uma mensagem ao cliente

  •  A mensagem recebida pelo cliente

  •  Exibir mensagens do lado do servidor

Acho que você gosta

Origin blog.csdn.net/m0_63300795/article/details/132159540
Recomendado
Clasificación