beego搭建websocket服务 go语言安装websocket
go get github.com/gorilla/websocket
beego中代码使用

以下代码是controller核心部分代码,router等代码则不展示。

package controllers
import (
    "fmt"
    "github.com/astaxie/beego"
    "net/http"
    "github.com/gorilla/websocket"
)

type MySocketController struct {
    beego.Controller
}

// 定义数据结构{"表格id1": {客户端浏览器id: true}, "表格id2": {客户端浏览器id: true}}
var tableClinets = make(map[string]map[*websocket.Conn]bool)

func (c *MySocketController) Get() {
    ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
    if err != nil{
        beego.Info(err)
    }
    defer ws.CloseHandler()
    
	// 这里是我用户的结构体,你可以按自己需要定义
    var msg models.RecvWs
    
    for {
        err := ws.ReadJSON(&msg)
        if err != nil {
            beego.Info("页面可能断开啦")
            for k,v := range tableClinets{
                if _,ok := v[ws];ok{
                    delete(v, ws)
                    if len(v) == 0{
                        delete(tableClinets,k)
                    }
                    fmt.Println(tableClinets)
                }
            }
            break
        }
     
        // 获取表格ID,判断是否存在数据结构中,不存在插入。
        tableId := msg.TableUuid
        if sockets, ok := tableClinets[tableId]; ok{
            if _, ok := sockets[ws]; !ok{
                sockets[ws] = true
            }
        }else{
			client_map := map[*websocket.Conn]bool{ws: true}
            tableClinets[tableId] = client_map
        }

        // 将获取的消息按表格ID广播出去
        clients := tableClinets[tableId]
        go func(msg models.RecvWs){
            // 开启协程去做一些操作,例如可以实时去修改库里的内容
        }(msg)
        
        // 将消息广播的同时要把自己的客户端除去,自己不能给自己广播。
		for client := range clients{
            if client != ws{
                err = client.WriteJSON(msg)
                if err != nil {
                    client.Close()
                    delete(clients, client)
                    if len(clients) == 0{
                        delete(tableClinets,msg.TableUuid)
                    }
                }
            }
        }
    }
}

前端代码

注意temp是用来存放后端第一次返回来的数据,在jexcel监测到表格有变化时一定要先去temp去看看有没有,没有则向后端发送。不然会造成后端向前端推数据时,前端表格发生变化,执行了onchange,又向后端发送,后端又广播出去,一个死循环。具体把控可根据业务来。

var temp = {} 	
var ws = new WebSocket('ws://ip地址:8080/ws');
ws.onopen = function(){
    // 第一个建立连接时向后端发送一个数据,让后端保存好socket,和文档的uuid
    var data = {
        "file_id": file_id,
        "first_status": "true"
    }
    req_data = JSON.stringify(data);
    ws.send(req_data)
    
	// 初始化表格
    $("#mytable").jexcel({
        data: table_size,
        defaultColWidth: res.table_width,
        tableOverflow: true,
        onchange: change_data,
    });
};

// 定义发送数据的函数, 表格ID和别的信息
var change_data = function(instance, cell, x, y, value){
    var data = {
        "file_id": file_id,	
    }
    
    // 尝试从temp_data字典中获取该单元格的数据, 并判断数据的来源
    if(temp_data.hasOwnProperty(cellName)){
        if(temp_data[cellName]==value){
            delete temp_data[cellName];
            return
        }
        delete temp_data[cellName];
    }

    req_data = JSON.stringify(data);
    ws.send(req_data)
}

// 用来接收后端广播的消息,并渲染到表格上
ws.onmessage = function (res) {
    var received_msg = res.data;
    var obj = JSON.parse(received_msg);
    var cellName = obj["update_name"]
    var value = obj["update_value"]
    
    // 改变单元格的内容
    $("#mytable").jexcel('setValue', cellName, value)
};

示例

以下为企业微信(腾讯定制-安信)小程序开发单个页面。
在这里插入图片描述