商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > gin使用websocket实现数据实时推送

gin使用websocket实现数据实时推送

  发布于2026-07-06 阅读(0)

扫一扫,手机访问

业务场景

给自己的项目加几个 ECharts 图表,用来展示几个系统近一周的访问量。效果差不多是这样:

gin使用websocket实现数据实时推送

三个图表分别对应:简历访问量、音乐访问量、以及两者的对比

1. 数据采集

访问信息的采集入口很简单——在简历页面和音乐页面埋了一个提交接口,每次用户访问就上报页面类型和访问时间。不需要什么花哨的东西,一个接口搞定。

2. 数据整理

后端需要把近一周每天的数据按天汇总,然后返回给前端。来看一下音乐页面访问量的处理函数(简历页面同理):

// 获取我的音乐本周访问量
func (this Personal) GetMusicData(ctx *gin.Context) {
	now := time.Now()
	year, month, day := now.Date()
	today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
	t1 := today.AddDate(0, 0, -1)
	t2 := today.AddDate(0, 0, -2)
	t3 := today.AddDate(0, 0, -3)
	t4 := today.AddDate(0, 0, -4)
	t5 := today.AddDate(0, 0, -5)
	t6 := today.AddDate(0, 0, -6)
	tourist1 := []modules.Tourist{}
	tourist2 := []modules.Tourist{}
	tourist3 := []modules.Tourist{}
	tourist4 := []modules.Tourist{}
	tourist5 := []modules.Tourist{}
	tourist6 := []modules.Tourist{}
	tourist7 := []modules.Tourist{}

	err := modules.DB.Where("scene LIKE ? AND add_time > ?", "%music%", today).Find(&tourist1).Error
	err2 := modules.DB.Where("scene LIKE ? AND add_time > ? AND add_time < ?", "%music%", t1, today).Find(&tourist2).Error
	err3 := modules.DB.Where("scene LIKE ? AND add_time > ? AND add_time < ?", "%music%", t2, t1).Find(&tourist3).Error
	err4 := modules.DB.Where("scene LIKE ? AND add_time > ? AND add_time < ?", "%music%", t3, t2).Find(&tourist4).Error
	err5 := modules.DB.Where("scene LIKE ? AND add_time > ? AND add_time < ?", "%music%", t4, t3).Find(&tourist4).Error
	err6 := modules.DB.Where("scene LIKE ? AND add_time > ? AND add_time < ?", "%music%", t5, t4).Find(&tourist4).Error
	err7 := modules.DB.Where("scene LIKE ? AND add_time > ? AND add_time < ?", "%music%", t6, t5).Find(&tourist4).Error
	if err != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil || err7 != nil {
		ctx.JSON(400, gin.H{
			"message": "获取失败",
		})
	} else {
		arr := []int{len(tourist7), len(tourist6), len(tourist5), len(tourist4), len(tourist3), len(tourist2), len(tourist1)}
		ctx.JSON(200, gin.H{
			"message": "获取成功",
			"data":    arr,
		})
	}
}

逻辑挺直白的:从今天往前推7天,每天分别查数据库里 scene 包含 "music" 的记录,最后按时间顺序打包成一个数组返回。

3. 前端绑定数据到 ECharts

... ... 前端那部分没什么好展开的,无非是把拿到的数据塞进 ECharts 的 series 里,这里省略若干行。

4. 重点:用 WebSocket 实现实时推送

访问量变化了,怎么能让页面自动刷新?老老实实让用户手动刷新肯定不现实,所以得靠 WebSocket 在服务端和客户端之间保持一条长链接。

后端部分

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}
// 这里声明一个链接池
var conns []*websocket.Conn

func (this UserController) WS(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		println("upgrade错误:", err)
		return
	}
	defer c.Close()
	// 把所有链接存在链接池里
	conns = append(conns, c)
	for {
		_, _, err := c.ReadMessage()
		if err != nil {
			println("read:", err)
			break
		}
	}
}

关键点:在数据采集的接口里,一旦收到新的访问记录,就遍历链接池,广播一个消息——告诉所有在线的客户端“数据变了,快去拉”。

func (this UserController) AddTourist(ctx *gin.Context) {
	scene := ctx.Request.FormValue("scene")
	message := ctx.Request.FormValue("message")
	time := time.Now().UTC()
	tourist := &modules.Tourist{
		Scene:   scene,
		Message: message,
		AddTime: time,
	}
	err := modules.DB.Model(&modules.Tourist{}).Create(&tourist).Error
	if err != nil {
		ctx.JSON(400, gin.H{
			"message": "新增浏览用户信息失败",
		})
	} else {
		// 循环链接池,广播消息,消息类型随便定,前端认得就行
		for i := range conns {
			if index := strings.Index(scene, "jianli"); index != -1 {
				conns[i].WriteMessage(websocket.TextMessage, []byte("jianli"))
			} else if index := strings.Index(scene, "music"); index != -1 {
				conns[i].WriteMessage(websocket.TextMessage, []byte("music"))
			}
		}
		ctx.JSON(200, gin.H{
			"message": "新增浏览用户信息成功!",
		})
	}
}

管理端收到推送后,重新刷新对应的图表数据——这样就实现了访问量实时变化的效果。

const websocket=new WebSocket("ws://xxx.xxx.xxx.xxx:8088/ws")
websocket.onopen=(evt)=>{
  console.log("链接成功")
}
websocket.onmessage=(evt)=>{
// 收到后端推送的消息,刷新对应数据
  if(evt.data=="jianli"){
    refreshChartJL()
  }else if(evt.data=="music"){
    refreshChartMusic()
  }
}
websocket.onclose=()=>{
  console.log("链接关闭")
}
const getAllData=()=>{
    ...
    ...
    ...
}

总结

整个实现下来其实并不复杂,核心就是 WebSocket 链路维护 + 数据采集时的广播通知。但别光看,动手写一遍才能真正吃透。如果你在实现过程中遇到什么问题,欢迎留言交流。

本文转载于:https://www.jb51.net/jiaoben/363569ga6.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注