我开发的客服系统后端是使用的Golang语言,Go是Google公司开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go 天生支持并发。好处太多就不多说了。
全源码客服系统用户,想要针对自己的业务,进行二次开发,那么就需要了解一下我们客服系统的开发逻辑,从而进行定制化的功能开发。
系统架构:Golang Gin框架 + MySQL + 前端 ElementUI
编译版只能修改前端,全源码用户才需要了解golang本身开发。
项目没有使用任何高级的设计模式,难懂的绕圈的设计模式。最基本的结构,后端接口就是:定义路由,控制器里处理逻辑调用数据库的model层。前端页面就是,定义路由,控制器里渲染页面。有经验的开发者半天绝对能知道如何去修改。
-
技术栈
-
前端技术
- 语言/框架:Vue.js 2 + ElementUI
-
特点:
- Vue.js 2
- ElementUI
- CDN 引入:无需前端构建工具(如 Webpack),直接通过
<script>
标签引入,适合轻量级部署。
-
优势:
- 灵活修改:前端代码未编译,可直接编辑 HTML/JS/CSS,适合定制化需求。
- 多端适配:响应式设计,兼容 PC、移动端、小程序、公众号等场景。
-
后端技术
- 语言/框架:
Golang
+Gin
+GORM
-
特点:
- Golang:编译型语言,高性能、高并发,适合处理客服系统的实时消息。
- Gin:轻量级 Web 框架,路由高效,中间件支持完善。
- GORM:ORM 库,简化 MySQL 数据库操作,支持链式调用。
-
优势:
- 编译部署:代码编译为二进制文件,无需安装 Go 环境。
- 性能强劲:Golang 的协程(Goroutine)轻松支持高并发客服会话。
- 低依赖:相比 PHP/Java,无需配置运行时环境(如 JVM、PHP-FPM)。
-
数据库
- 主数据库:
MySQL
-
运维与部署
-
Web 服务:
Nginx
- 反向代理、负载均衡、静态资源托管。
-
私有化部署:
- 支持自有域名 + 自有服务器,数据完全自主掌控。
-
对比 PHP/Java:
- PHP:需安装 PHP 运行时、Composer 依赖。
- Java:需配置 JVM、Tomcat/Jar 包环境。
- Golang:只需一个二进制文件 + 配置文件,开箱即用。
-
前后端混合渲染模式
设置静态文件目录
服务端渲染(SSR)页面,由后端gin将页面加载出来,页面中的主要逻辑都是调用后端的API接口
利用gin下面的函数,设置静态文件服务,将static目录作为静态文件目录
engine.Static("/static", "./static")
使用gin的加载HTML模板方法,将static/templates/下的页面模板文件加载进来
engine.LoadHTMLGlob("static/templates/*")
一般情况下,你在浏览器上访问的网址,想找到对应的模板文件,就根据网址去static/templates/ 下找对应名称的html文件。在渲染和加载模板文件时,我一般都是对应的进行加载的。
Golang Gin如何展示一个静态页面
这里举一个具体的golang gin展示一个静态页面的例子
在router/view.go文件下增加页面路由入口
//收集表单demo
engine.GET("/collect_form", func(c *gin.Context) {c.HTML(http.StatusOK, "form.html", gin.H{})
})
在static/templates/default/下创建form.html
这样访问 网址/collect_form ,就能正确访问到这个静态页面了
-
前端二开需求
想要修改前端界面,删除某些功能,或修改某些文字,可以查看下面介绍
我们的前端是传统的开发模式,不是node编译后部署形式,前端没有独立的项目
所有展示的页面地址,都是后端的地址,后端把前端html模板页渲染出来展示
-
渲染前端页面的原理
Gin框架引入并渲染前端页面后,前端页面就是传统的开发模式了,可以引入js写样式等
Golang Gin框架展示一个静态页面,是在路由处理中加载模板页面。在./router/view.go中是所有与前端页面展示有关的逻辑。
如果访问地址是 /douyin.html ,那么路由处理类似下面。页面模板地址位于 ./static/templates/下
//前台页面
engine.GET("/douyin.html", func(c *gin.Context) {c.HTML(http.StatusOK, "douyin.html", gin.H{})
})
-
修改访客聊天页
前端页面地址位于 ./static/templates/default/chat_page.html
想要删除或隐藏某些工具栏上的按钮,可以直接在页面里找到元素位置,直接删除掉。
如果找不到元素的位置,可以直接在模板文件中搜索页面中不可变的字符串,比如下面的class属性,不可动态引入的
寻找其他元素位置,可以同理直接在 ./static/templates/下全局搜索
-
后端接口二开需求
先审查元素,查看网络请求的接口地址,然后查找Gin的路由定义函数
当前项目的./router/api.go ,里面定义的就是所有接口的路由入口了
路由入口举例
就是/kefu/kefuinfo 这个get请求接口的入口定义,使用goland等IDE,直接点击后面的控制器函数,就能进入控制器代码,查看具体的处理逻辑
kefuGroup := engine.Group("/kefu")
kefuGroup.Use(middleware.JwtApiMiddleware, middleware.KefuIpblack, middleware.SetLanguage)
{//获取客服信息kefuGroup.GET("/kefuinfo", controller.GetKefuInfo)
控制器部分代码举例
非常简单的逻辑,处理一下,就去调用model里面的操作数据库
func GetKefuInfo(c *gin.Context) {kefuId, _ := c.Get("kefu_id")entIdStr, _ := c.Get("ent_id")user := models.User{ID: uint(kefuId.(float64))}result := user.GetOneUser("*")if result.ID == 0 {c.JSON(200, gin.H{"code": 400,"msg": "客服不存在",})return}if result.Status == 1 {c.JSON(200, gin.H{"code": types.ApiCode.ACCOUNT_FORBIDDEN,"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_FORBIDDEN),})return}result.Password = ""result.EntId = entIdStr.(string)c.JSON(200, gin.H{"code": 200,"msg": "ok","result": result,})
}
数据库层代码举例
例如models/users.go ,就是所有增删查改了
func UpdateUser(id string, name string, password string, avator string, nickname, email, tel string, agentNum uint) {user := &User{Name: name,Avator: avator,Nickname: nickname,AgentNum: agentNum,Email: email,Tel: tel,}user.UpdatedAt = time.Now()if password != "" {user.Password = password}DB.Model(&User{}).Where("id = ?", id).Update(user)
}