21 KiB
21 KiB
Ciyon 后台管理系统开发框架 - 后端开发指南
框架概述
Ciyon 是一个基于 Golang 开发的轻量级、高性能的后台管理系统开发框架,提供完整的用户权限管理、数据操作、文件上传、日志记录等功能。
核心特点:
- 轻量级:核心库代码精简,依赖少
- 高性能:原生 Golang 编写,充分利用 Go 协程优势
- 易扩展:模块化设计,组件可独立使用
- RESTful API 设计:支持多种前端框架对接
- 完整权限体系:基于角色的权限控制(RBAC)
- 多租户支持:支持 SaaS 模式部署
技术栈:
- 后端:Go 1.22+、MySQL
- 存储:本地存储 + S3 云存储(腾讯云、阿里云、Cloudflare R2)
项目结构
golang/
├── main.go # 程序入口
├── route_adm.go # 路由配置
├── go.mod # Go 模块配置
├── go.sum # 依赖版本锁定
├── gobuild.bat # Windows 编译脚本
├── web.ini # 配置文件
├── zciyon/ # 核心库
│ ├── web.go # Web 服务器
│ ├── mysql.go # MySQL 数据库
│ ├── sql.go # SQL 构建器
│ ├── db.go # 数据库接口
│ ├── upload.go # 文件上传
│ ├── redis.go # Redis 接口
│ ├── log.go # 日志系统
│ ├── excel.go # Excel 导出
│ ├── ws.go # WebSocket
│ ├── sse.go # Server-Sent Events
│ ├── i18n.go # 国际化
│ ├── c.go # 通用工具函数
│ ├── http.go # HTTP 客户端
│ ├── json.go # JSON 处理
│ ├── ini.go # 配置文件解析
│ ├── memkv.go # 内存 KV 存储
│ ├── mqtt.go # MQTT 客户端
│ ├── post.go # POST 数据处理
│ ├── tcpclient.go # TCP 客户端
│ ├── tcpserver.go # TCP 服务器
│ ├── udpclient.go # UDP 客户端
│ ├── udpserver.go # UDP 服务器
│ ├── grpc.go # gRPC 服务
│ ├── sys_linux.go # Linux 系统调用
│ └── sys_win.go # Windows 系统调用
├── web/ # Web 资源(静态文件)
│ ├── admin/ # 管理后台页面
│ └── jscss/ # 前端库
└── test/ # 测试文件
核心架构
1. 请求处理流程
客户端请求
↓
Nginx (可选,反向代理)
↓
Ciyon Web Server
↓
路由解析 (/admin/xxx.action)
↓
业务处理函数 (execFunc)
↓ (失败)
Mock 数据 (execMock)
↓ (失败)
转发到 PHP 接口 (execPHP)
↓ (失败)
返回错误 JSON
详细说明:
- 路由解析:根据 URL 路径解析出对应的业务函数
- 业务处理函数:优先执行 Golang 业务函数
- 成功:返回 JSON 响应
- 失败:继续下一步
- Mock 数据:如果业务函数不存在,尝试从 Mock 数据返回
- 成功:返回 Mock 数据
- 失败:继续下一步
- 转发到 PHP 接口:如果 Mock 也不存在,转发请求到 PHP 接口
- 成功:返回 PHP 接口的响应
- 失败(未找到函数):返回 "未找到业务函数" 错误
- 返回错误:所有尝试都失败,返回错误信息
2. 模块化设计
zciyon 核心库模块
| 模块 | 文件 | 功能描述 |
|---|---|---|
| Web 服务器 | web.go | HTTP 服务器、路由、静态文件服务 |
| 数据库 | mysql.go | MySQL 连接池、增删改查操作 |
| SQL 构建器 | sql.go | 链式 SQL 构建器 |
| 数据库接口 | db.go | 数据库操作抽象接口 |
| 文件上传 | upload.go | 本地文件上传处理 |
| Redis | redis.go | Redis 客户端接口 |
| 日志 | log.go | 文件日志、TCP 日志 |
| Excel | excel.go | Excel 导出功能 |
| WebSocket | ws.go | WebSocket 服务器 |
| SSE | sse.go | Server-Sent Events |
| 国际化 | i18n.go | 多语言支持 |
| HTTP 客户端 | http.go | HTTP 请求客户端 |
| JSON 处理 | json.go | JSON 编解码 |
| 配置文件 | ini.go | INI 配置文件解析 |
| 内存 KV | memkv.go | 内存键值存储 |
| MQTT | mqtt.go | MQTT 协议支持 |
| gRPC | grpc.go | gRPC 服务支持 |
| TCP/UDP | tcp*.go, udp*.go | TCP/UDP 网络通信 |
快速开始
1. 环境准备
配置文件 (web.ini)
[db]
host=127.0.0.1
port=3306
user=root
pass=your_password
name=your_database
maxopenconn=0
maxidelconn=0
maxlifesec=0
[main]
runmode=dev # dev 或 prod
tasksec=5 # 自动任务执行间隔(秒)
[log]
logfile=log/ciyon.log
logtcp=
logfilelevel=1 # 1-5,数字越小级别越高
logtcplevel=3
[web]
webmode=http
webipsk=127.0.0.1:4003
webhttp2= # HTTP2配置:端口,证书.crt,证书.key
[php]
host= # PHP代理地址(可选)
[mock]
target= # Mock数据库表名
docpass=
[s3A] # Cloudflare R2
access=
secret=
endpoint=1d486c90526e9c65512a35642f26d0c3.r2.cloudflarestorage.com
region=us-east-1
bucket=ciy5
acl=public-read
url=https://dao.ciy.cn/ud/
[s3B] # 腾讯云COS
access=
secret=
endpoint=tob-1322789299.cos.ap-nanjing.myqcloud.com
region=ap-nanjing
bucket=tob-1322789299
acl=public-read
url=https://tob-1322789299.cos.ap-nanjing.myqcloud.com/ud/
[s3C] # 阿里云OSS
access=
secret=
endpoint=expn.oss-cn-hangzhou.aliyuncs.com
region=oss-cn-hangzhou
bucket=expn
acl=public-read
url=https://expn.oss-cn-hangzhou.aliyuncs.com/ud/
[cdn]
weburl=https://ciyon.ciy.cn
files=.html;.js;.css
provider=cloud.tencent.com
secretId=
secretKey=
2. 创建业务模块
创建后端处理函数
文件:web/admin/demo.go
package admin
import (
"net/http"
c "ciyon/zciyon"
)
// 初始化数据
func Demo_init(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
_, userid := Verifyfast(r, c.CiyDB, post)
if userid == 0 {
return false
}
// 查询数据
csql := c.NewCiySQL("zc_demo")
csql.Where("status", 1).Order("id desc").Limit(1, 10)
list, total, err := c.CiyDB.Get(csql)
if err != nil {
return c.ErrJSON(w, "查询失败", err)
}
// 返回数据
return c.SuccJSON(w, r, map[string]any{
"list": list,
"total": total,
"status": c.Getcatas(c.CiyDB, "status"),
})
}
// 更新数据
func Demo_update(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
_, userid := Verifyfast(r, c.CiyDB, post)
if userid == 0 {
return false
}
id := post.Getint("id")
name := post.Get("name")
// 更新数据
csql := c.NewCiySQL("zc_demo")
csql.Where("id", id)
_, err := c.CiyDB.Update(csql, map[string]any{
"name": name,
"updatetime": c.Tostamp(),
})
if err != nil {
return c.ErrJSON(w, "更新失败", err)
}
// 记录日志
SaveLogDB(c.CiyDB, "DEMO", nil, map[string]any{"id": id, "name": name})
return c.SuccJSON(w, r)
}
// 删除数据
func Demo_del(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
_, userid := Verifyfast(r, c.CiyDB, post)
if userid == 0 {
return false
}
ids := post.Get("ids")
// 删除数据
csql := c.NewCiySQL("zc_demo")
csql.Where("id in", ids)
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_TABLE)
if err != nil {
return c.ErrJSON(w, "删除失败", err)
}
// 记录日志
SaveLog(c.CiyDB, "DEMO", "删除记录 IDs: "+ids)
return c.SuccJSON(w, r)
}
// 导出数据
func Demo_exportxls(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
_, userid := Verifyfast(r, c.CiyDB, post)
if userid == 0 {
return false
}
// 查询数据
csql := c.NewCiySQL("zc_demo")
csql.Where("status", 1)
list, _, err := c.CiyDB.Get(csql)
if err != nil {
return c.ErrJSON(w, "查询失败", err)
}
// 生成Excel
fields := []map[string]string{
{"name": "ID", "width": "50"},
{"name": "名称", "width": "100"},
{"name": "创建时间", "type": "dt", "width": "120"},
}
datas := [][]string{}
for _, row := range list {
datas = append(datas, []string{
c.Tostr(row["id"]),
c.Tostr(row["name"]),
c.Todate(c.Toint(row["createtime"]), "Y-m-d H:i"),
})
}
xml := c.General_excel_xml(fields, datas, map[string]any{
"toptitle": "数据列表",
"sheetname": "Sheet1",
})
w.Header().Set("Content-Type", "application/vnd.ms-excel")
w.Header().Set("Content-Disposition", "attachment; filename=demo.xls")
w.Write([]byte(xml))
return true
}
注册路由
在 route_adm.go 中添加路由:
func setWebRoute_adm(web *c.CiyWebServer) {
web.RouterFunc("/admin/demo", map[string]map[string]func(http.ResponseWriter, *http.Request) bool{
"normal": {
"init": demo.Normal_init,
"update": demo.Normal_update,
"del": demo.Normal_del,
"getdata": demo.Normal_getdata,
"exportxls": demo.Normal_exportxls,
},
})
}
后端开发
1. 数据库操作
CiySQL 链式查询
// 基本查询
csql := c.NewCiySQL("user")
csql.Where("name like", "张").Where("age>", 18)
csql.Order("id desc").Limit(1, 10)
list, total, err := c.CiyDB.Get(csql)
// 日期区间查询
csql.Where_daterange("createtime", "2024-01-01~2024-12-31")
// 相对日期查询
csql.Where_dayrange("createtime", "-30~0") // 最近30天
csql.Where_dayrange("createtime", "0") // 今天
csql.Where_dayrange("createtime", "-1") // 昨天
// 月份区间查询
csql.Where_monthrange("createtime", "2024-1") // 本月
csql.Where_monthrange("createtime", "2024-1~2024-6") // 月份区间
// 数值区间查询
csql.Where_numrange("price", 100, 1000, 100) // 10000~100000
// 原始SQL
csql.RawSQL("select * from user where id=?", 123)
// 字段排除
csql.Column("!id,password") // 排除id和password字段
// JOIN查询
csql.Join("role", "user.roleid=role.id", "left")
// 分组查询
csql.Group("department").Having("count(*)>10")
数据库CRUD操作
// 插入
csql := c.NewCiySQL("user")
lastid, err := c.CiyDB.Insert(csql, map[string]any{
"name": "张三",
"age": 25,
"createtime": c.Tostamp(),
})
// 更新
csql := c.NewCiySQL("user")
csql.Where("id", 123)
_, err := c.CiyDB.Update(csql, map[string]any{
"name": "李四",
"age": []string{"age+1"}, // SQL表达式:age+1
"updatetime": c.Tostamp(),
})
// 删除(三种模式)
csql := c.NewCiySQL("user")
csql.Where("id", 123)
// 直接删除
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_NONE)
// 备份到_bak表
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_TABLE)
// 标记删除(设置deltimes字段)
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_FIELD)
// 事务处理
err := c.CiyDB.Tran(func() error {
// 扣款
csql1 := c.NewCiySQL("account")
csql1.Where("id", 123)
c.CiyDB.Update(csql1, map[string]any{"balance": []string{"balance-100"}})
// 记录日志
csql2 := c.NewCiySQL("log")
c.CiyDB.Insert(csql2, map[string]any{"msg": "扣款100"})
return nil
})
2. 权限验证
// 完整验证(带用户信息)
func Verifyuser(r *http.Request, db *c.CiyMysql, post *c.CiyPost) (map[string]any, error)
// 快速验证(仅返回用户ID)
func Verifyfast(r *http.Request, db *c.CiyMysql, post *c.CiyPost) (map[string]any, int)
// 权限检查
func Nopower(db *c.CiyMysql, userid int, chkpower string) bool
// 使用示例
func Demo_init(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
rsuser, userid := Verifyfast(r, c.CiyDB, post)
if userid == 0 {
return false // 自动返回登录错误
}
// 检查权限(p123v表示菜单ID 123的查看权限)
if Nopower(c.CiyDB, userid, "p123v") {
return c.ErrJSON(w, "您未被授权操作")
}
// 业务逻辑
return c.SuccJSON(w, r)
}
3. 文件上传
本地上传:
func Upload_upload(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
_, userid := Verifyfast(r, c.CiyDB, post)
if userid == 0 {
return false
}
path := post.Get("pathfile")
file := post.Getfile()
// 保存文件
json, err := c.SaveUploadFile(path, file)
if err != nil {
return c.ErrJSON(w, err.Error())
}
return c.SuccJSON(w, r, json)
}
S3上传(生成签名):
func Upload_s3(w http.ResponseWriter, r *http.Request) bool {
post := c.NewCiyPost(w, r)
storselect := post.Get("storselect") // A/B/C
path := post.Get("pathfile")
// 获取S3配置
accessKey := c.CiyVars.Ini.GetKey("s3"+storselect, "access", "")
secretKey := c.CiyVars.Ini.GetKey("s3"+storselect, "secret", "")
endpoint := c.CiyVars.Ini.GetKey("s3"+storselect, "endpoint", "")
region := c.CiyVars.Ini.GetKey("s3"+storselect, "region", "")
bucket := c.CiyVars.Ini.GetKey("s3"+storselect, "bucket", "")
// 生成S3签名(示例代码)
// 返回签名信息,前端直接上传到S3
return c.SuccJSON(w, r, ret)
}
4. 日志记录
// 记录操作日志
SaveLog(db *c.CiyMysql, types string, msg string)
// 记录数据变更日志
SaveLogDB(db *c.CiyMysql, types string, oldrow map[string]any, newrow map[string]any)
// 使用示例
func Demo_update(w http.ResponseWriter, r *http.Request) bool {
// 获取旧数据
csql := c.NewCiySQL("zc_demo")
csql.Where("id", id)
oldrow, _ := c.CiyDB.Getone(csql)
// 执行更新
// ...
// 记录操作日志
SaveLog(c.CiyDB, "DEMO", "更新记录 ID: "+c.Tostr(id))
// 记录数据变更
SaveLogDB(c.CiyDB, "DEMO", oldrow, newrow)
return c.SuccJSON(w, r)
}
5. WebSocket
func Wsdemo(w http.ResponseWriter, r *http.Request) bool {
ws, err := c.NewCiyWebsocket(w, r)
if err != nil {
return false
}
// 接收消息
ws.OnMessageJSON(func(code int, id int, json map[string]any) {
// 处理消息
ws.SendSucc(id, map[string]any{
"msg": "收到消息",
"data": json,
})
})
// 错误处理
ws.OnError(func(err error) {
c.Log.Error("WS", err.Error())
})
// 关闭处理
ws.OnClose(func() {
c.Log.Info("WS", "连接关闭")
})
return true
}
6. SSE (Server-Sent Events)
func SSE_get(w http.ResponseWriter, r *http.Request) bool {
if !c.SSEInit(w) {
return false
}
for i := 0; i < 10; i++ {
c.SSESend_data(w, "消息 "+c.Tostr(i))
c.Sleep(1)
}
return true
}
7. HTTP 客户端
// GET 请求
resp, err := c.HttpGet("https://api.example.com/data")
// POST 请求
resp, err := c.HttpPost("https://api.example.com/api", map[string]any{
"name": "张三",
"age": 25,
})
// 带Header的请求
headers := map[string]string{
"Authorization": "Bearer token",
}
resp, err := c.HttpGet("https://api.example.com/data", headers)
8. JSON 处理
// JSON 编码
jsonStr, err := c.JsonEncode(map[string]any{
"name": "张三",
"age": 25,
})
// JSON 解码
var data map[string]any
err := c.JsonDecode(jsonStr, &data)
9. 配置文件读取
// 读取配置值
value := c.CiyVars.Ini.GetKey("db", "host", "")
10. 内存 KV 存储
// 设置值
c.CiyVars.MemKV.Set("key", "value", 3600) // 3600秒过期
// 获取值
value, exists := c.CiyVars.MemKV.Get("key")
// 删除值
c.CiyVars.MemKV.Delete("key")
权限体系
权限编码规范
权限编码格式:
p{菜单ID}{操作类型}
操作类型:
v- 查看e- 编辑d- 删除a- 添加s- 审批x- 自定义
示例:
p123v - 菜单ID 123 的查看权限
p123e - 菜单ID 123 的编辑权限
p123d - 菜单ID 123 的删除权限
权限验证
后端验证:
if Nopower(c.CiyDB, userid, "p123v") {
return c.ErrJSON(w, "您未被授权操作")
}
部署指南
编译
# Windows
gobuild.bat
# Linux
GOOS=linux GOARCH=amd64 go build -o zgo main.go
# macOS
GOOS=darwin GOARCH=amd64 go build -o zgo main.go
Nginx 配置
server {
listen 80;
server_name yourdomain.com;
# 静态文件
location / {
root /path/to/web;
index index.html;
}
# API 代理
location / {
proxy_pass http://127.0.0.1:4003;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# WebSocket
location /ws/ {
proxy_pass http://127.0.0.1:4003;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Systemd 服务
创建服务文件:/etc/systemd/system/ciyon.service
[Unit]
Description=Ciyon Web Server
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/path/to/golang
ExecStart=/path/to/golang/zgo
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
启动服务:
systemctl daemon-reload
systemctl start ciyon
systemctl enable ciyon
systemctl status ciyon
常见问题
1. 数据库连接失败
问题: 数据库连接失败 解决:
- 检查
web.ini中数据库配置是否正确 - 检查 MySQL 服务是否启动
- 检查数据库用户权限
2. 权限验证失败
问题: 提示"请重新登录" 解决:
- 检查
zc_online表中会话是否存在 - 检查会话是否过期
- 检查
Gtokenswapsec配置 - 检查 Token 加密密钥是否一致
3. 文件上传失败
问题: 文件上传失败 解决:
- 检查
web/ud/目录是否存在 - 检查目录写入权限
- 检查文件大小限制
- 检查文件类型是否在允许列表中
4. 日志不输出
问题: 日志不输出到文件 解决:
- 检查
log/ciyon.log文件是否存在 - 检查文件写入权限
- 检查
logfilelevel配置
最佳实践
代码规范
命名规范:
- 包名:小写单词,如
admin - 文件名:小写单词+下划线,如
demo.go - 函数名:大写开头(导出)或小写开头(私有)
- 变量名:尽量小写,如
userid - 常量名:大写+下划线,如
MAX_COUNT
注释规范:
// 函数功能说明
// 参数说明
// 返回值说明
func Demo_init(w http.ResponseWriter, r *http.Request) bool {
// ...
}
错误处理
// 统一错误返回
if err != nil {
return c.ErrJSON(w, "操作失败", err)
}
// 记录错误日志
if err != nil {
c.Log.Error("DEMO", "操作失败: "+err.Error())
return c.ErrJSON(w, "操作失败", err)
}
安全建议
- SQL 注入防护: 使用参数化查询
- XSS 防护: 对输出进行转义
- CSRF 防护: 使用 Token 验证
- 密码加密: 使用 SHA256 加密
- 权限控制: 严格的权限验证
- 日志记录: 记录所有操作日志
附录
A. 配置参数说明
| 参数 | 说明 | 默认值 |
|---|---|---|
| runmode | 运行模式 | dev |
| logfile | 日志文件路径 | log/ciyon.log |
| logfilelevel | 日志级别 | 3 |
| webmode | Web 模式 | http |
| webipsk | 监听地址 | 127.0.0.1:4003 |
| dbhost | 数据库地址 | 127.0.0.1 |
| dbport | 数据库端口 | 3306 |
| dbuser | 数据库用户 | root |
| dbpass | 数据库密码 | - |
| dbname | 数据库名称 | - |
B. 工具函数速查
| 函数 | 说明 | 示例 |
|---|---|---|
| Tostamp() | 获取当前时间戳 | c.Tostamp() |
| Todate() | 时间格式化 | c.Todate(c.Tostamp(), "Y-m-d H:i:s") |
| Tostr() | 转字符串 | c.Tostr(123) |
| Toint() | 转整数 | c.Toint("123") |
| Tofloat() | 转浮点数 | c.Tofloat("123.45") |
| MD5() | MD5 加密 | c.MD5("password") |
| Sha256() | SHA256 加密 | c.Sha256("password") |
| Encrypt() | 字符串加密 | c.Encrypt("text", "E", "key") |
| Uniqid() | 生成唯一ID | c.Uniqid(10) |
| Randstr() | 生成随机字符串 | c.Randstr(10) |
C. 错误码说明
| 错误码 | 说明 |
|---|---|
| 1 | 成功 |
| 2 | 未登录 |
| 3 | 权限不足 |
| 4 | 参数错误 |
| 9 | 操作失败 |
总结
Ciyon 框架是一个轻量级、高性能的后台管理系统开发框架,提供了完整的用户权限管理、数据操作、文件上传、日志记录等功能。开发者可以根据本文档快速上手开发,并根据实际需求进行扩展。
开发建议:
- 先熟悉核心库的使用方法
- 参考示例代码进行开发
- 遵循代码规范和最佳实践
- 注重安全性和性能优化
- 做好日志记录和错误处理
技术支持:
- 官网:https://ciy.cn/code
- 文档:本文档
- 示例:web/admin/ 目录下的示例代码
文档版本: v2.0
更新日期: 2026-03-18
作者: AI Assistant