使用WebSocket实现从后端向前端推送信息

目录

一. 写本文的初衷

二. 实例概述

三. 开始实践

        1. 引入依赖

        2. Websocket 相关配置

        3. 创建消息数量单例

        4.  创建操作枚举

        5.  主要服务类

                <1> sendMessage

                <2> broadcast

        6. 消息数量单例控制器

        7. 前端页面

                <1>页面结构

                <2>js部分

        8. 效果展示


一. 写本文的初衷

        学习如何使用 WebSocket 技术,了解Java全双端通信。通过实践下面这个实例,以便于更好的理解。(最后附上了本demo的gitee地址,有需要可以随时下载)

二. 实例概述

        使用单例模式+WebSocket向前端用户提示需要处理的消息数量。这里的单例模式用来存储消息的数量,将初始数量设置为10。这里的"+"号和"-"是一个抽象的概念,泛指用户在某数据上做的操作使得该数据增加或减少。

三. 开始实践

        1. 引入依赖
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/>
    </parent>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
    <dependencies>
        2. Websocket 相关配置
@Configuration
public class WebSocketConfig {
    
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}
        3. 创建消息数量单例
由于此单例需要频繁使用,所以创建为饿汉式单例。
public class CountSingle {

    private Integer count = 10;
    private final static CountSingle countSingle = new CountSingle();

    public static Integer getCount() {
        return getInstance().count;
    }

    public static synchronized void setCount(OperEnum operEnum) {
        if (operEnum == OperEnum.ADD) {
            getInstance().count++;
        }
        if (operEnum == OperEnum.SUB) {
            getInstance().count--;
        }
    }

    public static CountSingle getInstance() {
        return countSingle;
    }

}
        4.  创建操作枚举

        此枚举分别对应用户做的加或减操作 

public enum OperEnum {

    ADD(1), SUB(2);

    private final Integer code;

    OperEnum(int code) {
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }
}
        5.  主要服务类

        这里主要说两个重要的方法:

                <1> sendMessage

                向当前会话主体对象发送信息

                <2> broadcast

                向所有会话主体对象广播信息

@Component
@ServerEndpoint("/websocket")
public class WebSocketServer {

    private static final CopyOnWriteArraySet<WebSocketServer> connections = new CopyOnWriteArraySet<>();
    private Session session;

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        connections.add(this);
        this.sendMessage(String.valueOf(CountSingle.getCount()));
        System.out.println("新建连接: " + session.getId());
    }

    @OnClose
    public void onClose() {
        connections.remove(this);
        System.out.println("连接关闭: " + session.getId());
    }

    @OnError
    public void onError(Throwable error) {
        error.printStackTrace();
    }

    private void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void broadcast(String message) {
        for (WebSocketServer client : connections) {
            client.sendMessage(message);
        }
    }

}
        6. 消息数量单例控制器
@RestController
public class CountController {

    @GetMapping("add")
    public void add() {
        CountSingle.setCount(OperEnum.ADD);
        WebSocketServer.broadcast(String.valueOf(CountSingle.getCount()));
    }
    
    @GetMapping("sub")
    public void sub() {
        CountSingle.setCount(OperEnum.SUB);
        WebSocketServer.broadcast(String.valueOf(CountSingle.getCount()));
    }

}
        7. 前端页面
                <1>页面结构
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="/lib/jquery-3.4.1.min.js"></script>
    <script src="/lib/layui-v2.5.5/layui.js"></script>
    <link rel="stylesheet" href="/lib/layui-v2.5.5/css/layui.css">

    <style>
        div {
            text-align: center;
        }
    </style>

</head>
<body>
<div>
    <button class="layui-btn layui-btn-sm layui-btn-normal" onclick="add()">+</button>
    <button class="layui-btn layui-btn-sm layui-btn-warm" onclick="sub()">-</button>
    <button class="layui-btn">查看消息<span class="layui-badge layui-bg-gray" id="count"></span></button>
</div>
                <2>js部分
    let socket = new WebSocket("ws://localhost:8080/websocket");

    socket.onmessage = function (event) {
        $("#count").text(event.data);
    };

    function add() {
        $.ajax({
            url: '/add', // 请求的 URL
            type: 'GET', // 请求方法:GET、POST 等
            dataType: 'json', // 预期服务器返回的数据类型
        });
    }

    function sub() {
        $.ajax({
            url: '/sub', // 请求的 URL
            type: 'GET', // 请求方法:GET、POST 等
            dataType: 'json', // 预期服务器返回的数据类型
        });
    }
        8. 效果展示

        这里需要使用两个浏览器才能看到效果。 

websocket测试

项目gitee地址:WebsocketTest: 本系统做一个简单的应用,使用单例模式+WebSocket向前端提示需要处理的消息数量。

以下是一个基于 Spring Boot、WebSocket 和 Vue 实现后端前端实时推送数据的代码示例: 1. 后端代码 ``` @Controller public class WebSocketController { private final WebSocketService webSocketService; @Autowired public WebSocketController(WebSocketService webSocketService) { this.webSocketService = webSocketService; } @GetMapping("/") public String index() { return "index"; } @MessageMapping("/send") public void send(String message) { webSocketService.sendAll(message); } @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } ``` ``` @Service public class WebSocketService { private final List<Session> sessions = new CopyOnWriteArrayList<>(); public void add(Session session) { sessions.add(session); } public void remove(Session session) { sessions.remove(session); } public void sendAll(String message) { sessions.forEach(session -> { try { session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } }); } } ``` 2. 前端代码 ``` <template> <div> <h1>Real-time data:</h1> <ul> <li v-for="(data, index) in dataList" :key="index">{{ data }}</li> </ul> <input type="text" v-model="message" /> <button @click="send">Send</button> </div> </template> <script> export default { data() { return { dataList: [], message: '' } }, mounted() { const ws = new WebSocket('ws://localhost:8080/ws'); ws.onmessage = (event) => { this.dataList.push(event.data); }; ws.onclose = () => { console.log('Connection closed'); }; }, methods: { send() { const ws = new WebSocket('ws://localhost:8080/ws'); ws.onopen = () => { ws.send(this.message); ws.close(); }; } } } </script> ``` 在这个示例中,我们首先创建了一个 WebSocket 服务端,其中包含了一个用于处理客户端发送的消息的方法 send(),它会将接收到的消息发送给所有连接上的客户端。我们还创建了一个 WebSocketService,用于管理客户端连接和消息发送。 在前端,我们通过 Vue 的 mounted 生命周期创建了一个 WebSocket 连接,并在每次接收到服务器发来的消息时将其添加到一个数据列表中,然后在模板中通过 v-for 渲染出来。我们还在模板中添加了一个文本框和一个按钮,用于向服务器发送消息。当用户点击按钮时,我们创建一个新的 WebSocket 连接,并在连接打开后发送用户输入的消息,然后立即关闭连接。 要注意的是,我们在前端中创建了两个 WebSocket 连接,一个用于接收服务器推送的数据,另一个用于向服务器发送数据。这是因为 WebSocket 是全双工通信,可以同时进行发送和接收操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值