WebSocket 来单提醒和客户催单功能

一:WebSocket :

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

HTTP协议和WebSocket协议对比:

  • HTTP是短连接 WebSocket是长连接
  • HTTP通信是单向的,基于请求响应模式
  • WebSocket支持双向通信
  • HTTP和WebSocket底层都是TCP连接

应用场景:

  • 视频弹幕
  • 网页聊天
  • 体育实况更新
  • 股票基金报价实时更新

二: WebSocket的使用步骤(入门小程序):

  • 1:先准备一个html页面
  • websocket是一个客户端和服务端前后交互的页面,所以要编写入门小程序肯定要有一个前端。
  • 2:导入maven坐标
  • 3:编写WebSocketServer类
  • 这有点像我们处理http请求时候编写的Controll类
  • 4:导入配置类WebSocketConfiguration,注册WebSocket的服务端组件
  • 5:导入定时任务类WebSocketTask,定时向客户端推送数据(这是一个测试方法)

前端页面代码:

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);

    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
    }
    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>

WebSocketServer类:

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

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 客户端发送过来的消息
     */
    @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();
            }
        }
    }

}

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

这个类和websocket技术没什么关系,只是用来测试。

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()));
    }
}

结果展示:

客户端:
服务端:

WebSocket缺点:

  • 服务器长期维护长连接需要一定的成本
  • 各个浏览器支持程度不一
  • WebSocket 是长连接,受网络限制比较大,需要处理好重连

三:来单提醒实现:

需求分析:

用户下单并且支付成功后,需要第一时间通知外卖商家。通知的形式有如下两种:

  1. 语音播报
  2. 弹出提示框

设计:

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

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

orderId 为订单id

content 为消息内容

最后一步:服务端发送给客户端浏览器的数据这一步的发送的东西其实是依照这个业务来制定的。

具体代码实现:

在OrderServiceImpl中先自动导入WebSocketServer

在serviceOrderServiceImpl的payment方法中写入如下代码:

java 复制代码
        //用户支付成功之后,通过websocket给客户端浏览器
        //封装数据
        Map map = new HashMap();
        map.put("type",1);
        map.put("orderId",this.orders.getId());
        map.put("content","订单号"+this.orders.getNumber());
        //将map数据转成json
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);

视频中教的是在paySuccess中写这段代码

不过我们因为支付功能的不能使用,默认都是直接支付成功,这样就跳过了在paySuccess中更改订单状态的步骤,我们直接在payment方法中做,

所以我们的来单提醒的操作也需要放在payment方法中。

最后还有一个点就是这个语音播报我一开始播不出来,这个不是代码的问题,是我的浏览器设置阻止了语音

这里直接改成允许就行

还有一个需要把WebSocketTask这个类中的每五秒播报一次注释掉。

四:客户催单:

需求分析:

用户在小程序中点击催单按钮后,需要第一时间通知外卖商家。

通知的形式有如下两种:

  • 语音播报
  • 弹出提示框

设计:

这里的设计其实和上面的来单提醒功能很相似

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

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

orderId 为订单id

content 为消息内容

接口设计:

具体代码实现:

Controll层:
java 复制代码
    /**
     * 用户催单
     * @param orderId
     * @return
     */
    @GetMapping("/reminder/{id}")
    @ApiOperation("用户催单")
    public Result reminder(@PathVariable("id") Long orderId){
        orderService.reminder(orderId);
        return Result.success();
    }
Service层:
java 复制代码
/**
     * 用户催单
     * @param orderId
     * @return
     */
    @Override
    public void reminder(Long orderId) {
        //根据订单id查询订单
        Orders ordersDB = orderMapper.getByNumber(String.valueOf(orderId));
        if(ordersDB == null){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        //用户支付成功之后,通过websocket给客户端浏览器
        //封装数据
        Map map = new HashMap();
        map.put("type",1);
        map.put("orderId",this.orders.getId());
        map.put("content","订单号"+this.orders.getNumber());
        //将map数据转成json
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }

整体的思路就和刚刚的来单提醒差不多。

相关推荐
red watchma2 分钟前
Xshell->MCU Ymodem协议实现
网络·单片机·嵌入式硬件
sky北城18 分钟前
读书笔记整理--网络学习与概念整合
网络·智能路由器
极客范儿20 分钟前
新华三H3CNE网络工程师认证—OSPF多区域概念与配置
网络·智能路由器
望获linux1 小时前
【实时Linux实战系列】FPGA 与实时 Linux 的协同设计
大数据·linux·服务器·网络·数据库·fpga开发·操作系统
国科安芯1 小时前
高辐射环境下AS32S601ZIT2型MCU的抗辐照性能与应用潜力分析
网络·人工智能·单片机·嵌入式硬件·fpga开发
wang09071 小时前
网络协议之DNS
网络·网络协议
wanhengidc1 小时前
云手机的魅力与优势
网络·游戏·智能手机·架构·云计算
Hello.Reader10 小时前
Flink 受管状态的自定义序列化原理、实践与可演进设计
java·网络·flink
极客先躯13 小时前
高可用巡检脚本实战:一键掌握服务、网络、VIP、资源状态
运维·网络·金融
时空潮汐13 小时前
无需公网 IP:神卓 K900 实现海康摄像头异地观看的两种简单方法
服务器·网络·tcp/ip·海康摄像头·神卓n600·神卓云监控