根据搜索结果和Go社区最佳实践,我为你整理了一份适合多前台系统后端的Go项目结构方案。考虑到你有Java背景,我会适当对比说明。
🏗️ Go HTTP服务项目结构最佳实践
一、核心设计原则
⚠️ Go与Java的重要区别
- Go强调 "少即是多",不要为了看起来专业而堆砌目录
- 先做出能跑的东西,再考虑拆包重构
internal/、pkg/、cmd/是工具,不是必须的模式
✅ 模块化优先:根据功能边界划分模块
✅ 标准布局:遵循Go社区约定
✅ 显式优于隐式:通过目录结构清晰表达代码关系二、推荐项目目录结构
your-project/
├── cmd/ # 【应用入口】类似Java的main类
│ └── server/
│ └── main.go # 程序启动入口
│
├── internal/ # 【私有业务代码】类似Java的src/main/java/com/xxx
│ ├── config/ # 配置加载与解析
│ │ └── config.go
│ ├── handler/ # 【HTTP处理器】类似Java的Controller
│ │ ├── user_handler.go
│ │ ├── order_handler.go
│ │ └── middleware/ # 中间件
│ │ ├── auth.go
│ │ └── cors.go
│ ├── service/ # 【业务逻辑层】类似Java的Service
│ │ ├── user_service.go
│ │ └── order_service.go
│ ├── repository/ # 【数据访问层】类似Java的DAO/Mapper
│ │ ├── user_repo.go
│ │ └── order_repo.go
│ ├── model/ # 【数据库实体】类似Java的Entity
│ │ ├── user.go
│ │ └── order.go
│ ├── dto/ # 【数据传输对象】类似Java的DTO
│ │ ├── request/ # 请求入参
│ │ │ ├── user_req.go
│ │ │ └── order_req.go
│ │ └── response/ # 响应出参
│ │ ├── user_resp.go
│ │ └── common_resp.go
│ ├── router/ # 【路由注册】类似Java的@Configuration + @RequestMapping
│ │ └── router.go
│ └── consts/ # 【常量定义】类似Java的Constants
│ ├── code.go # 业务状态码
│ └── msg.go # 提示信息
│
├── pkg/ # 【公共包】可被外部项目引用,类似Java的公共library
│ ├── logger/ # 日志封装
│ ├── utils/ # 工具函数
│ │ ├── encrypt.go
│ │ └── validate.go
│ └── errors/ # 自定义错误
│ └── errors.go
│
├── api/ # 【API定义】类似Java的OpenAPI/Swagger定义
│ ├── openapi.yaml
│ └── proto/ # 如果有gRPC
│ └── v1/
│
├── configs/ # 【配置文件】类似Java的application.yml
│ ├── config.yaml
│ ├── config.dev.yaml
│ └── config.prod.yaml
│
├── scripts/ # 【脚本文件】类似Java的Maven/Gradle脚本
│ ├── init-db.sh
│ └── deploy.sh
│
├── tests/ # 【集成测试】
│ └── integration/
│ └── user_test.go
│
├── docs/ # 【文档】
│ └── api.md
│
├── go.mod # 【模块定义】类似Java的pom.xml/build.gradle
├── go.sum # 依赖校验文件
├── Makefile # 构建脚本(可选)
└── README.md三、关键目录详解
1️⃣ cmd/ - 应用入口
go
// cmd/server/main.go
package main
import (
"your-project/internal/config"
"your-project/internal/router"
"your-project/pkg/logger"
)
func main() {
// 1. 加载配置
cfg := config.Load()
// 2. 初始化日志
logger.Init(cfg.Log)
// 3. 注册路由
r := router.Setup()
// 4. 启动服务
r.Run(":8080")
}💡 Java对比:相当于
SpringBootApplication主类
2️⃣ internal/ - 私有业务代码
⚠️ 重要:internal 目录下的包只能被当前项目内部引用,其他项目无法导入,这是Go的强制约定。
2.1 handler/ - HTTP处理器
go
// internal/handler/user_handler.go
package handler
import (
"github.com/gin-gonic/gin"
"your-project/internal/dto/request"
"your-project/internal/dto/response"
"your-project/internal/service"
)
type UserHandler struct {
userService *service.UserService
}
func (h *UserHandler) GetUser(c *gin.Context) {
// 1. 解析请求参数
var req request.GetUserReq
if err := c.ShouldBind(&req); err != nil {
response.Error(c, err)
return
}
// 2. 调用服务层
user, err := h.userService.GetByID(req.ID)
// 3. 返回响应
response.Success(c, user)
}💡 Java对比:相当于
@RestController
2.2 service/ - 业务逻辑层
go
// internal/service/user_service.go
package service
import (
"your-project/internal/model"
"your-project/internal/repository"
)
type UserService struct {
userRepo *repository.UserRepository
}
func (s *UserService) GetByID(id int64) (*model.User, error) {
// 业务逻辑处理
return s.userRepo.FindByID(id)
}💡 Java对比:相当于
@Service
2.3 repository/ - 数据访问层
go
// internal/repository/user_repo.go
package repository
import (
"gorm.io/gorm"
"your-project/internal/model"
)
type UserRepository struct {
db *gorm.DB
}
func (r *UserRepository) FindByID(id int64) (*model.User, error) {
var user model.User
err := r.db.First(&user, id).Error
return &user, err
}💡 Java对比:相当于
@Repository/ Mapper
2.4 model/ - 数据库实体
go
// internal/model/user.go
package model
import "time"
type User struct {
ID int64 `gorm:"primaryKey" json:"id"`
Username string `gorm:"uniqueIndex" json:"username"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}💡 Java对比:相当于
@Entity实体类
2.5 dto/ - 数据传输对象
go
// internal/dto/request/user_req.go
package request
type CreateUserReq struct {
Username string `json:"username" binding:"required,min=3,max=20"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=6"`
}
// internal/dto/response/user_resp.go
package response
type UserResp struct {
ID int64 `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
}
// 统一响应格式
type CommonResp struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}💡 Java对比:相当于 DTO/VO 类
2.6 router/ - 路由注册
go
// internal/router/router.go
package router
import (
"github.com/gin-gonic/gin"
"your-project/internal/handler"
"your-project/internal/handler/middleware"
)
func Setup() *gin.Engine {
r := gin.Default()
// 全局中间件
r.Use(middleware.CORS())
r.Use(middleware.Logger())
// API路由组
api := r.Group("/api/v1")
{
// 需要认证的路由
auth := api.Group("")
auth.Use(middleware.Auth())
{
// 用户相关
userHandler := &handler.UserHandler{}
auth.GET("/users/:id", userHandler.GetUser)
auth.POST("/users", userHandler.CreateUser)
// 订单相关
orderHandler := &handler.OrderHandler{}
auth.GET("/orders", orderHandler.ListOrders)
}
}
return r
}💡 Java对比:相当于
@Configuration+@RequestMapping
2.7 consts/ - 常量定义
go
// internal/consts/code.go
package consts
// 业务状态码
const (
CodeSuccess = 0
CodeInvalidParam = 400
CodeUnauthorized = 401
CodeForbidden = 403
CodeNotFound = 404
CodeInternalError = 500
)
// internal/consts/msg.go
package consts
// 提示信息
const (
MsgSuccess = "操作成功"
MsgInvalidParam = "参数错误"
MsgUnauthorized = "未授权"
)💡 Java对比:相当于
Constants常量类
3️⃣ pkg/ - 公共包
⚠️ 注意:pkg/ 下的代码可以被外部项目引用,放真正需要复用的代码。
pkg/
├── logger/ # 日志封装
├── utils/ # 工具函数
├── errors/ # 自定义错误
└── cache/ # 缓存封装go
// pkg/utils/encrypt.go
package utils
import "golang.org/x/crypto/bcrypt"
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}💡 Java对比:相当于公共
utilslibrary,可被其他项目依赖
4️⃣ configs/ - 配置文件
yaml
# configs/config.yaml
server:
port: 8080
mode: debug
database:
host: localhost
port: 3306
user: root
password: ${DB_PASSWORD}
dbname: mydb
log:
level: info
format: jsongo
// internal/config/config.go
package config
import "github.com/spf13/viper"
type Config struct {
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
Log LogConfig `mapstructure:"log"`
}
func Load() *Config {
viper.SetConfigFile("configs/config.yaml")
viper.ReadInConfig()
var cfg Config
viper.Unmarshal(&cfg)
return &cfg
}💡 Java对比:相当于
application.yml+@ConfigurationProperties
四、多前台系统适配建议
由于你要服务多个前台系统,建议:
方案1:按业务域划分路由前缀
/api/v1/app-a/users # A应用
/api/v1/app-b/users # B应用
/api/v1/app-c/users # C应用方案2:统一API + 不同权限
/api/v1/users # 统一接口通过 token 或 app_id 区分不同前台系统,在中间件中做权限控制。
方案3:多模块拆分(推荐大型项目)
your-project/
├── cmd/
│ ├── admin-server/ # 管理后台服务
│ ├── app-server/ # C端应用服务
│ └── open-api-server/ # 开放平台服务
├── internal/
│ ├── shared/ # 共享业务逻辑
│ ├── admin/ # 管理后台特有逻辑
│ └── app/ # C端应用特有逻辑五、新手建议
| 建议 | 说明 |
|---|---|
| 🎯 从小开始 | 初期可以简化结构,等业务复杂了再拆分 |
| 📦 善用go mod | 用 go mod init 初始化模块,自动管理依赖 |
| 🔧 选择合适框架 | 推荐 Gin 或 Echo |
| 🧪 写测试 | 每个 handler 和 service 都配单元测试 |
| 📖 读官方文档 | Go Modules |
六、推荐依赖
bash
# Web框架
go get github.com/gin-gonic/gin
# ORM
go get gorm.io/gorm
go get gorm.io/driver/mysql
# 配置管理
go get github.com/spf13/viper
# 日志
go get go.uber.org/zap
# 验证
go get github.com/go-playground/validator/v10
# 工具
go get github.com/google/uuid希望这个结构能帮助你快速上手!有任何具体问题欢迎继续提问 🚀