README
¶
CLI - 代码生成器
CLI 是 LiteCore 框架的配套命令行工具,提供代码生成和项目脚手架功能。
特性
- 智能扫描:自动扫描项目中的 Entity、Repository、Service、Controller、Middleware、Listener、Scheduler 组件
- 7 层架构支持:完整的 7 层依赖注入架构(内置管理器层 → Entity → Repository → Service → 交互层)
- 交互层生成:自动生成 Controller/Middleware/Listener/Scheduler 四种容器初始化代码
- 实体基类支持:生成的 Entity 使用
common.BaseEntityWithTimestamps基类,自动生成 CUID2 ID 和时间戳 - 项目脚手架:支持快速创建符合 LiteCore 架构的新项目
- 灵活配置:支持自定义项目路径、输出目录、包名和配置文件路径
- 双模式使用:既可作为命令行工具,也可作为库导入使用
快速开始
安装
方法 1:go install(推荐)
go install github.com/lite-lake/litecore-go/cli@latest
安装后直接使用 cli 命令
方法 2:本地构建
# 构建可执行文件
go build -o litecore-cli ./cli
# 或直接使用 go run
go run ./cli/main.go
命令概览
# 查看帮助
litecore-cli --help
# 查看版本
litecore-cli version
# 生成容器代码
litecore-cli generate
# 创建新项目
litecore-cli scaffold
# 生成 Shell 补全
litecore-cli completion bash
代码生成
基本用法
# 使用默认配置生成(当前目录,输出到 internal/application)
litecore-cli generate
# 指定项目路径
litecore-cli generate --project /path/to/project
# 指定输出目录
litecore-cli generate --output internal/container
# 指定包名
litecore-cli generate --package container
# 指定配置文件路径
litecore-cli generate --config configs/app.yaml
# 完整示例
litecore-cli generate --project . --output internal/application --package application --config configs/config.yaml
参数说明
| 参数 | 简写 | 默认值 | 说明 |
|---|---|---|---|
--project |
-p |
. |
项目路径 |
--output |
-o |
internal/application |
输出目录 |
--package |
- | application |
包名 |
--config |
-c |
configs/config.yaml |
配置文件路径 |
作为库使用
package main
import (
"os"
"github.com/lite-lake/litecore-go/cli/generator"
)
func main() {
cfg := generator.DefaultConfig()
// 修改配置
cfg.ProjectPath = "."
cfg.OutputDir = "internal/container"
cfg.PackageName = "container"
cfg.ConfigPath = "configs/config.yaml"
if err := generator.Run(cfg); err != nil {
os.Exit(1)
}
}
项目脚手架
基本用法
# 交互式模式(推荐)
litecore-cli scaffold
# 使用 basic 模板
litecore-cli scaffold --module github.com/user/app --project myapp --template basic
# 使用 standard 模板
litecore-cli scaffold --module github.com/user/app --project myapp --template standard
# 使用 full 模板
litecore-cli scaffold --module github.com/user/app --project myapp --template full
参数说明
| 参数 | 简写 | 默认值 | 说明 |
|---|---|---|---|
--module |
-m |
- | 模块路径(如 github.com/user/app) |
--project |
-n |
- | 项目名称 |
--output |
-o |
- | 输出目录 |
--template |
-t |
- | 模板类型(basic/standard/full) |
--interactive |
-i |
- | 交互式模式 |
模板类型
| 模板 | 包含内容 |
|---|---|
basic |
目录结构 + go.mod + README |
standard |
basic + 配置文件 + 基础中间件 + 自动生成容器代码 |
full |
standard + 完整示例代码(entity/repository/service/controller/listener/scheduler) |
代码约定
目录结构
项目根目录/
├── internal/
│ ├── entities/ # 实体层:导出的结构体类型
│ ├── repositories/ # 仓储层:I 前缀接口 + New 前缀工厂函数
│ ├── services/ # 服务层:I 前缀接口 + New 前缀工厂函数
│ ├── controllers/ # 交互层 - 控制器:I 前缀接口 + New 前缀工厂函数
│ ├── middlewares/ # 交互层 - 中间件:I 前缀接口 + New 前缀工厂函数
│ ├── listeners/ # 交互层 - 监听器:I 前缀接口 + New 前缀工厂函数
│ ├── schedulers/ # 交互层 - 定时器:I 前缀接口 + New 前缀工厂函数
│ └── application/ # 生成的容器代码
└── configs/
└── config.yaml # 配置文件
命名规范
| 层级 | 接口命名 | 工厂函数命名 | 实现结构体 |
|---|---|---|---|
| Entity | MessageEntity |
无需工厂函数 | Message |
| Repository | IMessageRepository |
NewMessageRepository() |
messageRepositoryImpl |
| Service | IMessageService |
NewMessageService() |
messageServiceImpl |
| Controller | IMessageController |
NewMessageController() |
msgControllerImpl |
| Middleware | IAuthMiddleware |
NewAuthMiddleware() |
authMiddlewareImpl |
| Listener | IMessageListener |
NewMessageListener() |
messageListenerImpl |
| Scheduler | ICleanupScheduler |
NewCleanupScheduler() |
cleanupSchedulerImpl |
组件示例
Entity 示例(使用基类)
package entities
import (
"github.com/lite-lake/litecore-go/common"
)
// 使用 BaseEntityWithTimestamps 基类(最常用)
// 基类提供:
// - ID(25 位 CUID2 字符串)
// - CreatedAt(创建时间)
// - UpdatedAt(更新时间)
// - GORM Hook 自动填充
type Message struct {
common.BaseEntityWithTimestamps
Nickname string `gorm:"type:varchar(20);not null" json:"nickname"`
Content string `gorm:"type:varchar(500);not null" json:"content"`
Status string `gorm:"type:varchar(20);default:'pending'" json:"status"`
}
func (m *Message) EntityName() string {
return "Message"
}
func (m *Message) TableName() string {
return "messages"
}
func (m *Message) GetId() string {
return m.ID
}
var _ common.IBaseEntity = (*Message)(nil)
其他基类选项:
// BaseEntityOnlyID - 仅 ID(适合配置表、字典表)
type Config struct {
common.BaseEntityOnlyID
Key string
Value string
}
// BaseEntityWithCreatedAt - ID + 创建时间(适合日志、审计记录)
type AuditLog struct {
common.BaseEntityWithCreatedAt
Action string
Details string
}
Repository 示例
package repositories
import (
"{{.ModulePath}}/internal/entities"
"github.com/lite-lake/litecore-go/common"
"github.com/lite-lake/litecore-go/manager/configmgr"
"github.com/lite-lake/litecore-go/manager/databasemgr"
)
type IMessageRepository interface {
common.IBaseRepository
Create(message *entities.Message) error
GetByID(id string) (*entities.Message, error) // ID 类型为 string
}
type messageRepositoryImpl struct {
Config configmgr.IConfigManager `inject:""`
Manager databasemgr.IDatabaseManager `inject:""`
}
func NewMessageRepository() IMessageRepository {
return &messageRepositoryImpl{}
}
func (r *messageRepositoryImpl) RepositoryName() string {
return "MessageRepository"
}
func (r *messageRepositoryImpl) OnStart() error {
return nil
}
func (r *messageRepositoryImpl) OnStop() error {
return nil
}
func (r *messageRepositoryImpl) Create(message *entities.Message) error {
db := r.Manager.DB()
return db.Create(message).Error
}
func (r *messageRepositoryImpl) GetByID(id string) (*entities.Message, error) {
db := r.Manager.DB()
var message entities.Message
err := db.Where("id = ?", id).First(&message).Error // 使用 Where 查询
if err != nil {
return nil, err
}
return &message, nil
}
Service 示例
package services
import (
"errors"
"{{.ModulePath}}/internal/entities"
"{{.ModulePath}}/internal/repositories"
"github.com/lite-lake/litecore-go/common"
"github.com/lite-lake/litecore-go/manager/configmgr"
"github.com/lite-lake/litecore-go/manager/loggermgr"
)
type IMessageService interface {
common.IBaseService
CreateMessage(name string) (*entities.Message, error)
GetMessage(id string) (*entities.Message, error) // ID 类型为 string
}
type messageServiceImpl struct {
Config configmgr.IConfigManager `inject:""`
Repository repositories.IMessageRepository `inject:""`
LoggerMgr loggermgr.ILoggerManager `inject:""`
}
func NewMessageService() IMessageService {
return &messageServiceImpl{}
}
func (s *messageServiceImpl) ServiceName() string {
return "MessageService"
}
func (s *messageServiceImpl) OnStart() error {
return nil
}
func (s *messageServiceImpl) OnStop() error {
return nil
}
func (s *messageServiceImpl) CreateMessage(name string) (*entities.Message, error) {
if name == "" {
return nil, errors.New("名称不能为空")
}
message := &entities.Message{
Name: name,
// ID、CreatedAt、UpdatedAt 由 Hook 自动填充
}
if err := s.Repository.Create(message); err != nil {
return nil, err
}
s.LoggerMgr.Ins().Info("示例创建成功", "id", message.ID, "name", name)
return message, nil
}
func (s *messageServiceImpl) GetMessage(id string) (*entities.Message, error) {
return s.Repository.GetByID(id)
}
Controller 示例
package controllers
import (
"net/http"
"{{.ModulePath}}/internal/services"
"github.com/gin-gonic/gin"
"github.com/lite-lake/litecore-go/common"
"github.com/lite-lake/litecore-go/manager/loggermgr"
)
type IExampleController interface {
common.IBaseController
}
type exampleControllerImpl struct {
ExampleService services.IExampleService `inject:""`
LoggerMgr loggermgr.ILoggerManager `inject:""`
}
func NewExampleController() IExampleController {
return &exampleControllerImpl{}
}
func (c *exampleControllerImpl) ControllerName() string {
return "ExampleController"
}
func (c *exampleControllerImpl) GetRouter() string {
return "/api/examples [POST],/api/examples/:id [GET]"
}
func (c *exampleControllerImpl) Handle(ctx *gin.Context) {
method := ctx.Request.Method
if method == "POST" {
c.handleCreate(ctx)
} else if method == "GET" {
c.handleGet(ctx)
}
}
func (c *exampleControllerImpl) handleCreate(ctx *gin.Context) {
var req struct {
Name string `json:"name" binding:"required"`
}
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
example, err := c.ExampleService.CreateExample(req.Name)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, example)
}
func (c *exampleControllerImpl) handleGet(ctx *gin.Context) {
id := ctx.Param("id") // ID 类型为 string,直接使用,无需解析
example, err := c.ExampleService.GetExample(id)
if err != nil {
ctx.JSON(http.StatusNotFound, gin.H{"error": "示例不存在"})
return
}
ctx.JSON(http.StatusOK, example)
}
重要提示:
- Entity 使用
BaseEntityWithTimestamps基类,ID 类型为 string - Repository 中 ID 参数类型为 string,查询使用
Where("id = ?", id) - Service 中 ID 参数类型为 string
- Controller 中 ID 直接从路径参数获取,无需类型转换
- 时间戳由 GORM Hook 自动填充,无需在 Service 层手动设置
var _ IMessageRepository = (*messageRepositoryImpl)(nil)
#### Service 示例
```go
package services
import (
"github.com/lite-lake/litecore-go/common"
"github.com/lite-lake/litecore-go/internal/repositories"
)
type IMessageService interface {
common.IBaseService
}
type messageServiceImpl struct {
MessageRepo repositories.IMessageRepository `inject:""`
}
func NewMessageService() IMessageService {
return &messageServiceImpl{}
}
var _ IMessageService = (*messageServiceImpl)(nil)
Controller 示例
package controllers
import (
"github.com/lite-lake/litecore-go/common"
"github.com/lite-lake/litecore-go/internal/services"
"github.com/lite-lake/litecore-go/server/http"
)
type IMessageController interface {
common.IBaseController
}
type messageControllerImpl struct {
MessageService services.IMessageService `inject:""`
}
func NewMessageController() IMessageController {
return &messageControllerImpl{}
}
func (c *messageControllerImpl) GetRouter() http.Router {
return nil
}
var _ IMessageController = (*messageControllerImpl)(nil)
生成的文件
internal/application/
├── entity_container.go # 实体容器初始化
├── repository_container.go # 仓储容器初始化
├── service_container.go # 服务容器初始化
├── controller_container.go # 控制器容器初始化
├── middleware_container.go # 中间件容器初始化
├── listener_container.go # 监听器容器初始化
├── scheduler_container.go # 定时器容器初始化
└── engine.go # 引擎创建函数
使用生成的代码
package main
import (
"log"
app "github.com/example/project/internal/application"
)
func main() {
engine, err := app.NewEngine()
if err != nil {
log.Fatalf("Failed to create engine: %v", err)
}
if err := engine.Initialize(); err != nil {
log.Fatalf("Failed to initialize engine: %v", err)
}
if err := engine.Start(); err != nil {
log.Fatalf("Failed to start engine: %v", err)
}
engine.WaitForShutdown()
}
API 说明
generator.Config
type Config struct {
ProjectPath string // 项目路径
OutputDir string // 输出目录
PackageName string // 包名
ConfigPath string // 配置文件路径
}
主要函数
// 运行代码生成器
func Run(cfg *Config) error
// 运行代码生成器,失败时 panic
func MustRun(cfg *Config)
// 返回默认配置
func DefaultConfig() *Config
// 查找项目模块名
func FindModuleName(projectPath string) (string, error)
scaffold.Config
type Config struct {
ModulePath string // 模块路径
ProjectName string // 项目名称
OutputDir string // 输出目录
TemplateType TemplateType // 模板类型
Interactive bool // 是否交互式
LitecoreGoVer string // LiteCore Go 版本
}
type TemplateType string
const (
TemplateTypeBasic TemplateType = "basic"
TemplateTypeStandard TemplateType = "standard"
TemplateTypeFull TemplateType = "full"
)
工作流程
代码生成流程
- 扫描项目:解析器扫描
internal/目录下的各层组件 - 提取组件:提取接口定义、工厂函数
- 生成代码:构建器使用模板生成容器初始化代码
- 写入文件:将生成的代码写入输出目录
脚手架创建流程
- 创建目录结构:根据模板类型创建项目目录
- 生成配置文件:生成 go.mod、config.yaml 等
- 生成示例代码:根据模板类型生成示例组件
- 调用生成器:自动运行代码生成器
注意事项
- 不要手动修改生成的代码:所有生成的文件头部包含
// Code generated by litecore/cli. DO NOT EDIT.注释 - 接口命名:组件接口必须使用
I前缀(如IMessageService) - 工厂函数:工厂函数必须使用
New前缀(如NewMessageService) - 配置文件:配置文件必须存在且格式正确
- 模块路径:项目必须有 go.mod 文件,且能正确解析模块名
- 依赖注入:需要注入的依赖必须使用
inject:""标签,工厂函数不接受参数
完整示例
参考 samples/messageboard 项目,展示了完整的代码生成和使用流程:
# 进入示例项目
cd samples/messageboard
# 运行代码生成器
go run ../cli/main.go generate
# 查看生成的代码
ls internal/application/
# 运行应用
go run cmd/server/main.go
常见问题
Q: 为什么需要代码生成器?
A: LiteCore 采用 7 层依赖注入架构,手动编写容器初始化代码容易出错且维护困难。代码生成器自动化这一过程,确保代码的一致性和正确性。
Q: 生成的代码可以手动修改吗?
A: 不可以。所有生成的代码头部都包含 // Code generated by litecore/cli. DO NOT EDIT. 注释。如果需要修改,应该更新业务代码后重新生成。
Q: 如何更新生成的代码?
A: 修改业务代码(添加/删除组件)后,重新运行代码生成器即可。
Q: 支持哪些层级?
A: 支持 7 层架构:Entity、Repository、Service、Controller、Middleware、Listener、Scheduler。
Q: basic/standard/full 模板有什么区别?
A: basic 只包含基础结构,standard 包含配置文件和基础中间件,full 包含完整的示例代码。
Q: 代码生成器会影响性能吗?
A: 代码生成器仅在开发阶段运行,不影响生产环境的性能。
Q: 如何自定义输出目录?
A: 使用 --output 参数或修改 Config 的 OutputDir 字段。
Q: factory 函数为什么不接受参数?
A: LiteCore 的依赖注入机制会自动注入 inject:"" 标记的依赖,因此工厂函数不需要显式传入参数。
Documentation
¶
There is no documentation for this package.