{"id":30930274,"url":"https://github.com/peteryangs/superadminapi20","last_synced_at":"2025-09-10T10:44:06.581Z","repository":{"id":133974894,"uuid":"373554247","full_name":"PeterYangs/superAdminApi20","owner":"PeterYangs","description":"superAdmin 开箱即用的后台框架，支持权限管理、无限极分类、平滑重启、菜单管理、消息队列(即时和延迟)、任务调度、session、大文件上传等功能","archived":false,"fork":false,"pushed_at":"2025-03-13T13:58:55.000Z","size":583,"stargazers_count":14,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-13T14:36:38.543Z","etag":null,"topics":["admin-panel","go"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PeterYangs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-03T15:23:52.000Z","updated_at":"2025-03-13T13:58:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"e17d04a7-c4da-46a5-8e5a-24c47163af6b","html_url":"https://github.com/PeterYangs/superAdminApi20","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/PeterYangs/superAdminApi20","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminApi20","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminApi20/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminApi20/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminApi20/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PeterYangs","download_url":"https://codeload.github.com/PeterYangs/superAdminApi20/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminApi20/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274448137,"owners_count":25287120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["admin-panel","go"],"created_at":"2025-09-10T10:44:05.024Z","updated_at":"2025-09-10T10:44:06.561Z","avatar_url":"https://github.com/PeterYangs.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# superAdmin\n\n开箱即用的后台框架\n\n[中文文档](https://www.kancloud.cn/peter_yang/v001/2401726)\n\n[相关博客](https://www.zhihu.com/column/c_1394224785514082304)\n\n### 在线demo\n\nhttps://www.peterdemo.net\n\n账号：test\n\n密码：Aa123456\n\n### 前端仓库\nhttps://github.com/PeterYangs/superAdminPage20\n\n### 环境要求\n\nredis\n\nmysql\n\n\n### 开发模式\n```shell\ngo run main.go\n```\n\n### 编译\u0026部署\n编译二进制文件\n```\ngo build main.go\n```\n\n直接运行\n```\n./main\n\n或者\n\n./main start\n```\n\n后台运行\n```\n./main start -d\n```\n\n安全停止\n```\n./main stop\n```\n\n\n\n运行内置命令\n```shell\n./main artisan\n```\n\n\n\n\n### Quick start\n\n**controller**\n\n```go\npackage controller\n\nimport (\n\t\"github.com/PeterYangs/superAdminCore/v2/contextPlus\"\n\t\"github.com/PeterYangs/superAdminCore/v2/response\"\n)\n\nfunc Index(c *contextPlus.Context) *response.Response {\n\n\treturn response.Resp().Api(1, \"success\", \"index\")\n}\n```\n\n**route**\n\nroutes/routes.go\n\n```go\nfunc Routes(_r route.Group) {\n\n    _r.Registered(route.GET, \"/index\", controller.Index).Bind()\n\n    _r.Group(\"/login\", func (_login route.Group) {\n\n        _login.Registered(route.POST, \"/login\", login.Login, loginLimiter.LoginLimiter).Bind()\n\n        _login.Registered(route.POST, \"/logout\", login.Logout).Bind()\n\n    })\n}\n```\n\n**session**\n\n```go\nfunc Session(c *contextPlus.Context) *response.Response {\n\n    c.Session.Set(\"key\", \"value\")\n\n    c.Session.Get(\"key\")\n\n    return nil\n}\n```\n\n**全局中间件**\n\nmiddleware/global.go\n```go\npackage middleware\n\nimport (\n\t\"github.com/PeterYangs/superAdminCore/v2/contextPlus\"\n\t\"github.com/PeterYangs/superAdminCore/v2/middleware/session\"\n\t\"superadmin/middleware/accessLog\"\n)\n\nfunc Load() []contextPlus.HandlerFunc {\n\n\treturn []contextPlus.HandlerFunc{\n\n\t\tsession.StartSession,\n\t\taccessLog.AccessLog,\n\t}\n}\n\n```\n\n\n\n**验证码**\n\n获取验证码\n\n```go\nfunc Captcha(c *contextPlus.Context) *response.Response {\n\n    b := c.GetCaptcha()\n\n    c.Header(\"content-type\", \"image/png\")\n\n    return response.Resp().Byte(b)\n}\n```\n\n检查验证码\n\n```go\nfunc CheckCaptcha(c *contextPlus.Context) *response.Response {\n\n    code := c.Query(\"code\")\n\n    bool:= c.CheckCaptcha(code)\n\n    return response.Resp().Json(gin.H{\"bool\":code})\n\n}\n```\n\n**参数验证**\n\n```go\npackage regex\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"github.com/gin-gonic/gin\"\n)\n\n// Regex 参数规则验证示例，路由为 /regex/:name ,请求为 /regex/1sds?test[]=1\u0026test[]=2,regex标记只支持string和[]string两个类型\nfunc Regex(c *contextPlus.Context) *response.Response {\n\n\ttype regex struct {\n\t\tTest []string `form:\"test[]\" json:\"test\" regex:\"[0-9a-z/]+\"`\n\t\tName string   `uri:\"name\" json:\"name\" regex:\"[0-9a-z]+\"`\n\t}\n\n\tvar t regex\n\n\terr := c.ShouldBindPlus(\u0026t)\n\n\tif err != nil {\n\n\t\treturn response.Resp().Json(gin.H{\"code\": 2, \"msg\": err.Error()})\n\n\t}\n\n\treturn response.Resp().Json(gin.H{\"code\": 1, \"msg\": \"hello world\"})\n}\n\n```\n\n**数据库迁移**\n\n```shell\n\n[root@localhost ~]# ./main artisan\nUse the arrow keys to navigate: ↓ ↑ → ←\n? 选择类型:\n  \u003e 数据库迁移\n    数据填充\n    生成key\n    生成任务类\n\n```\n\n迁移文件\n\n```go\npackage migrate_2019_08_12_055619_create_admin_table\n\nimport \"gin-web/migrate\"\n\nfunc Up() {\n\n\tmigrate.Create(\"admin\", func(createMigrate *migrate.Migrate) {\n\n\t\tcreateMigrate.Name = \"migrate_2019_08_12_055619_create_admin_table\"\n\n\t\t//主键\n\t\tcreateMigrate.BigIncrements(\"id\")\n\n\t\t//int\n\t\tcreateMigrate.Integer(\"user_id\").Unsigned().Nullable().Default(0).Unique().Comment(\"用户id\")\n\n\t\t//varchar\n\t\tcreateMigrate.String(\"title\", 255).Default(\"\").Comment(\"标题\")\n\n\t\t//text\n\t\tcreateMigrate.Text(\"content\").Default(migrate.Null).Comment(\"内容\")\n\n\t\t//索引\n\t\tcreateMigrate.Unique(\"user_id\", \"title\")\n\n\t})\n\n}\n\nfunc Down() {\n\n\tmigrate.DropIfExists(\"admin\")\n\n}\n\n```\n\n**限流器**\n\n```go\npackage loginLimiter\n\nimport (\n\t\"gin-web/component/limiter\"\n\t\"gin-web/contextPlus\"\n\t\"golang.org/x/time/rate\"\n\t\"time\"\n)\n\nfunc LoginLimiter(c *contextPlus.Context) {\n\n\t//每秒生成一个令牌，桶的大小是10,第三个参数是自定义key，根据自定义的key寻找限流器（默认是每1分钟清理一次过期的限流器）\n\tif !limiter.NewLimiter(rate.Every(1*time.Second), 10, c.ClientIP()).Allow() {\n\n\t\tc.String(500, \"访问频率过高\")\n\n\t\tc.Abort()\n\n\t}\n\n}\n\n```\n\n**分布式锁**\n\n非阻塞\n\n```go\nfunc Index(c *contextPlus.Context) *response.Response {\n\n    //申请一个锁，过期时间是10秒\n    lock := redis.GetClient().Lock(\"lock\", 10*time.Second)\n\n    //释放锁\n    defer lock.Release()\n\n    //是否拿到锁\n    if lock.Get() {\n\n        return response.Resp().Json(gin.H{\"res\": true})\n    \n    }\n\n    return response.Resp().Json(gin.H{\"res\": false})\n\n}\n```\n\n阻塞\n\n```go\nfunc Index(c *contextPlus.Context) *response.Response {\n\n    //申请一个锁，过期时间是10秒\n    lock := redis.GetClient().Lock(\"lock\", 10*time.Second)\n\n    defer lock.Release()\n\n    //是否拿到锁\n    if lock.Block(time.Second * 3) {\n    \t\n    \ttime.Sleep(4 * time.Second)\n\n        return response.Resp().Json(gin.H{\"res\": true})\n    }\n\n    return response.Resp().Json(gin.H{\"res\": false})\n\n}\n```\n\n**消息队列**\n\n生成任务类\n```shell\n[root@localhost superAdminApi20]# ./main artisan\nUse the arrow keys to navigate: ↓ ↑ → ←\n? 选择类型:\n    数据库迁移\n    数据填充\n    生成key\n  \u003e 生成任务类\n```\n\n任务类\n```go\npackage access\n\nimport (\n\t\"gin-web/database\"\n\t\"gin-web/model\"\n\t\"gin-web/task\"\n)\n\ntype TaskAccess struct {\n\ttask.BaseTask\n\tParameters *Parameter\n}\n\ntype Parameter struct {\n\ttask.Parameter\n\tIp      string\n\tUrl     string\n\tParams  string\n\tAdminId float64\n}\n\nfunc NewTask(ip string, url string, params string, adminId float64) *TaskAccess {\n\n\treturn \u0026TaskAccess{\n\n\t\tBaseTask: task.BaseTask{\n\t\t\tTaskName: \"access\",\n\t\t},\n\t\tParameters: \u0026Parameter{\n\t\t\tIp:      ip,\n\t\t\tUrl:     url,\n\t\t\tParams:  params,\n\t\t\tAdminId: adminId,\n\t\t},\n\t}\n}\n\nfunc (t *TaskAccess) Run() error {\n\n\tdatabase.GetDb().Create(\u0026model.Access{\n\t\tIp:      t.Parameters.Ip,\n\t\tUrl:     t.Parameters.Url,\n\t\tParams:  t.Parameters.Params,\n\t\tAdminId: t.Parameters.AdminId,\n\t})\n\t\n\treturn nil\n\n}\n\nfunc (t *TaskAccess) BindParameters(p map[string]interface{}) {\n\n\tt.BaseTask.Bind(t.Parameters, p)\n\n}\n\n```\n\n\n即时任务\n\n```go\npackage controller\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"gin-web/queue\"\n\t\"gin-web/response\"\n\t\"gin-web/task/email\"\n\t\"gin-web/task/sms\"\n)\n\nfunc Task(c *contextPlus.Context) *response.Response {\n\n\tqueue.Dispatch(email.NewTask(\"904801074@qq.com\", \"title\", \"content\")).Queue(\"low\").Run()\n\n\treturn response.Resp().Api(1, \"123\", \"\")\n\n}\n```\n\n延迟队列\n\n```go\npackage controller\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"gin-web/queue\"\n\t\"gin-web/response\"\n\t\"gin-web/task/email\"\n\t\"gin-web/task/sms\"\n\t\"time\"\n)\n\nfunc Task(c *contextPlus.Context) *response.Response {\n\n\tqueue.Dispatch(email.NewTask(\"904801074@qq.com\", \"title\", \"content\")).Queue(\"low\").Delay(100 * time.Second).Run()\n\n\treturn response.Resp().Api(1, \"123\", \"\")\n\n}\n```\n\n\n重试次数\n```go\npackage controller\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"gin-web/queue\"\n\t\"gin-web/response\"\n\t\"gin-web/task/email\"\n\t\"gin-web/task/sms\"\n)\n\nfunc Task(c *contextPlus.Context) *response.Response {\n\n\tqueue.Dispatch(email.NewTask(\"904801074@qq.com\", \"title\", \"content\")).SetTryTime(3).Run()\n\n\treturn response.Resp().Api(1, \"123\", \"\")\n\n}\n```\n\n\n**任务调度**\n\ncrontab/crontabs.go\n```go\npackage crontab\n\nimport \"fmt\"\n\nfunc Crontab(c *crontab) {\n\n\tc.newSchedule().everyHour().function(func() {\n\n\t\tfmt.Println(\"每小时\")\n\n\t})\n\n\tc.newSchedule().hourlyAt(16).everyMinute().function(func() {\n\n\t\tfmt.Println(\"每个16点的每分钟\")\n\n\t})\n\n\tc.newSchedule().minuteAt(18).function(func() {\n\n\t\tfmt.Println(\"每小时的第18分钟\")\n\n\t})\n\n\tc.newSchedule().everyMinute().function(func() {\n\n\t\t//panic(\"模拟报错\")\n\n\t\tfmt.Println(\"每分钟\")\n\n\t})\n\n\tc.newSchedule().everyMinuteAt(2).function(func() {\n\n\t\tfmt.Println(\"每2分钟\")\n\n\t})\n\n\tc.newSchedule().everyDay().hourlyAt(16).minuteAt(36).function(func() {\n\n\t\tfmt.Println(\"每天16点36分\")\n\n\t})\n\n\tc.newSchedule().dayAt(23).hourlyAt(16).minuteAt(50).function(func() {\n\n\t\tfmt.Println(\"23号16点50分\")\n\n\t})\n\n\tc.newSchedule().dayAt(24).hourBetween(8, 10).function(func() {\n\n\t\tfmt.Println(\"24号8点-10点\")\n\n\t})\n\n\tc.newSchedule().hourBetween(8, 9).everyMinute().function(func() {\n\n\t\tfmt.Println(\"每天8点-9点每分钟\")\n\n\t})\n\n\tc.newSchedule().dayBetween(22, 24).everyHour().everyMinute().function(func() {\n\n\t\tfmt.Println(\"22号-24号每分钟\")\n\n\t})\n\n}\n\n```\n\n\n**命令行**\n\n需要实现\n```go\ntype Artisan interface {\n\tArtisanRun()\n\tGetName() string\n}\n```\n一个例子\n```go\npackage demo\n\nimport \"github.com/PeterYangs/superAdminCore/v2/component/logs\"\n\ntype Demo struct {\n}\n\nfunc (d Demo) GetName() string {\n\n\treturn \"demo\"\n}\n\nfunc (d Demo) ArtisanRun() {\n\n\tlogs.NewLogs().Debug(\"demo\")\n}\n\n```\n运行\n```shell\n./main artisan\n```\n**缓存**\n\n缓存支持两种驱动`file`和`redis`，在`.env`文件中设置`CACHE_DRIVER=redis`\n```go\npackage test\n\nimport (\n\t\"fmt\"\n\t\"github.com/PeterYangs/superAdminCore/v2/cache\"\n\t\"github.com/PeterYangs/superAdminCore/v2/contextPlus\"\n\t\"github.com/PeterYangs/superAdminCore/v2/response\"\n)\n\nfunc Cache(c *contextPlus.Context) *response.Response {\n\n\tcache.Cache().Put(\"nice\", \"0\", 0)\n\n\tfmt.Println(cache.Cache().Get(\"nice\"))\n\n\treturn response.Resp().Api(1, \"success\", \"\")\n}\n\n```\n\n**管理员登录模式**\n\n在.env文件中设置\n```dotenv\n#登录模式，single(单点登录),multi(多点登录)\nLOGIN_MODE=single|multi\n```\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeteryangs%2Fsuperadminapi20","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeteryangs%2Fsuperadminapi20","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeteryangs%2Fsuperadminapi20/lists"}