借鉴了 DDD(领域驱动设计) 和 分层架构(Layered Architecture),在 Java/Spring 世界里用得很多,在 Go 里虽然倾向于简化,但在中大型项目里还是非常有价值的。 Golang 开发最佳实践中常见的 分层概念,即:
Controller(控制层)
Service(服务层 业务逻辑层)
Repository/DAO(数据访问层,通常也包括 Mapping)
DTO(Data Transfer Object,数据传输对象)
VO(Value Object,值对象 视图对象)
Mapping(对象映射,通常是 DTO/VO 与实体之间的转换)
这些概念主要下面我详细展开:
1. Controller(控制层)
作用:接收客户端请求,调用业务逻辑(Service),返回结果。
特点:
负责处理 HTTP 请求(通常结合 Gin、Echo 等框架)。
只做 请求解析、调用 service、返回响应,不写业务逻辑。
输入通常是
DTO
,输出通常是VO
或JSON Response
。示例:
func(c *UserController) Register(ctx *gin.Context) {var req dto.RegisterRequestif err := ctx.ShouldBindJSON(&req); err != nil{ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}user, err := c.userService.Register(req)if err != nil{ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}ctx.JSON(http.StatusOK, vo.UserVOFromEntity(user))}
2. Service(服务层 业务逻辑层)
作用:封装业务逻辑,是核心。
特点:
处理 业务规则(如注册时校验手机号是否存在、发送验证码、保存数据库)。
调用 Repository/DAO 进行数据库操作。
输入是
DTO
或Entity
,输出通常是Entity
。示例:
func(s *UserService) Register(req dto.RegisterRequest) (*entity.User, error) {// 校验是否已存在if s.userRepo.ExistsByEmail(req.Email) {return nil, errors.New("用户已存在")}user := entity.User{Email: req.Email,Phone: req.Phone,Nickname: req.Nickname,}if err := s.userRepo.Save(&user); err != nil {return nil, err}return &user, nil}
3. Repository DAO(数据访问层,含 Mapping)
作用:封装数据库操作。
特点:
与数据库打交道(GORM、SQL、MongoDB 等)。
提供接口,如
FindByID
、Save
、Delete
。与业务逻辑解耦,方便切换存储方式。
示例:
type UserRepository interface{Save(user *entity.User) errorFindByID(id uint) (*entity.User, error)ExistsByEmail(email string) bool}
4. DTO(Data Transfer Object,数据传输对象)
作用:请求体/传输数据。
特点:
用来接收前端请求的数据。
通常与前端交互,不直接使用
Entity
,避免暴露数据库字段。可以带有校验标签(如
binding:"required,email"
)。示例:
type RegisterRequest struct{Email string `json:"email" binding:"required,email"`Phone string`json:"phone" binding:"required"`Nickname string`json:"nickname" binding:"required"`}
5. VO(Value Object / View Object,值对象 / 视图对象)
作用:返回给前端的对象。
特点:
与前端展示需求对应。
不等于
Entity
,比如密码字段需要去掉,时间格式需要转成字符串。示例:
type UserVO struct{ID uint `json:"id"`Email string `json:"email"`Nickname string `json:"nickname"`JoinedAt string `json:"joined_at"`}func UserVOFromEntity (u *entity.User) UserVO {return UserVO{ID: u.ID,Email: u.Email,Nickname: u.Nickname,JoinedAt: u.CreatedAt.Format("2006-01-02 15:04:05"),}}
6. Mapping(对象映射)
作用:Entity <-> DTO <-> VO 的转换。
特点:
避免 Controller/Service 层写一堆赋值代码。
可以用工具(如 jinzhu/copier)简化。
示例:
func(req *RegisterRequest) ToEntity() entity.User {return entity.User{Email: req.Email,Phone: req.Phone,Nickname: req.Nickname,}}
推荐的目录结构
一个比较清晰的 Golang 分层目录 可以这样组织:
/project/controller// 控制器user_controller.go/service// 业务逻辑user_service.go/repository// 数据访问user_repository.go/entity// 数据库实体user.go/dto// 数据传输对象register_request.go/vo// 视图对象user_vo.go/mapping// 对象映射user_mapping.go
✅ 总结:
Controller:接收请求,调用 Service,返回响应。
Service:业务逻辑核心。
Repository:封装数据库访问。
DTO:请求数据对象。
VO:响应数据对象。
Mapping:DTO ↔ Entity ↔ VO 的转换工具。
这样分层的好处是:职责清晰、易于扩展、方便测试和维护。




