双工通信:WebSocket服务

(一)WebSocket概述

WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信------浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输

注意;Websocket也只能由客户端先握手建立连接,但是双方都可以申请结束会话

(二)入门案例

实现步骤:

①直接使用websocket.html页面作为WebSocket客户端

连接建立:
A[页面加载] --> B[创建 WebSocket 对象]
B --> C[发起握手请求]
C --> D[服务器响应 101 状态码]
D --> E[触发 onopen 回调]
页面代码如下:

html 复制代码
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Demo</title>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">发送消息</button>
    <button onclick="closeWebSocket()">关闭连接</button>
    <div id="message">
    </div>
</body>
<script type="text/javascript">
    var websocket = null;
    var clientId = Math.random().toString(36).substr(2);//将生成的随机数转换为36进制,substr(2) 截取去掉开头的 "0."

    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        //连接WebSocket节点,当打开页面时会自动创建一个会话,clientId是当前客户端的标识(刷新后重新执行获得新的clientId)

//下面的连接地址也会交给Nginx进行代理转发
        websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);//协议地址:ws:// 表示非加密 WebSocket,wss:// 表示加密   创建对象时立即尝试与服务器建立连接
    }
    else{
        alert('Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };

    //连接成功建立的回调方法
    websocket.onopen = function(){
        setMessageInnerHTML("连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }

    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
        websocket.close();
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //发送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
	
	//关闭连接
    function closeWebSocket() {
        websocket.close();
    }
</script>
</html>

回调函数:(Callback Function) 是一种 异步编程模式,通过将函数作为参数传递给其他代码,由特定事件触发执行。在 WebSocket 中,回调用于处理连接状态变化和消息

连接成功的回调:onopen
  • 触发时机:WebSocket 握手成功,连接建立后自动调用。

  • 典型用途:发送初始数据或更新 UI 状态(如显示"已连接")

接收消息的回调:onmessage
  • 触发时机:当客户端收到服务器发送的消息时。

  • 参数event.data 包含消息内容(文本、二进制等)

连接错误的回调:onerror
  • 触发时机:连接过程中发生错误(如网络中断、无效地址)。

连接关闭的回调:onclose

  • 触发时机:连接关闭后(无论主动关闭还是异常断开)。

客户端效果:当刷新页面时,会自动new一个 WebSocket对象,开启会话

②导入WebSocket的maven坐标

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

③导入WebSocket服务端组件WebSocketServer,用于和客户端通信

java 复制代码
package com.sky.WebSocketServer;

import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息  这个方法类似HTTP中的Controller
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

④导入配置类WebSocketConfiguration,注册WebSocket的服务端组件

java 复制代码
package com.sky.config;

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

/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

⑤导入定时任务类WebSocketTask,定时向客户端推送数据

java 复制代码
package com.sky.task;

import com.sky.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Component
public class WebSocketTask {
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 通过WebSocket每隔5秒向客户端发送消息
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void sendMessageToClient() {
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }
}

消息通信:
A[用户输入消息] --> B[点击发送按钮]
B --> C[调用 websocket.send()]
C --> D[服务器接收消息]
D --> E[服务器可能回复消息]
E --> F[触发 onmessage 回调]

复制代码
连接关闭:
A[用户点击关闭/窗口关闭] --> B[调用 websocket.close()]
B --> C[发送 Close 帧]
C --> D[服务器响应 Close 帧]
D --> E[触发 onclose 回调]

(三)苍穹外卖(实现向客户端推送消息:来单提醒)

设计:
• 通过 WebSocket 实现管理端页面和服务端保持长连接状态
• 当客户支付后,调用 WebSocket 的相关 API 实现服务端向客户端推送消息
• 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
• 约定服务端发送给客户端浏览器的数据格式为 JSON ,字段包括: type , orderId , content

  • type 为消息类型,1为来单提醒 2为客户催单

  • orderId 为订单id

  • content 为消息内容

//只有支付成功才会推送来单提醒

(1)在订单接口实现类中注入websocket

复制代码
@Autowired
private WebSocketServer webSocketServer;

(2)在支付成功方法中添加推送消息

java 复制代码
// 通过WebSocket向客户端浏览器发送消息 type orderId content
        Map map = new HashMap<>();
        map.put("type",1);// 1 来单提醒
        map.put("orderId",ordersDB.getId());
        map.put("content","订单号: " + outTradeNo);
     //需要转成JSON格式
        String jsonString = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(jsonString);

测试:

内网穿透:由于之前的测试都是在局域网中实现的,要给微信后台推送消息就需要通过内网穿透,获得一个临时域名(公网ip),通过该域名来回调函数

SpringBoot+SSM项目实战 苍穹外卖(08) 用户下单支付 内网穿透cpolar软件 绕开微信支付实现_支付内穿-CSDN博客

(四)客户催单

需求分析:用户点击催单,需要第一时间通知外卖商家,通知形式:

(1)语音播报

(2)弹出提示框

需求分析设计:
• 通过 WebSocket 实现管理端页面和服务端保持长连接状态
• 当用户点击催单按钮后,调用 WebSocket 的相关 API 实现服务端向客户端推送消息
• 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
• 约定服务端发送给客户端浏览器的数据格式为 JSON ,字段包括: type , orderId , content

  • type 为消息类型,1为来单提醒 2为客户催单

  • orderId 为订单id

  • content 为消息内容

java 复制代码
/*催单*/
    public void ReminderOrder(Long id) {
        Orders order=orderSubmitMapper.getById(id);
        if(order==null ){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
//向客户端推送催单消息(2,订单id,商户)
        Map info=new HashMap();
        info.put("type",2);//2.用户催单
        info.put("orderId",order.getId());
        info.put("content","订单号: " + order.getNumber());
        //需要转换为JSON格式
        String jsonString =JSON.toJSONString(info);
        //使用WebSocket进行消息推送
        webSocketServer.sendToAllClient(jsonString);
    }
}

分析,当微信小程序用户进行催单时,先发送一个请求到服务器的Controller中,通过WebSocket向客户端浏览器推送催单消息,此时,管理端的商家就能收到催单提醒

相关推荐
༺ཉི།星陈大海།ཉྀ༻CISSP7 分钟前
专网内网IP攻击防御:从应急响应到架构加固
网络·安全
William一直在路上7 小时前
KONG API Gateway中的核心概念
网络·gateway·kong
sakoba10 小时前
Docker学习其二(容器卷,Docker网络,Compose)
运维·网络·学习·docker·容器·基础
惜.己11 小时前
appium中urllib3.exceptions.LocationValueError: No host specified. 的错误解决办法
网络·appium
吉凶以情迁12 小时前
window服务相关问题探索 go语言服务开发探索调试
linux·服务器·开发语言·网络·golang
专注VB编程开发20年12 小时前
UDP受限广播地址255.255.255.255的通信机制详解
网络·udp·智能路由器
1892280486113 小时前
NX947NX955美光固态闪存NX962NX966
大数据·服务器·网络·人工智能·科技
Sadsvit14 小时前
Linux 进程管理与计划任务
linux·服务器·网络
一碗白开水一14 小时前
【模型细节】FPN经典网络模型 (Feature Pyramid Networks)详解及其变形优化
网络·人工智能·pytorch·深度学习·计算机视觉
什么都想学的阿超15 小时前
【网络与爬虫 38】Apify全栈指南:从0到1构建企业级自动化爬虫平台
网络·爬虫·自动化