快速开始
5 分钟快速上手 Bamboo Base Go
快速开始
本指南将帮助你快速搭建一个基于 Bamboo Base Go 的 Web 服务。
安装
# 按需安装对应层级模块
go get github.com/bamboo-services/bamboo-base-go/defined
go get github.com/bamboo-services/bamboo-base-go/common
go get github.com/bamboo-services/bamboo-base-go/major
go get github.com/bamboo-services/bamboo-base-go/plugins/grpc # 可选项目结构
推荐的项目结构:
your-project/
├── main.go # 入口文件
├── .env # 环境变量配置
├── api/ # API 请求/响应结构定义
│ └── user/
│ └── user.go
├── internal/
│ ├── app/
│ │ ├── middleware/ # 中间件
│ │ ├── route/ # 路由注册
│ │ └── startup/ # 启动初始化
│ ├── entity/ # 数据库实体
│ ├── handler/ # HTTP 处理器
│ └── logic/ # 业务逻辑层
└── go.mod环境配置
创建 .env 文件:
# 调试模式
XLF_DEBUG=true
# 服务配置
XLF_HOST=localhost
XLF_PORT=8080
# gRPC 配置(可选)
GRPC_PORT=1119
GRPC_REFLECTION=false
# 数据库配置
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASS=your_password
DATABASE_NAME=your_database
DATABASE_PREFIX=app_
DATABASE_TIMEZONE=Asia/Shanghai
# Redis 配置
NOSQL_HOST=localhost
NOSQL_PORT=6379
NOSQL_PASS=
NOSQL_DATABASE=0
NOSQL_POOL_SIZE=10
# 雪花算法配置(可选,默认自动生成)
SNOWFLAKE_DATACENTER_ID=1
SNOWFLAKE_NODE_ID=1入口文件
package main
import (
"context"
xCtx "github.com/bamboo-services/bamboo-base-go/defined/context"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
xMain "github.com/bamboo-services/bamboo-base-go/major/main"
xReg "github.com/bamboo-services/bamboo-base-go/major/register"
xRegNode "github.com/bamboo-services/bamboo-base-go/major/register/node"
"your-project/internal/app/startup"
"your-project/internal/app/route"
)
func main() {
// 1. 初始化 bamboo-base-go 核心组件(传入自定义节点)
reg := xReg.Register(context.Background(), []xRegNode.RegNodeList{
{Key: xCtx.DatabaseKey, Node: startup.InitDatabase},
{Key: xCtx.RedisClientKey, Node: startup.InitRedis},
})
log := xLog.WithName(xLog.NamedMAIN)
// 2. 交由 Runner 托管服务生命周期(路由注册 + 启动 + 优雅关闭)
xMain.Runner(reg, log, route.NewRoute)
}可选:HTTP + gRPC 一体化启动
当服务同时暴露 HTTP 与 gRPC 接口时,可将 gRPC 任务函数直接挂入 xMain.Runner:
需要额外引入 gRPC 运行时相关包:
import (
xGrpcInterface "github.com/bamboo-services/bamboo-base-go/plugins/grpc/interceptor"
xGrpcRunner "github.com/bamboo-services/bamboo-base-go/plugins/grpc/runner"
"google.golang.org/grpc"
)grpcTask := xGrpcRunner.New(
xGrpcRunner.WithLogger(xLog.WithName(xLog.NamedGRPC)),
xGrpcRunner.WithRegisterService(func(ctx context.Context, server grpc.ServiceRegistrar) {
// 注册你的 gRPC Service
}),
xGrpcRunner.WithUnaryInterceptors(
xGrpcInterface.Recover(),
xGrpcInterface.InitContext(reg.Init.Ctx),
xGrpcInterface.ResponseBuilder(),
),
)
xMain.Runner(reg, log, route.NewRoute, grpcTask)完整说明参见:gRPC 运行时
业务初始化
数据库和 Redis 通过节点化系统注入,通常放在 startup 包中实现:
package startup
import (
"context"
"log/slog"
"strings"
xEnv "github.com/bamboo-services/bamboo-base-go/defined/env"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
"your-project/internal/entity"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
// 需要自动迁移的数据表
var migrateTables = []interface{}{
&entity.User{},
}
// InitDatabase 数据库初始化节点
func InitDatabase(ctx context.Context) (any, error) {
log := xLog.WithName(xLog.NamedINIT)
log.Debug(ctx, "正在连接数据库...")
// 构建 DSN
dsn := strings.Builder{}
dsn.WriteString("host=")
dsn.WriteString(xEnv.GetEnvString(xEnv.DatabaseHost, "localhost"))
dsn.WriteString(" user=")
dsn.WriteString(xEnv.GetEnvString(xEnv.DatabaseUser, "postgres"))
dsn.WriteString(" password=")
dsn.WriteString(xEnv.GetEnvString(xEnv.DatabasePass, ""))
dsn.WriteString(" dbname=")
dsn.WriteString(xEnv.GetEnvString(xEnv.DatabaseName, "postgres"))
dsn.WriteString(" port=")
dsn.WriteString(xEnv.GetEnvString(xEnv.DatabasePort, "5432"))
dsn.WriteString(" sslmode=disable")
db, err := gorm.Open(postgres.Open(dsn.String()), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
TablePrefix: xEnv.GetEnvString(xEnv.DatabasePrefix, "app_"),
SingularTable: true,
},
Logger: xLog.NewSlogLogger(slog.Default().WithGroup(xLog.NamedREPO), xLog.GormLoggerConfig{
SlowThreshold: 200,
LogLevel: xLog.LevelInfo,
IgnoreRecordNotFoundError: true,
}),
})
if err != nil {
return nil, err
}
// 自动迁移
_ = db.AutoMigrate(migrateTables...)
log.Info(ctx, "数据库连接成功")
// 返回值将被存入上下文
return db, nil
}Redis 初始化
package startup
import (
"context"
xEnv "github.com/bamboo-services/bamboo-base-go/defined/env"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
"github.com/redis/go-redis/v9"
)
// InitRedis Redis 初始化节点
func InitRedis(ctx context.Context) (any, error) {
log := xLog.WithName(xLog.NamedINIT)
log.Debug(ctx, "正在连接 Redis...")
rdb := redis.NewClient(&redis.Options{
Addr: xEnv.GetEnvString(xEnv.NoSqlHost, "localhost") + ":" + xEnv.GetEnvString(xEnv.NoSqlPort, "6379"),
Password: xEnv.GetEnvString(xEnv.NoSqlPass, ""),
DB: xEnv.GetEnvInt(xEnv.NoSqlDatabase, 0),
PoolSize: xEnv.GetEnvInt(xEnv.NoSqlPoolSize, 10),
})
log.Info(ctx, "Redis 连接成功")
// 返回值将被存入上下文
return rdb, nil
}实体定义
package entity
import (
xModels "github.com/bamboo-services/bamboo-base-go/major/models"
xSnowflake "github.com/bamboo-services/bamboo-base-go/common/snowflake"
)
// User 用户实体
type User struct {
xModels.BaseEntity // 继承基础实体(ID、CreatedAt、UpdatedAt)
Username string `gorm:"type:varchar(64);uniqueIndex" json:"username"`
Email string `gorm:"type:varchar(128);uniqueIndex" json:"email"`
Password string `gorm:"type:varchar(256)" json:"-"`
}
// GetGene 返回用户基因,用于雪花 ID 生成
func (u *User) GetGene() xSnowflake.Gene {
return xSnowflake.GeneUser
}路由注册
package route
import (
xMiddle "github.com/bamboo-services/bamboo-base-go/major/middleware"
xReg "github.com/bamboo-services/bamboo-base-go/major/register"
xRoute "github.com/bamboo-services/bamboo-base-go/major/route"
"your-project/internal/handler"
)
func NewRoute(xReg *xReg.Reg) {
engine := xReg.Serve
// 全局异常处理
engine.NoMethod(xRoute.NoMethod)
engine.NoRoute(xRoute.NoRoute)
// 全局中间件
engine.Use(xMiddle.ResponseMiddleware)
engine.Use(xMiddle.ReleaseAllCors)
engine.Use(xMiddle.AllowOption)
// API 路由组
api := engine.Group("/api/v1")
{
userHandler := handler.NewUserHandler()
// 用户路由
user := api.Group("/user")
user.POST("/register", userHandler.Register)
user.POST("/login", userHandler.Login)
}
}Handler 编写
package handler
import (
xError "github.com/bamboo-services/bamboo-base-go/common/error"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
xResult "github.com/bamboo-services/bamboo-base-go/major/result"
xUtil "github.com/bamboo-services/bamboo-base-go/common/utility"
"github.com/gin-gonic/gin"
apiUser "your-project/api/user"
"your-project/internal/logic"
)
type UserHandler struct {
log *xLog.LogNamedLogger
}
func NewUserHandler() *UserHandler {
return &UserHandler{
log: xLog.WithName(xLog.NamedCONT),
}
}
// Register 用户注册
func (h *UserHandler) Register(c *gin.Context) {
h.log.Info(c, "开始处理用户注册请求")
// 1. 验证并绑定数据
req := xUtil.BindData(c, &apiUser.RegisterRequest{})
if req == nil {
return
}
// 2. 调用业务逻辑(通过上下文获取资源)
user, xErr := logic.NewUserLogic().CreateUser(c, req.Username, req.Email, req.Password)
if xErr != nil {
_ = c.Error(xErr) // 传递给错误中间件处理
return
}
// 3. 返回成功响应
xResult.SuccessHasData(c, "注册成功", user)
}
// Login 用户登录
func (h *UserHandler) Login(c *gin.Context) {
h.log.Info(c, "开始处理用户登录请求")
req := xUtil.BindData(c, &apiUser.LoginRequest{})
if req == nil {
return
}
// 查找用户
user, xErr := logic.NewUserLogic().GetUserByUsername(c, req.Username)
if xErr != nil {
_ = c.Error(xErr)
return
}
// 验证密码
if !logic.NewUserLogic().VerifyPassword(user.Password, req.Password) {
// 创建错误并传递给中间件
_ = c.Error(xError.NewError(c.Request.Context(), xError.Unauthorized, "用户名或密码错误", false))
return
}
xResult.SuccessHasData(c, "登录成功", user)
}Logic 层编写
package logic
import (
xError "github.com/bamboo-services/bamboo-base-go/common/error"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
xUtil "github.com/bamboo-services/bamboo-base-go/common/utility"
xCtxUtil "github.com/bamboo-services/bamboo-base-go/common/utility/context"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"your-project/internal/entity"
)
type UserLogic struct {
log *xLog.LogNamedLogger
}
func NewUserLogic() *UserLogic {
return &UserLogic{
log: xLog.WithName(xLog.NamedLOGC),
}
}
// CreateUser 创建用户
func (l *UserLogic) CreateUser(c *gin.Context, username, email, password string) (*entity.User, *xError.Error) {
l.log.Info(c, "开始创建用户")
// 从上下文获取数据库连接
ctx := c.Request.Context()
db := xCtxUtil.MustGetDB(ctx)
// 检查用户名是否存在
var count int64
db.Model(&entity.User{}).Where("username = ?", username).Count(&count)
if count > 0 {
return nil, xError.NewError(c.Request.Context(), xError.Existed, "用户名已存在", false)
}
// 加密密码
hashedPassword, err := xUtil.HashPassword(password)
if err != nil {
return nil, xError.NewInternalServerError(c.Request.Context(), "密码加密失败", err)
}
// 生成雪花 ID(从上下文获取节点)
userID := xCtxUtil.MustGenerateGeneSnowflakeID(ctx, entity.User{}.GetGene())
user := &entity.User{
Username: username,
Email: email,
Password: hashedPassword,
}
user.ID = userID
if err := db.Create(user).Error; err != nil {
return nil, xError.NewInternalServerError(c.Request.Context(), "创建用户失败", err)
}
return user, nil
}
// GetUserByUsername 根据用户名获取用户
func (l *UserLogic) GetUserByUsername(c *gin.Context, username string) (*entity.User, *xError.Error) {
// 从上下文获取数据库连接
db := xCtxUtil.MustGetDB(c.Request.Context())
var user entity.User
if err := db.Where("username = ?", username).First(&user).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, xError.NewError(c.Request.Context(), xError.UserNotFound, "用户不存在", false, err)
}
return nil, xError.NewInternalServerError(c.Request.Context(), "查询用户失败", err)
}
return &user, nil
}
// VerifyPassword 验证密码
func (l *UserLogic) VerifyPassword(hashedPassword, password string) bool {
return xUtil.VerifyPassword(password, hashedPassword) == nil
}API 结构定义
package user
import "your-project/internal/entity"
// RegisterRequest 注册请求
type RegisterRequest struct {
Username string `json:"username" binding:"required,min=3,max=32"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=6"`
}
// LoginRequest 登录请求
type LoginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
// UserResponse 用户响应
type UserResponse struct {
*entity.User
Token string `json:"token,omitempty"`
}运行项目
# 启动服务
go run main.go启动成功后,你将看到类似输出:
2024-01-15 10:00:00 [INFO] [INIT] 初始化系统上下文
2024-01-15 10:00:00 [INFO] [INIT] 数据库连接成功
2024-01-15 10:00:00 [INFO] [INIT] Redis 连接成功
2024-01-15 10:00:00 [INFO] [MAIN] 服务器启动成功 addr=http://localhost:8080测试接口
# 注册用户
curl -X POST http://localhost:8080/api/v1/user/register \
-H "Content-Type: application/json" \
-d '{"username":"test","email":"test@example.com","password":"123456"}'
# 用户登录
curl -X POST http://localhost:8080/api/v1/user/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"123456"}'