Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd3d629282 | |||
| deb3cc71bf |
+8
-1
@@ -1,2 +1,9 @@
|
||||
report.md
|
||||
# Claude Code 协作指引(本地,不入库)
|
||||
CLAUDE.md
|
||||
|
||||
# 临时发版辅助文件
|
||||
gitHub_release_*.md
|
||||
|
||||
# 构建产物
|
||||
*.exe
|
||||
bin/
|
||||
|
||||
+76
-2
@@ -14,6 +14,79 @@ xlgo 框架更新日志。本文档遵循 [Keep a Changelog](https://keepachange
|
||||
|
||||
---
|
||||
|
||||
## [1.0.4] - 2026-06-22
|
||||
|
||||
> 本版本定位为 **DX & Docs release**:开发体验与文档改进,无破坏性 API 变更。对应体检报告 #25/#27/#28/#29/#30。
|
||||
|
||||
### Added ✨
|
||||
|
||||
#### CLI 多模板(#28)
|
||||
|
||||
`xlgo new` 新增 `--template` 参数,支持三种脚手架模板:
|
||||
|
||||
```bash
|
||||
xlgo new myapp --template minimal # 轻量 HTTP,无 MySQL/Redis 依赖
|
||||
xlgo new myapp --template api # 标准业务 API,含分层目录(默认)
|
||||
xlgo new myapp --template fullstack # 全组件,NewFullStack 一键启用
|
||||
```
|
||||
|
||||
- `minimal`:仅 logger + health + 示例路由,目录结构最小化,第一次接触 xlgo 从这里开始
|
||||
- `api`:含 handler/model/repository/service 分层 + MySQL/Redis/JWT 配置(默认模板)
|
||||
- `fullstack`:`NewFullStack` 全组件 + Swagger + Storage
|
||||
|
||||
#### examples/ 目录(#29)
|
||||
|
||||
新增两个可运行示例,帮助快速上手:
|
||||
|
||||
- `examples/minimal/` — 50 行可跑,不依赖外部服务
|
||||
- `examples/full/` — MySQL + Redis + JWT + user CRUD 完整示例(登录发 token、认证路由、创建/查询用户)
|
||||
- `examples/README.md` — 运行说明与接口文档
|
||||
|
||||
#### docs/ 文档结构(#30)
|
||||
|
||||
- 新增 `docs/` 目录,`docs/plans/` 归档历史规划与体检报告
|
||||
- 新增 `docs/README.md` 文档索引
|
||||
- `Version_Update_Plan_v1.0.2.md` → `docs/plans/`
|
||||
- `Version_v1.0.2_report.md` → `docs/plans/`
|
||||
- 早期 `report.md` → `docs/plans/v2.0-review.md`
|
||||
- `CHANGELOG.md` / `GUIDE.md` 按惯例保留在仓库根目录
|
||||
|
||||
### Changed 🔄
|
||||
|
||||
#### 模块路径文档改进(#25)
|
||||
|
||||
经评估**保留** `xlgo-core` 模块路径——`-core` 后缀反映这是 xlgo 多产品系列(xlgo-core / xlgo-orm / xlgo-ai ...)的核心产品,不去掉。模块路径(`github.com/EthanCodeCraft/xlgo-core`)与包名(`xlgo`)不同是 Go 惯例(cf. `github.com/gin-gonic/gin` → 包名 `gin`)。
|
||||
|
||||
改进文档说明,消除新用户 `go mod tidy` 撞墙的困惑:
|
||||
|
||||
- README 快速开始新增「模块路径与包名」小节,给出完整 import 示例:
|
||||
```go
|
||||
import xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
```
|
||||
- CLAUDE.md `Import Path Note` 措辞明确化,说明 module path / package name / `-core` 语义
|
||||
|
||||
#### Without* Option 定位文档化(#27)
|
||||
|
||||
经调研 `Without*` 系列 Option 有真实用例(测试覆盖「先开再关」语义 + `NewFullStack` 后排除单项),**不删除、不标 Deprecated**,改为文档化其定位:
|
||||
|
||||
- `app.go` `WithoutLogger` 注释说明:`Without*` 主要用于 `NewFullStack` / `RunFullStack` 启用全部组件后排除个别项
|
||||
- README 快速开始补充用法说明:`xlgo.NewFullStack(xlgo.WithoutSwaggerRoutes())`
|
||||
|
||||
### 依赖与构建
|
||||
|
||||
- `.gitignore` 整理:忽略 `CLAUDE.md`、构建产物(`*.exe` / `bin/`)、临时发版文件(`gitHub_release_*.md`)
|
||||
|
||||
### 升级说明
|
||||
|
||||
v1.0.4 **无破坏性变更**,从 v1.0.3 升级只需:
|
||||
|
||||
```bash
|
||||
go get github.com/EthanCodeCraft/xlgo-core@v1.0.4
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## [1.0.3] - 2026-06-22
|
||||
|
||||
> 本版本定位为 **bug fix release**:收口 v1.0.2 引入的破坏性清理,并修复 4 个轻量 bug + 依赖复查。
|
||||
@@ -341,8 +414,9 @@ v1.0.2 引入可插拔方言注册表后,`gorm.io/driver/postgres` 成为直
|
||||
- 基础框架功能
|
||||
- 完整示例代码
|
||||
|
||||
[Unreleased]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.0.3...HEAD
|
||||
[Unreleased]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.0.4...HEAD
|
||||
[1.0.4]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.4
|
||||
[1.0.3]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.3
|
||||
[1.0.2]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.2
|
||||
[1.0.2]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.0.1...v1.0.3
|
||||
[1.0.1]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.1
|
||||
[1.0.0]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.0
|
||||
|
||||
@@ -94,6 +94,41 @@ go run main.go
|
||||
访问 http://localhost:8080/health 检查服务状态。
|
||||
|
||||
> v1.0.2 起,`xlgo.New()` 默认是轻量应用,不会自动初始化 MySQL、Redis、Storage 或 Swagger。需要完整基础设施时请显式使用 `WithMySQL()`、`WithRedis()`、`WithStorage()`、`WithSwaggerRoutes()`,或直接使用 `xlgo.NewFullStack()`。
|
||||
>
|
||||
> `Without*` 系列 Option(如 `WithoutSwaggerRoutes`)主要用于 `NewFullStack` / `RunFullStack` 启用全部组件后排除个别项,例如 `xlgo.NewFullStack(xlgo.WithoutSwaggerRoutes())` 全组件但关闭 Swagger。`xlgo.New()` 本身已全关,无需再 `Without`。
|
||||
|
||||
### 4. 模块路径与包名
|
||||
|
||||
xlgo 的 **模块路径** 是 `github.com/EthanCodeCraft/xlgo-core`,**包名** 是 `xlgo`(二者不同是 Go 惯例,如 `github.com/gin-gonic/gin` → 包名 `gin`)。import 时用别名 `xlgo` 即可:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := xlgo.New(
|
||||
xlgo.WithConfigPath("./config.yaml"),
|
||||
xlgo.WithLogger(),
|
||||
xlgo.WithHealthRoutes(),
|
||||
)
|
||||
// 注册一个示例路由
|
||||
app.GetRouter().GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"message": "Hello xlgo!"})
|
||||
})
|
||||
// 启用 JWT 认证示例路由(需配合 WithMySQL/WithRedis 生成 token)
|
||||
_ = middleware.RequireUserTypes("admin")
|
||||
|
||||
_ = app.Run()
|
||||
}
|
||||
```
|
||||
|
||||
> 子包(`config` / `database` / `logger` / `middleware` ...)的包名与目录名一致,无需别名。
|
||||
|
||||
---
|
||||
|
||||
@@ -699,6 +734,18 @@ docker run -d -p 8080:8080 xlgo-app:latest
|
||||
|
||||
> 完整变更历史见 [CHANGELOG.md](./CHANGELOG.md)。
|
||||
|
||||
### v1.0.4 (2026-06-22)
|
||||
|
||||
> 本版本定位为 **DX & Docs release**:开发体验与文档改进,无破坏性 API 变更。
|
||||
|
||||
- **CLI 多模板** - `xlgo new --template minimal/api/fullstack`,支持轻量 HTTP / 标准业务 / 全组件三种脚手架
|
||||
- **examples/ 目录** - 新增 `examples/minimal`(无依赖可跑)与 `examples/full`(mysql+redis+jwt+user CRUD)可运行示例
|
||||
- **模块路径文档** - 明确说明 module path `xlgo-core` 与 package name `xlgo` 的关系,补完整 import 示例(保留 `-core`,xlgo 多产品系列)
|
||||
- **Without* 定位** - 文档化 `Without*` Option 主要用于 `NewFullStack` 后排除单项
|
||||
- **文档结构** - 规划文档归档到 `docs/plans/`,新增 `docs/README.md` 索引
|
||||
|
||||
升级:`go get github.com/EthanCodeCraft/xlgo-core@v1.0.4`(无破坏性变更)
|
||||
|
||||
### v1.0.3 (2026-06-22)
|
||||
|
||||
> 本版本定位为 **bug fix release**:收口 v1.0.2 引入的破坏性清理,并修复 4 个轻量 bug + 依赖复查。完整说明见 [CHANGELOG.md#unreleased](./CHANGELOG.md#unreleased)。
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
// Version 框架版本号。发版时只改这一处,避免版本字面量散落各处。
|
||||
// CLI(xlgo version)、脚手架生成的 go.mod 等均引用此常量。
|
||||
const Version = "1.0.3"
|
||||
const Version = "1.0.4"
|
||||
|
||||
// HealthCheckFunc 健康检查函数
|
||||
type HealthCheckFunc func(context.Context) error
|
||||
@@ -123,7 +123,11 @@ func WithDefaultRoutes() Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithoutLogger 关闭日志
|
||||
// WithoutLogger 关闭日志。
|
||||
//
|
||||
// Without* 系列的定位:xlgo.New() 默认是轻量应用(组件全关),故 Without*
|
||||
// 主要用于 NewFullStack / RunFullStack 启用全部组件后,排除个别不需要的项。
|
||||
// 例如:xlgo.NewFullStack(xlgo.WithoutSwaggerRoutes()) 全组件但关 Swagger。
|
||||
func WithoutLogger() Option {
|
||||
return func(a *App) { a.enableLogger = false }
|
||||
}
|
||||
|
||||
+61
-24
@@ -19,17 +19,46 @@ func createProject(name string) {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建目录结构
|
||||
dirs := []string{
|
||||
name,
|
||||
name + "/config",
|
||||
name + "/handler",
|
||||
name + "/model",
|
||||
name + "/repository",
|
||||
name + "/service",
|
||||
name + "/middleware",
|
||||
name + "/public",
|
||||
name + "/logs",
|
||||
// 解析 --template 与 --module 参数(默认 template=api)
|
||||
tmplName := "api"
|
||||
module := name
|
||||
args := os.Args[3:]
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--template", "-t":
|
||||
if i+1 < len(args) {
|
||||
tmplName = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--module", "-m":
|
||||
if i+1 < len(args) {
|
||||
module = args[i+1]
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 校验模板名
|
||||
switch tmplName {
|
||||
case "minimal", "api", "fullstack":
|
||||
// ok
|
||||
default:
|
||||
fmt.Printf("未知模板: %s(可选: minimal / api / fullstack)\n", tmplName)
|
||||
return
|
||||
}
|
||||
|
||||
// minimal 模板目录结构最小化;api/fullstack 含完整分层目录
|
||||
var dirs []string
|
||||
dirs = append(dirs, name, name+"/public", name+"/logs")
|
||||
if tmplName != "minimal" {
|
||||
dirs = append(dirs,
|
||||
name+"/config",
|
||||
name+"/handler",
|
||||
name+"/model",
|
||||
name+"/repository",
|
||||
name+"/service",
|
||||
name+"/middleware",
|
||||
)
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
@@ -39,12 +68,6 @@ func createProject(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取模块路径
|
||||
module := name
|
||||
if len(os.Args) > 3 && os.Args[3] == "--module" && len(os.Args) > 4 {
|
||||
module = os.Args[4]
|
||||
}
|
||||
|
||||
caser := cases.Title(language.English)
|
||||
data := TemplateData{
|
||||
Package: caser.String(name),
|
||||
@@ -54,14 +77,28 @@ func createProject(name string) {
|
||||
Year: time.Now().Year(),
|
||||
}
|
||||
|
||||
// 按模板选择 main.go 与 config.yaml
|
||||
var mainTmpl, configTmpl string
|
||||
switch tmplName {
|
||||
case "minimal":
|
||||
mainTmpl, configTmpl = templates.MainMinimal, templates.ConfigMinimal
|
||||
case "fullstack":
|
||||
mainTmpl, configTmpl = templates.MainFull, templates.ConfigFull
|
||||
default: // api
|
||||
mainTmpl, configTmpl = templates.Main, templates.Config
|
||||
}
|
||||
|
||||
// 创建文件
|
||||
files := map[string]string{
|
||||
name + "/main.go": templates.Main,
|
||||
name + "/config.yaml": templates.Config,
|
||||
name + "/go.mod": fmt.Sprintf(templates.GoMod, module, xlgo.Version),
|
||||
name + "/Makefile": templates.Makefile,
|
||||
name + "/.gitignore": templates.Gitignore,
|
||||
name + "/handler/home.go": templates.Handler,
|
||||
name + "/main.go": mainTmpl,
|
||||
name + "/config.yaml": configTmpl,
|
||||
name + "/go.mod": fmt.Sprintf(templates.GoMod, module, xlgo.Version),
|
||||
name + "/Makefile": templates.Makefile,
|
||||
name + "/.gitignore": templates.Gitignore,
|
||||
}
|
||||
// api/fullstack 模板带示例 handler
|
||||
if tmplName != "minimal" {
|
||||
files[name+"/handler/home.go"] = templates.Handler
|
||||
}
|
||||
|
||||
for path, content := range files {
|
||||
@@ -84,7 +121,7 @@ func createProject(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("✓ 项目 %s 创建成功\n", name)
|
||||
fmt.Printf("✓ 项目 %s 创建成功(模板: %s)\n", name, tmplName)
|
||||
fmt.Println("\n下一步:")
|
||||
fmt.Printf(" cd %s\n", name)
|
||||
fmt.Println(" go mod tidy")
|
||||
|
||||
+10
-3
@@ -11,15 +11,22 @@ func printUsage() {
|
||||
fmt.Println(`xlgo - Go Web 框架脚手架工具
|
||||
|
||||
用法:
|
||||
xlgo new <项目名> 创建新项目
|
||||
xlgo make handler <名称> 创建处理器
|
||||
xlgo new <项目名> [--template <模板>] [--module <模块路径>] 创建新项目
|
||||
xlgo make handler <名称> 创建处理器
|
||||
xlgo make repository <名称> 创建仓库
|
||||
xlgo make model <名称> 创建模型
|
||||
xlgo make service <名称> 创建服务
|
||||
xlgo version 显示版本号
|
||||
xlgo version 显示版本号
|
||||
|
||||
模板 (xlgo new --template <名称>):
|
||||
minimal 轻量 HTTP 服务,不依赖 MySQL/Redis(默认入门)
|
||||
api 标准业务 API,含 MySQL/Redis/JWT 与 handler/model/repository/service 分层(默认)
|
||||
fullstack 全组件,一键启用 MySQL/Redis/Storage/Swagger/AutoMigrate
|
||||
|
||||
示例:
|
||||
xlgo new myapp
|
||||
xlgo new myapp --template minimal
|
||||
xlgo new myapp --template fullstack --module github.com/me/myapp
|
||||
xlgo make handler user
|
||||
xlgo make repository user`)
|
||||
}
|
||||
|
||||
+168
-2
@@ -2,8 +2,12 @@ package main
|
||||
|
||||
// Templates 存放所有代码生成模板
|
||||
var templates = struct {
|
||||
Main string
|
||||
Config string
|
||||
Main string // api 模板:标准业务 API(mysql+redis+jwt+分层)
|
||||
MainMinimal string // minimal 模板:轻量 HTTP,无外部依赖
|
||||
MainFull string // fullstack 模板:全组件
|
||||
Config string // api 模板配置
|
||||
ConfigMinimal string
|
||||
ConfigFull string
|
||||
GoMod string
|
||||
Makefile string
|
||||
Gitignore string
|
||||
@@ -104,6 +108,168 @@ storage:
|
||||
path: ./public
|
||||
base_url: http://localhost:8080/public
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
max_backups: 30
|
||||
max_age: 30
|
||||
compress: true
|
||||
`,
|
||||
|
||||
// MainMinimal minimal 模板:轻量 HTTP 服务,不依赖 MySQL/Redis/Storage
|
||||
MainMinimal: `package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/EthanCodeCraft/xlgo-core/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var configPath string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&configPath, "config", "./config.yaml", "配置文件路径")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
app := xlgo.New(
|
||||
xlgo.WithConfigPath(configPath),
|
||||
xlgo.WithLogger(),
|
||||
xlgo.WithHealthRoutes(),
|
||||
xlgo.WithMiddlewares(middleware.Logger(), middleware.CORS()),
|
||||
xlgo.WithModules(router.ModuleFunc(registerRoutes)),
|
||||
)
|
||||
|
||||
if err := app.Run(); err != nil {
|
||||
fmt.Printf("启动失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func registerRoutes(r *gin.RouterGroup) {
|
||||
api := r.Group("/api/v1")
|
||||
api.GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"message": "Hello {{.Name}}!"})
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
||||
// ConfigMinimal minimal 模板配置:仅 app + server + log,无数据库/Redis
|
||||
ConfigMinimal: `app:
|
||||
name: "{{.Name}}"
|
||||
site_name: "{{.NameLower}}"
|
||||
version: "1.0.0"
|
||||
env: "dev"
|
||||
debug: true
|
||||
base_url: "http://localhost:8080"
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
mode: development
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
max_backups: 30
|
||||
max_age: 30
|
||||
compress: true
|
||||
`,
|
||||
|
||||
// MainFull fullstack 模板:全组件(FullStack),含 Swagger + Storage
|
||||
MainFull: `package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/EthanCodeCraft/xlgo-core/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var configPath string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&configPath, "config", "./config.yaml", "配置文件路径")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// NewFullStack 一键启用全部组件:Logger/MySQL/Redis/Storage/Wire/Health/Swagger/AutoMigrate
|
||||
// 如需排除个别组件,追加对应 Without* Option,例如 xlgo.WithoutSwaggerRoutes()
|
||||
app := xlgo.NewFullStack(
|
||||
xlgo.WithConfigPath(configPath),
|
||||
xlgo.WithMiddlewares(middleware.Logger(), middleware.CORS()),
|
||||
xlgo.WithModules(router.ModuleFunc(registerRoutes)),
|
||||
// xlgo.WithModels(&User{}, &Order{}), // 注册模型以启用自动迁移
|
||||
)
|
||||
|
||||
if err := app.Run(); err != nil {
|
||||
fmt.Printf("启动失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func registerRoutes(r *gin.RouterGroup) {
|
||||
api := r.Group("/api/v1")
|
||||
api.GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"message": "Welcome to {{.Name}} (fullstack)!"})
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
||||
// ConfigFull fullstack 模板配置:全组件配置
|
||||
ConfigFull: `app:
|
||||
name: "{{.Name}}"
|
||||
site_name: "{{.NameLower}}"
|
||||
version: "1.0.0"
|
||||
env: "dev"
|
||||
debug: true
|
||||
base_url: "http://localhost:8080"
|
||||
token_expire: 86400
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
mode: development
|
||||
|
||||
database:
|
||||
driver: mysql # mysql(默认)或 postgres
|
||||
host: localhost
|
||||
port: 3306
|
||||
user: root
|
||||
password: your_password
|
||||
name: {{.NameLower}}
|
||||
max_idle_conns: 10
|
||||
max_open_conns: 100
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 0
|
||||
|
||||
jwt:
|
||||
secret: your_jwt_secret_key_here
|
||||
expire: 86400
|
||||
|
||||
storage:
|
||||
driver: local
|
||||
local:
|
||||
path: ./public
|
||||
base_url: http://localhost:8080/public
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# xlgo 文档
|
||||
|
||||
| 文档 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| README.md | 仓库根 | 快速开始、功能概览、更新日志 |
|
||||
| GUIDE.md | 仓库根 | 完整使用指南 |
|
||||
| CHANGELOG.md | 仓库根 | 变更日志(遵循 Keep a Changelog) |
|
||||
| CLAUDE.md | 仓库根 | Claude Code 协作指引 |
|
||||
| docs/plans/ | 本目录 | 历史版本规划与体检报告归档 |
|
||||
|
||||
## docs/plans/ 归档文档
|
||||
|
||||
这些是各版本开发时的规划/评审文档,**反映当时状态**,代码可能已演进,阅读时请对照 CHANGELOG 确认现状。
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| Version_Update_Plan_v1.0.2.md | v1.0.2 更新计划(已完成) |
|
||||
| Version_v1.0.2_report.md | v1.0.2 体检报告,含 #1-#30 改进建议与版本路线图 |
|
||||
| v2.0-review.md | 更早期的 v2.0 评估报告 |
|
||||
|
||||
> v1.0.2 体检报告中的 #1-#30 改进项,完成情况见根目录 [CHANGELOG.md](../CHANGELOG.md) 各版本章节。
|
||||
@@ -0,0 +1,485 @@
|
||||
# xlgo Web 框架评估报告(v2.0 优化后版本)
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
xlgo 是一个基于 Go + Gin 构建的轻量级 Web 开发框架,旨在提供后端开发的基础设施。本报告基于 v2.0 版本(经过全面优化和 zl 工具库移植后)进行评估。
|
||||
|
||||
---
|
||||
|
||||
## 二、本轮优化内容汇总
|
||||
|
||||
### 2.1 新增核心包
|
||||
|
||||
| 包名 | 来源 | 函数数 | 核心功能 |
|
||||
|------|------|--------|----------|
|
||||
| `utils/` | zl/utils | 111 | 随机数、字符串、时间、转换、文件、URL、验证、加密、HTTP客户端、UUID |
|
||||
| `console/` | zl/utils/print_*.go | 22 | 彩色控制台输出(Debug/Info/Success/Warn/Error) |
|
||||
| `compress/` | zl/service/compress | 7 | Gzip/Zip 压缩解压 |
|
||||
| `cache/keybuilder.go` | zl/service/cache | 新增 | 键名前缀管理,多站点共用 Redis |
|
||||
| `cache/lock.go` | zl/service/cache | 新增 | 分布式锁、计数器、TTL管理 |
|
||||
| `middleware/requestid.go` | zl/middleware | 2 | 请求ID追踪 |
|
||||
| `middleware/recover.go` | zl/middleware | 2 | Panic恢复中间件 |
|
||||
| `handler/handler.go` | zl/response | 增强 | 类型安全参数获取(QueryInt/PathInt/FormInt等) |
|
||||
| `response/response.go` | zl/response | 增强 | RequestID字段、文件下载、HTML响应、跳转 |
|
||||
| `config/config.go` | 新增 | AppConfig | 应用配置(SiteName/Env/Version等) |
|
||||
|
||||
### 2.2 配置增强
|
||||
|
||||
新增 `AppConfig` 配置块,支持站点别名:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
name: "用户管理系统"
|
||||
site_name: "user_api" # 站点别名,用于缓存键前缀、日志标识
|
||||
version: "1.0.0"
|
||||
env: "prod"
|
||||
debug: false
|
||||
base_url: "https://user.example.com"
|
||||
token_expire: 86400
|
||||
```
|
||||
|
||||
### 2.3 CLI 工具重构
|
||||
|
||||
将原来单个 `main.go`(约700行)拆分为模块化结构:
|
||||
|
||||
```
|
||||
cmd/xlgo/
|
||||
├── main.go # 入口和命令路由(~50行)
|
||||
├── types.go # 类型定义
|
||||
├── utils.go # 工具函数
|
||||
├── commands.go # 命令实现
|
||||
└── templates.go # 所有模板定义
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、项目规模对比
|
||||
|
||||
| 指标 | v1.1.0 | v2.0 | 提升 |
|
||||
|------|--------|------|------|
|
||||
| Go 源文件数 | 28 | 54 | +93% |
|
||||
| 代码行数 | ~2,800 | ~8,400 | +200% |
|
||||
| 包数量 | 16 | 23 | +44% |
|
||||
| 函数数量 | ~150 | ~450 | +200% |
|
||||
| 测试覆盖 | 0% | 8% (2/24包) | +8% | utils/console已有测试 |
|
||||
|
||||
---
|
||||
|
||||
## 四、模块完整性评估(v2.0)
|
||||
|
||||
### 4.1 核心模块评分对比
|
||||
|
||||
| 模块 | v1.1.0 | v2.0 | 提升 | 说明 |
|
||||
|------|--------|------|------|------|
|
||||
| 配置管理 | 8/10 | 9/10 | +1 | 新增 AppConfig、SiteName |
|
||||
| 数据库 | 8/10 | 8/10 | - | 保持稳定 |
|
||||
| Redis/缓存 | 9/10 | 10/10 | +1 | 分布式锁、键名前缀、计数器 |
|
||||
| JWT 认证 | 8/10 | 8/10 | - | 保持稳定 |
|
||||
| 日志系统 | 9/10 | 9/10 | - | 保持稳定 |
|
||||
| 中间件 | 8/10 | 9/10 | +1 | RequestID、Recover、彩色输出 |
|
||||
| 文件存储 | 9/10 | 9/10 | - | 保持稳定 |
|
||||
| 工具函数 | 3/10 | 9/10 | +6 | 111个实用函数 |
|
||||
| 验证器 | 9/10 | 9/10 | - | 保持稳定 |
|
||||
| 错误处理 | 8/10 | 8/10 | - | 保持稳定 |
|
||||
| 密码加密 | 9/10 | 9/10 | - | 保持稳定 |
|
||||
| SSE 支持 | 8/10 | 8/10 | - | 保持稳定 |
|
||||
| WebSocket | 8/10 | 8/10 | - | 保持稳定 |
|
||||
| 定时任务 | 7/10 | 7/10 | - | 保持稳定 |
|
||||
| 测试支持 | 8/10 | 8/10 | - | 保持稳定 |
|
||||
| CLI 工具 | 7/10 | 8/10 | +1 | 模块化重构、模板分离 |
|
||||
| 压缩解压 | 0/10 | 8/10 | +8 | Gzip/Zip完整实现 |
|
||||
| 控制台输出 | 0/10 | 9/10 | +9 | 跨平台彩色输出 |
|
||||
|
||||
### 4.2 新增 utils 包功能清单
|
||||
|
||||
#### 4.2.1 随机数生成 (random.go)
|
||||
```go
|
||||
RandString(16) // 随机字符串(字母+数字)
|
||||
RandDigit(6) // 随机数字字符串
|
||||
RandInt(1, 100) // 随机整数
|
||||
RandInt64(0, 1000) // 随机int64
|
||||
```
|
||||
|
||||
#### 4.2.2 字符串处理 (strings.go)
|
||||
```go
|
||||
IsBlank(s) // 检查空白
|
||||
IsAnyBlank(strs...) // 批量检查
|
||||
DefaultIfBlank(s, def) // 默认值
|
||||
Substr(s, 0, 10) // 子字符串(支持中文)
|
||||
StrLen(s) // Unicode长度
|
||||
EqualsIgnoreCase(a, b) // 不区分大小写
|
||||
Trim(s) // 去除空白
|
||||
```
|
||||
|
||||
#### 4.2.3 时间日期 (datetime.go)
|
||||
```go
|
||||
NowUnix() // 秒时间戳
|
||||
NowTimestamp() // 毫秒时间戳
|
||||
FromUnix(unix) // 时间戳转时间
|
||||
FormatDateTime(t) // 格式化 "2006-01-02 15:04:05"
|
||||
StartOfDay(t) // 当天开始
|
||||
EndOfDay(t) // 当天结束
|
||||
StartOfMonth(t) // 当月开始
|
||||
EndOfMonth(t) // 当月结束
|
||||
```
|
||||
|
||||
#### 4.2.4 类型转换 (convert.go)
|
||||
```go
|
||||
ToInt(s) // 字符串转int
|
||||
ToIntDefault(s, 0) // 带默认值
|
||||
ToInt64(s) // 转int64
|
||||
ToFloat64(s) // float64
|
||||
CalcPageCount(100, 10) // 计算总页数
|
||||
CalcOffset(2, 20) // 分页偏移
|
||||
```
|
||||
|
||||
#### 4.2.5 文件操作 (file.go)
|
||||
```go
|
||||
FileExists(path) // 检查文件存在
|
||||
DirExists(path) // 检查目录存在
|
||||
EnsureDir(path) // 确保目录存在
|
||||
ReadFile(path) // 读取文件
|
||||
WriteFile(path, data) // 写入文件
|
||||
CopyFile(dst, src) // 复制文件
|
||||
```
|
||||
|
||||
#### 4.2.6 URL处理 (url.go)
|
||||
```go
|
||||
ParseURL(rawURL) // 解析URL
|
||||
builder.AddQuery("key", "value") // 链式添加参数
|
||||
URLEncode(s) // URL编码
|
||||
URLDecode(s) // URL解码
|
||||
```
|
||||
|
||||
#### 4.2.7 格式验证 (validator.go)
|
||||
```go
|
||||
IsPhone(phone) // 手机号验证
|
||||
IsEmail(email) // 邮箱验证
|
||||
IsIPv4(ip) // IPv4验证
|
||||
IsIDCard(id) // 身份证验证
|
||||
IsChinese(s) // 中文验证
|
||||
IsNumeric(s) // 数字验证
|
||||
IsAlphanumeric(s) // 字母数字验证
|
||||
```
|
||||
|
||||
#### 4.2.8 加密编码 (crypto.go)
|
||||
```go
|
||||
MD5(s) // MD5哈希
|
||||
SHA256(s) // SHA256哈希
|
||||
Base64Encode(data) // Base64编码
|
||||
Base64URLEncode(data) // URL安全编码
|
||||
```
|
||||
|
||||
#### 4.2.9 HTTP客户端 (http.go)
|
||||
```go
|
||||
client := NewHTTPClient()
|
||||
client.SetTimeout(30*time.Second)
|
||||
client.SetHeader("Authorization", "Bearer xxx")
|
||||
client.Get(url, params) // GET请求
|
||||
client.PostJSON(url, data) // POST JSON
|
||||
client.Upload(url, files, params) // 文件上传
|
||||
```
|
||||
|
||||
#### 4.2.10 UUID生成 (uuid.go)
|
||||
```go
|
||||
UUID() // UUID v4字符串
|
||||
UUIDShort() // 短UUID(无横线)
|
||||
UUIDValid(s) // 验证UUID
|
||||
```
|
||||
|
||||
### 4.3 新增 console 包功能
|
||||
|
||||
```go
|
||||
console.Debug("调试信息") // 青色
|
||||
console.Info("普通信息") // 白色
|
||||
console.Success("成功信息") // 绿色
|
||||
console.Warn("警告信息") // 黄色
|
||||
console.Error("错误信息") // 红色
|
||||
|
||||
// 自定义配置
|
||||
c := console.New(
|
||||
console.WithColor(true),
|
||||
console.WithTime(true),
|
||||
console.WithCaller(true, 2),
|
||||
)
|
||||
c.Debug("自定义控制台输出")
|
||||
```
|
||||
|
||||
### 4.4 新增 compress 包功能
|
||||
|
||||
```go
|
||||
// Gzip 数据压缩
|
||||
GzipCompress(data)
|
||||
GzipDecompress(data)
|
||||
|
||||
// Gzip 文件压缩
|
||||
GzipCompressFile(src, dst)
|
||||
GzipDecompressFile(src, dst)
|
||||
|
||||
// Zip 打包
|
||||
Zip(zipPath, paths) // 打包文件/目录
|
||||
Unzip(zipPath, dstDir) // 解压到目录
|
||||
```
|
||||
|
||||
### 4.5 缓存键名前缀管理
|
||||
|
||||
```go
|
||||
// 自动从配置读取 site_name
|
||||
cache.K("user:1") // -> "cache:user_api:user:1"
|
||||
cache.KTemp("token") // -> "temp:user_api:token"
|
||||
cache.KPerm("config") // -> "perm:user_api:config"
|
||||
cache.KLock("order:123") // -> "lock:user_api:order:123"
|
||||
cache.KCounter("visit") // -> "counter:user_api:visit"
|
||||
cache.KSession("sid") // -> "session:user_api:sid"
|
||||
|
||||
// 分布式锁
|
||||
cache.Lock(ctx, key, ttl)
|
||||
cache.Unlock(ctx, key)
|
||||
cache.TryLock(ctx, key, ttl, retry, maxRetry)
|
||||
cache.WithLock(ctx, key, ttl, fn) // 自动管理锁
|
||||
|
||||
// 计数器
|
||||
cache.Incr(ctx, key)
|
||||
cache.Decr(ctx, key)
|
||||
```
|
||||
|
||||
### 4.6 中间件增强
|
||||
|
||||
```go
|
||||
// RequestID - 请求追踪
|
||||
r.Use(middleware.RequestID())
|
||||
// 响应头自动添加 X-Request-ID
|
||||
|
||||
// Recover - Panic恢复
|
||||
r.Use(middleware.Recover()) // 生产环境
|
||||
r.Use(middleware.RecoverWithDetail()) // 开发环境(返回详细信息)
|
||||
```
|
||||
|
||||
### 4.7 Handler 参数获取增强
|
||||
|
||||
```go
|
||||
// 类型安全的参数获取
|
||||
page := handler.QueryInt(c, "page", 1)
|
||||
id := handler.PathInt64(c, "id", 0)
|
||||
price := handler.QueryFloat64(c, "price", 0.0)
|
||||
enabled := handler.QueryBool(c, "enabled", false)
|
||||
count := handler.FormInt(c, "count", 0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、多站点共用 Redis 方案
|
||||
|
||||
### 5.1 问题背景
|
||||
|
||||
多个小项目共用一台 Redis 服务器时,缓存键名可能冲突:
|
||||
- 项目A: `user:1`
|
||||
- 项目B: `user:1`
|
||||
- 项目C: `user:1`
|
||||
|
||||
### 5.2 解决方案
|
||||
|
||||
通过 `site_name` 配置自动添加前缀:
|
||||
|
||||
| 项目 | config.yaml | 实际键名 |
|
||||
|------|-------------|----------|
|
||||
| 用户API | `site_name: user_api` | `cache:user_api:user:1` |
|
||||
| 订单API | `site_name: order_api` | `cache:order_api:user:1` |
|
||||
| 支付API | `site_name: pay_api` | `cache:pay_api:user:1` |
|
||||
|
||||
### 5.3 使用方式
|
||||
|
||||
```yaml
|
||||
# config.yaml
|
||||
app:
|
||||
site_name: "my_project"
|
||||
```
|
||||
|
||||
```go
|
||||
// 无需额外代码,自动生效
|
||||
cache.K("user:1") // -> "cache:my_project:user:1"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、性能评估(v2.0)
|
||||
|
||||
### 6.1 性能优化点
|
||||
|
||||
| 优化项 | 说明 |
|
||||
|--------|------|
|
||||
| RandString/RandDigit | 使用 sync.Pool 复用 rand.Source |
|
||||
| StringToBytes/BytesToString | 零拷贝转换 |
|
||||
| HTTPClient | 链式配置,连接复用 |
|
||||
| 缓存键名 | 预构建,避免重复拼接 |
|
||||
|
||||
### 6.2 性能基准估算
|
||||
|
||||
| 场景 | 预估 QPS | 说明 |
|
||||
|------|----------|------|
|
||||
| 简单查询 API | 12,000-18,000 | 无 DB 查询 |
|
||||
| 带 DB 查询 | 3,000-5,000 | 单表主键查询 |
|
||||
| 缓存查询 | 10,000-15,000 | Redis 缓存命中 |
|
||||
| SSE 流式响应 | 5,000-8,000 | 单连接 |
|
||||
| WebSocket 连接 | 10,000+ | 连接数 |
|
||||
| 文件压缩 | 50-100 MB/s | Gzip |
|
||||
| HTTP请求 | 1,000-5,000 | 外部API调用 |
|
||||
|
||||
---
|
||||
|
||||
## 七、扩展性评估(v2.0)
|
||||
|
||||
| 方面 | v1.1.0 | v2.0 | 说明 |
|
||||
|------|--------|------|------|
|
||||
| 存储扩展 | 本地 + OSS | 本地 + OSS | 保持 |
|
||||
| 缓存扩展 | 基础操作 | 分布式锁、计数器、前缀 | +3功能 |
|
||||
| 验证扩展 | 自定义规则 | 手机/邮箱/IP等预定义 | +7规则 |
|
||||
| 通信扩展 | HTTP + SSE + WS | 保持 | - |
|
||||
| 工具扩展 | 无 | 111个函数 | +111 |
|
||||
| 压缩扩展 | 无 | Gzip + Zip | +2 |
|
||||
| 控制台扩展 | 无 | 彩色输出 | +1 |
|
||||
|
||||
---
|
||||
|
||||
## 八、易用性评估(v2.0)
|
||||
|
||||
### 8.1 开发效率提升
|
||||
|
||||
| 任务 | v1.1.0 | v2.0 | 节省 |
|
||||
|------|--------|------|------|
|
||||
| 创建新项目 | 5 分钟 | 5 分钟 | - |
|
||||
| 添加 CRUD 模块 | 10 分钟 | 10 分钟 | - |
|
||||
| 请求验证 | 5 分钟 | 5 分钟 | - |
|
||||
| 参数类型转换 | 手动编写 | 调用 handler.QueryInt | 90% |
|
||||
| 文件压缩 | 手动实现 | 调用 compress.Zip | 100% |
|
||||
| 随机字符串 | 手动实现 | 调用 utils.RandString | 100% |
|
||||
| 时间格式化 | 记忆布局 | 调用 utils.FormatDateTime | 80% |
|
||||
| 分布式锁 | 手动实现 | 调用 cache.Lock | 100% |
|
||||
| HTTP请求 | 手动封装 | 调用 NewHTTPClient().Get | 100% |
|
||||
| 控制台调试 | fmt.Println | console.Debug(彩色) | 50% |
|
||||
|
||||
### 8.2 代码简化示例
|
||||
|
||||
```go
|
||||
// v1.1.0 - 手动实现
|
||||
func GetUser(c *gin.Context) {
|
||||
pageStr := c.Query("page")
|
||||
page := 1
|
||||
if pageStr != "" {
|
||||
p, err := strconv.Atoi(pageStr)
|
||||
if err == nil {
|
||||
page = p
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
// v2.0 - 一行搞定
|
||||
func GetUser(c *gin.Context) {
|
||||
page := handler.QueryInt(c, "page", 1)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、安全性评估(v2.0)
|
||||
|
||||
| 检查项 | v1.1.0 | v2.0 | 说明 |
|
||||
|--------|--------|------|------|
|
||||
| SQL 注入 | ✅ GORM | ✅ GORM | 保持 |
|
||||
| XSS | ⚠️ 应用层 | ⚠️ 应用层 | 保持 |
|
||||
| CSRF | ❌ 无 | ✅ 完善 | +1 | 多种模式:Cookie/API/DoubleSubmit |
|
||||
| 密码加密 | ✅ bcrypt | ✅ bcrypt | 保持 |
|
||||
| 请求验证 | ✅ validator | ✅ validator | 保持 |
|
||||
| 限流防护 | ✅ 完善 | ✅ 完善 | 保持 |
|
||||
| JWT 安全 | ✅ 黑名单 | ✅ 黑名单 | 保持 |
|
||||
| Panic恢复 | ❌ 无 | ✅ Recover中间件 | +1 |
|
||||
| 请求追踪 | ❌ 无 | ✅ RequestID | +1 |
|
||||
| 类型安全 | ⚠️ 手动 | ✅ 强类型函数 | +1 |
|
||||
|
||||
---
|
||||
|
||||
## 十、综合评分(v2.0)
|
||||
|
||||
| 维度 | v1.1.0 | v2.0 | 提升 |
|
||||
|------|--------|------|------|
|
||||
| 完整性 | 8.5/10 | 9.5/10 | +1.0 |
|
||||
| 性能 | 8.5/10 | 9.0/10 | +0.5 |
|
||||
| 扩展性 | 7.5/10 | 9.0/10 | +1.5 |
|
||||
| 易用性 | 9.0/10 | 9.5/10 | +0.5 |
|
||||
| 安全性 | 8.0/10 | 9.0/10 | +1.0 |
|
||||
| **总分** | **8.35/10** | **9.2/10** | **+0.85** |
|
||||
|
||||
---
|
||||
|
||||
## 十一、剩余改进建议
|
||||
|
||||
### 11.1 P3 - 下一步优化
|
||||
|
||||
| 功能 | 优先级 | 说明 |
|
||||
|------|--------|------|
|
||||
| Kafka 生产者 | 低 | 需重新设计连接池 |
|
||||
| WebSocket 客户端 | 低 | 框架已有服务端实现 |
|
||||
| 链路追踪 | 中 | OpenTelemetry集成 |
|
||||
| 单元测试 | 高 | 进行中,覆盖所有包 |
|
||||
| 性能基准 | 中 | 建立benchmark |
|
||||
|
||||
### 11.2 测试建议
|
||||
|
||||
```bash
|
||||
# 运行现有测试
|
||||
go test ./utils/... ./console/... -v
|
||||
|
||||
# 建议添加
|
||||
go test ./cache/... ./handler/... ./middleware/...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、结论
|
||||
|
||||
经过本轮全面优化,xlgo 框架已从 **生产就绪** 提升至 **功能丰富** 水平。
|
||||
|
||||
### 12.1 核心优势
|
||||
|
||||
1. **工具库完善** - 111个实用函数,覆盖日常开发80%场景
|
||||
2. **多站点支持** - SiteName配置解决共用Redis冲突
|
||||
3. **类型安全** - QueryInt/PathInt等避免手动转换
|
||||
4. **开发调试** - 彩色控制台输出,一眼识别日志级别
|
||||
5. **分布式支持** - Redis分布式锁开箱即用
|
||||
6. **文件处理** - Gzip/Zip压缩解压
|
||||
|
||||
### 12.2 适用场景
|
||||
|
||||
- ✅ 中大型 API 服务
|
||||
- ✅ 用户管理系统
|
||||
- ✅ AI 应用后端
|
||||
- ✅ 实时通信应用
|
||||
- ✅ 多项目共用资源
|
||||
- ✅ 创业项目 MVP
|
||||
- ✅ 学习 Go Web 开发
|
||||
|
||||
### 12.3 开发效率总结
|
||||
|
||||
| 场景 | 使用 xlgo v2.0 | 不使用框架 | 节省 |
|
||||
|------|----------------|------------|------|
|
||||
| 用户系统 | 4-5 人天 | 10-16 人天 | 60% |
|
||||
| AI应用 | 4-5 人天 | 9-14 人天 | 55% |
|
||||
| 通用API | 2-3 人天 | 5-8 人天 | 60% |
|
||||
|
||||
---
|
||||
|
||||
## 十三、版本历史
|
||||
|
||||
| 版本 | 日期 | 主要变化 |
|
||||
|------|------|----------|
|
||||
| v1.0.0 | 2026-04-29 | 基础框架 |
|
||||
| v1.1.0 | 2026-04-29 | P0/P1/P2修复(12项) |
|
||||
| v2.0.0 | 2026-04-29 | zl工具库移植、模块重构 |
|
||||
|
||||
---
|
||||
|
||||
*评估日期:2026-04-29*
|
||||
*评估版本:v2.0.0*
|
||||
*优化内容:新增5个包 + 增强5个包 + 配置扩展 + CLI重构 = 约120个函数*
|
||||
@@ -0,0 +1,42 @@
|
||||
# xlgo 示例
|
||||
|
||||
两个可运行示例,帮助快速上手 xlgo。
|
||||
|
||||
## minimal — 最小 HTTP 服务
|
||||
|
||||
不依赖 MySQL / Redis / Storage,纯 HTTP + 健康检查。第一次接触 xlgo 从这里开始。
|
||||
|
||||
```bash
|
||||
go run ./examples/minimal
|
||||
```
|
||||
|
||||
访问 http://localhost:8081/health(健康检查)与 http://localhost:8081/api/v1/(示例路由)。
|
||||
|
||||
## full — 完整业务 API
|
||||
|
||||
包含 MySQL + Redis + JWT + 一个 user CRUD(登录发 token、认证路由、创建/查询用户)。
|
||||
|
||||
**运行前需准备**:
|
||||
- MySQL(修改 `examples/full/config.yaml` 的 `database` 配置)
|
||||
- Redis(修改 `examples/full/config.yaml` 的 `redis` 配置)
|
||||
|
||||
```bash
|
||||
go run ./examples/full
|
||||
```
|
||||
|
||||
启动后自动迁移 user 表。接口:
|
||||
|
||||
| 方法 | 路径 | 说明 | 认证 |
|
||||
|---|---|---|---|
|
||||
| POST | /api/v1/login | 登录,返回 token | 否 |
|
||||
| GET | /api/v1/users/:id | 查询用户 | 是(Bearer token) |
|
||||
| POST | /api/v1/users | 创建用户 | 是(Bearer token) |
|
||||
|
||||
登录示例:
|
||||
```bash
|
||||
curl -X POST http://localhost:8082/api/v1/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"alice","password":"secret"}'
|
||||
```
|
||||
|
||||
> 示例代码为演示用途,密码明文存储、未做参数校验,生产环境请使用 bcrypt 哈希密码并配合 `validation` 包校验入参。
|
||||
@@ -0,0 +1,35 @@
|
||||
app:
|
||||
name: "xlgo-full-example"
|
||||
env: "dev"
|
||||
debug: true
|
||||
|
||||
server:
|
||||
port: 8082
|
||||
mode: development
|
||||
|
||||
database:
|
||||
driver: mysql
|
||||
host: localhost
|
||||
port: 3306
|
||||
user: root
|
||||
password: your_password
|
||||
name: xlgo_example
|
||||
max_idle_conns: 10
|
||||
max_open_conns: 100
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 0
|
||||
|
||||
jwt:
|
||||
secret: change-me-to-a-long-random-secret-at-least-32-chars
|
||||
expire: 86400
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
max_backups: 30
|
||||
max_age: 30
|
||||
compress: true
|
||||
@@ -0,0 +1,125 @@
|
||||
// Package main 是 xlgo 的完整示例:MySQL + Redis + JWT + 一个 user CRUD。
|
||||
//
|
||||
// 运行前需准备:
|
||||
// - MySQL(config.yaml 中 database 配置)
|
||||
// - Redis(config.yaml 中 redis 配置)
|
||||
//
|
||||
// 启动后会自动迁移 user 表。访问:
|
||||
//
|
||||
// POST /api/v1/login {"username":"alice","password":"secret"} → 返回 token
|
||||
// GET /api/v1/users/:id (需 Authorization: Bearer <token>)
|
||||
// POST /api/v1/users (创建用户)
|
||||
//
|
||||
// 运行:
|
||||
//
|
||||
// go run ./examples/full
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/database"
|
||||
"github.com/EthanCodeCraft/xlgo-core/jwt"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/repository"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/EthanCodeCraft/xlgo-core/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// User 示例模型
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string `gorm:"uniqueIndex;size:64" json:"username"`
|
||||
Password string `gorm:"size:128" json:"-"` // 实际项目应存 bcrypt 哈希
|
||||
UserType string `gorm:"size:32" json:"user_type"`
|
||||
}
|
||||
|
||||
var userRepo *repository.BaseRepo[User]
|
||||
|
||||
func main() {
|
||||
app := xlgo.NewFullStack(
|
||||
xlgo.WithConfigPath("./examples/full/config.yaml"),
|
||||
xlgo.WithModels(&User{}),
|
||||
xlgo.WithMiddlewares(middleware.Logger(), middleware.CORS()),
|
||||
xlgo.WithModules(router.ModuleFunc(registerRoutes)),
|
||||
)
|
||||
|
||||
// 初始化 user repository(App.Init 之后 master DB 才可用,这里在 registerRoutes 里延迟拿)
|
||||
_ = app
|
||||
|
||||
if err := app.Run(); err != nil {
|
||||
fmt.Printf("启动失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func registerRoutes(r *gin.RouterGroup) {
|
||||
// 延迟初始化 repo:此时 App.Init 已完成,database.GetDB() 可用
|
||||
userRepo = repository.NewBaseRepo[User](database.GetDB())
|
||||
|
||||
api := r.Group("/api/v1")
|
||||
|
||||
// 公开路由:登录
|
||||
api.POST("/login", login)
|
||||
|
||||
// 认证路由
|
||||
auth := api.Group("/", middleware.AuthRequired())
|
||||
auth.GET("/users/:id", getUser)
|
||||
auth.POST("/users", createUser)
|
||||
}
|
||||
|
||||
func login(c *gin.Context) {
|
||||
var req struct {
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 示例简化:查询用户,不校验密码哈希
|
||||
u, err := userRepo.FindOne(c.Request.Context(), "username = ?", req.Username)
|
||||
if err != nil {
|
||||
response.Fail(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
token, err := jwt.GenerateToken(u.ID, u.Username, "user", u.UserType)
|
||||
if err != nil {
|
||||
response.ServerError(c, "生成 token 失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"token": token})
|
||||
}
|
||||
|
||||
func getUser(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
// 示例简化:直接用 repo 查询,实际应转 uint
|
||||
var uid uint
|
||||
fmt.Sscanf(id, "%d", &uid)
|
||||
u, err := userRepo.FindByID(c.Request.Context(), uid)
|
||||
if err != nil {
|
||||
response.NotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
}
|
||||
|
||||
func createUser(c *gin.Context) {
|
||||
var u User
|
||||
if err := c.ShouldBindJSON(&u); err != nil {
|
||||
response.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
u.UserType = "user"
|
||||
if err := userRepo.Create(c.Request.Context(), &u); err != nil {
|
||||
response.Fail(c, "创建失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
app:
|
||||
name: "xlgo-minimal-example"
|
||||
env: "dev"
|
||||
debug: true
|
||||
|
||||
server:
|
||||
port: 8081
|
||||
mode: development
|
||||
@@ -0,0 +1,42 @@
|
||||
// Package main 是 xlgo 的最小可运行示例。
|
||||
//
|
||||
// 仅依赖一个 config.yaml,不初始化 MySQL / Redis / Storage,
|
||||
// 适合第一次接触 xlgo、或纯 HTTP 场景。
|
||||
//
|
||||
// 运行:
|
||||
//
|
||||
// go run ./examples/minimal
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/EthanCodeCraft/xlgo-core/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := xlgo.New(
|
||||
xlgo.WithConfigPath("./examples/minimal/config.yaml"),
|
||||
xlgo.WithLogger(),
|
||||
xlgo.WithHealthRoutes(),
|
||||
xlgo.WithMiddlewares(middleware.Logger(), middleware.CORS()),
|
||||
xlgo.WithModules(router.ModuleFunc(registerRoutes)),
|
||||
)
|
||||
|
||||
if err := app.Run(); err != nil {
|
||||
fmt.Printf("启动失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func registerRoutes(r *gin.RouterGroup) {
|
||||
api := r.Group("/api/v1")
|
||||
api.GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"message": "Hello xlgo!"})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user