美文网首页websoket
越写悦快乐之Vue项目如何集成WebSocket

越写悦快乐之Vue项目如何集成WebSocket

作者: 韬声依旧在路上 | 来源:发表于2020-09-13 16:20 被阅读0次
    SockJS - 图片来自我的手机

    作为一名有追求的码农来说,不管是前端、后端、抑或是测试、运维,都需要保持一定的好奇心才可以,那么大家都知道Vue作为前端框架的集大成者,拥有着易用、灵活和高效的优点,那么对于在Vue项目中集成WebSocket,大家有没有实践过呢?今天我为大家分享一下如何在Vue项目中集成WebSocket。

    开发环境

    • Window 10.0.17763
    • Node 10.18.0
    • Visual Studio Code 1.48.2
    • Vue 2.6.12

    特别说明

    本项目使用SockJS-ClientSTOMP.js来支持WebSocket后端(Node.js、Java等),在支持WebSocket的浏览器中可以直接进行连接、消息收发和端口等操作(详细内容请参考相关文档)。

    接入步骤

    添加依赖

    我们在项目的入库页面(index.html)中通过CDN的方式引入SockJS-ClientSTOMP.js,文件内容如下。

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="renderer" content="webkit" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
        />
        <title>信息管理系统</title>
      </head>
      <body>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.0/sockjs.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
        <div id="app"></div>
      </body>
    </html>
    

    在Vue文件中连接和关闭WebSocket

    既然我们在项目的入口页面中引入了WebSocket相关库,那么挂载在app下的Vue组件均可以使用STOMPSockJS,此时我们在Vue的生命周期函数mounted、和beforeDestroy中分别调用WebSocket的初始化和销毁函数,在data中声明WebSocket连接的HostTopic等相关变量,下面给出Vue文件的内容如下。

    <template>
    <div class="app-container">
        <el-row>
            <el-col>
                <search @getTableData="getTableData" @deleteSelected="remove"></search>
            </el-col>
        </el-row>
        <el-row>
            <el-col>
                <Table @search="search" :data="gridData" :table="table" :pageParams="pageParams" :pageSizes="[10, 20, 50]" @getSelected="getSelected"></Table>
            </el-col>
            <el-button @click="sendMessage">发送消息</el-button>
        </el-row>
    </div>
    </template>
    
    <script>
    import {
        list,
        save
    } from "@/api/dashboard/enterprise/myMessage";
    
    import Table from "@/components/table";
    
    import to from "@/to";
    
    import {
        getToken
    } from "@/utils/auth";
    
    import search from "./search";
    
    import {
        mapState,
        mapActions
    } from "vuex";
    
    const moment = require("moment");
    
    export default {
        name: "MesageList",
        components: {
            Table,
            search
        },
        data: function () {
            return {
                table: {
                    // 行定义
                    columns: [{
                            prop: "content",
                            label: "消息内容",
                            width: ""
                        },
                        {
                            prop: "sender",
                            label: "发送者",
                            width: ""
                        },
                        {
                            prop: "typeName",
                            label: "消息类型",
                            width: ""
                        }
                    ],
                    total: 0
                },
                wsHost: "http://localhost:8080/websocket",
                wsTopic: "/topic/greeting",
                websocket: null,
                stompClient: null,
                isConnected: false,
                message: {},
                messages: [],
                headers: {
                    Authorization: getToken()
                }
            };
        },
        computed: {
            ...mapState("dashboard/message/index", [
                "editDialogVisible",
                "editDialogTitle",
                "gridData",
                "pageParams",
                "checkboxSelected",
                "params",
                "total",
                "form"
            ])
        },
        mounted() {
            this._initSockJs();
        },
        beforeDestroy() {
            this._destroySockJs();
        },
        methods: {
            ...mapActions("dashboard/message/index", ["setStateData"]),
            // 操作回调
            action(obj) {
                if (obj.methods === "delete") {
                    this.setStateData({
                        checkboxSelected: [obj.row]
                    });
                    this.remove();
                }
            },
            // 删除
            remove() {
                if (this.checkboxSelected && this.checkboxSelected.length > 0) {
                    this.$confirm("此操作将永久删除, 是否继续?", "提示", {
                            confirmButtonText: "确定",
                            cancelButtonText: "取消",
                            type: "warning"
                        })
                        .then(async () => {
                            let [err, res] = await to(deleteByIds(this.checkboxSelected));
                            if (err) {
                                throw new Error(err.message);
                            }
                            this.$message({
                                type: "success",
                                message: "删除成功"
                            });
                            this.getTableData();
                        })
                        .catch(() => {
                            this.$message({
                                type: "info",
                                message: "已取消删除"
                            });
                        });
                }
            },
            // 查询
            search(pageParams) {
                this.setStateData({
                    pageParams: pageParams
                });
                this.getTableData();
            },
            // 选中回调
            getSelected(multipleSelection) {
                this.setStateData({
                    checkboxSelected: multipleSelection
                });
            },
            // 获取数据
            async getTableData() {
                let response = await list(this.params, this.pageParams);
                let gridData = response.data.list;
                let total = response.data.total;
                this.setStateData({
                    gridData: gridData
                });
                this.table.total = total;
            },
            _initSockJs() {
                this.getTableData();
                this.socket = new SockJS(this.wsHost);
                this.stompClient = Stomp.over(this.socket);
                // 订阅
                this.stompClient.connect(this.headers, frame => {
                    console.log("WebSocket连接成功", frame);
                    this.isConnected = true;
                    // 广播
                    this.stompClient.subscribe(this.wsTopic, response => {
                        console.log("/websocket/message", JSON.parse(response.body));
                        this.messages.push(JSON.parse(response.body));
                        this.setStateData({
                            gridData: this.messages
                        });
                    });
                    // 一对一
                    this.stompClient.subscribe("/user/topic/greeting", response => {
                        console.log(
                            "/user/topic/greeting/message",
                            JSON.parse(response.body)
                        );
                        this.messages.push(JSON.parse(response.body));
                        this.setStateData({
                            gridData: this.messages
                        });
                    });
                    // 广播
                    this.stompClient.subscribe("/topic/greeting", response => {
                        console.log("/topic/greeting/message", JSON.parse(response.body));
                        this.messages.push(JSON.parse(response.body));
                        this.setStateData({
                            gridData: this.messages
                        });
                    });
                });
            },
            _destroySockJs() {
                if (this.stompClient != null) {
                    this.stompClient.disconnect();
                    this.socket.onclose;
                    this.socket.close();
                    this.stompClient = {};
                    this.socket = {};
                    this.isConnected = false;
                }
                console.log("WebSocket断开成功");
            },
            async sendMessage() {
                this.message = {
                    sender: this.$store.getters.introduction,
                    type: "3",
                    content: "消息内容",
                    receiver: "*",
                    sendingDate: moment(new Date()).format("YYYY-MM-DD HH:mm:ss")
                };
    
                let [err, res] = await to(save(this.message));
                if (err) {
                    throw new Error(err.message);
                }
    
                this.stompClient.send(this.wsTopic, {}, JSON.stringify(this.message));
    
                this.$message({
                    showClose: true,
                    message: "消息发送成功",
                    type: "success"
                });
            }
        }
    };
    </script>
    

    sendMessage函数用于测试消息发送,发送完消息后持久化消息并通过订阅的Topic即时收取消息,收到消息后保存到表格中。

    getToken函数是为了获取登录认证后保存的个人信息。

    验证连接结果

    我们启动前后端的项目,然后定位到该页面,打开开发者工具并切换到控制台,控制台会显示以下信息。

    控制台结果 - 图片来自我的手机

    通过以上的截图我们可以得知WebSocket连接的后端地址,心跳检测的输出和stompClient的认证字段,那么急于此我们可以构建不同的应用场景,比如聊天、消息收发、任务提醒等功能,再配合其他功能来满足客户的诉求,我相信WebSocket的接入会让你的应用更好用。

    个人收获及感想

    我们的文章今天为大家介绍了Vue项目中接入WebSocket的方法,通过连接、收发消息和断开等方法来接入WebSocket后端,接入之后就可以愉快地集成其他的业务啦。而在现在的复杂多变的产品迭代周期中,WebSocket不可或缺,并且会不断发展和变化,相信过不了多久,我们的产品也会慢慢完善,并趋于完美。让我们一起持续打造能满足客户诉求的好产品,持续为客户做好服务,成为更好的团队和更好的自己。

    相关文章

      网友评论

        本文标题:越写悦快乐之Vue项目如何集成WebSocket

        本文链接:https://www.haomeiwen.com/subject/vpanektx.html