服务的UBD架构示例

举报
码乐 发表于 2024/11/20 18:43:45 2024/11/20
【摘要】 1 简介三层架构(UBD)就是为了符合"高内聚,低耦合“思想、把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构。在使用 Gin 实现三层架构的 Web 服务时,可以通过分层设计的方式,将功能模块划分为 表示层 (UI)、业务逻辑层 (BLL) 和 数据访问层 (DAL),从而实现高内聚、低耦合的架构。这种设计不仅便于代码维护,还能提升可扩展性和可测试...

1 简介

三层架构(UBD)就是为了符合"高内聚,低耦合“思想、把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构。

在使用 Gin 实现三层架构的 Web 服务时,可以通过分层设计的方式,将功能模块划分为 表示层 (UI)、业务逻辑层 (BLL) 和 数据访问层 (DAL),从而实现高内聚、低耦合的架构。
这种设计不仅便于代码维护,还能提升可扩展性和可测试性。

2 三层架构设计

  • 表示层 (UI)

负责处理 HTTP 请求和响应。
与客户端交互,通过调用业务逻辑层完成具体功能。
例如:路由控制器。

  • 业务逻辑层 (BLL)

负责业务逻辑处理。
接收表示层的请求,完成业务校验和处理逻辑。
调用数据访问层进行数据存取。

  • 数据访问层 (DAL)

与数据库直接交互。
负责执行 SQL 查询或通过 ORM 操作数据库。

3 go 的三层架构实现

目录结构.以下是一个示例的目录结构:

    project/
    ├── controllers/         // 表示层
    │   ├── user_controller.go
    ├── services/            // 业务逻辑层
    │   ├── user_service.go
    ├── models/              // 数据访问层
    │   ├── user_model.go
    ├── routes/              // 路由管理
    │   ├── routes.go
    ├── main.go              // 程序入口
    1. 数据访问层 (DAL)

负责定义数据模型和数据库操作逻辑,使用 GORM 操作数据库。

文件:models/user_model.go

  package models

  import (
      "errors"
      "gorm.io/gorm"
  )

  var db *gorm.DB // 假设已在 main.go 中初始化数据库连接

  // User 模型
  type User struct {
      ID    uint   `gorm:"primaryKey"`
      Name  string `gorm:"type:varchar(100)"`
      Email string `gorm:"type:varchar(100);unique"`
      Age   int    `gorm:"type:int"`
  }

  // 查询用户
  func GetUserByID(id uint) (*User, error) {
      var user User
      if err := db.First(&user, id).Error; err != nil {
          if errors.Is(err, gorm.ErrRecordNotFound) {
              return nil, nil // 用户不存在
          }
          return nil, err
      }
      return &user, nil
  }

  // 创建用户
  func CreateUser(user *User) error {
      return db.Create(user).Error
  }
    1. 业务逻辑层 (BLL)

负责处理业务逻辑,如数据校验、业务规则等。

文件:services/user_service.go

  package services

  import (
      "errors"
      "myapp/models"
  )

  // 创建用户业务逻辑
  func CreateUser(name, email string, age int) error {
      // 检查邮箱是否已经存在
      existingUser, _ := models.GetUserByID(1) // 示例:通过 Email 查询是否存在(未实现)
      if existingUser != nil {
          return errors.New("email already exists")
      }

      // 创建用户
      user := &models.User{Name: name, Email: email, Age: age}
      return models.CreateUser(user)
  }

  // 获取用户业务逻辑
  func GetUser(id uint) (*models.User, error) {
      user, err := models.GetUserByID(id)
      if err != nil {
          return nil, err
      }
      if user == nil {
          return nil, errors.New("user not found")
      }
      return user, nil
  }
    1. 表示层 (UI)

负责处理 HTTP 请求,调用业务逻辑层,并返回结果。

文件:controllers/user_controller.go

package controllers

import (
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"
    "myapp/services"
)

// 获取用户
func GetUser(c *gin.Context) {
    idParam := c.Param("id")
    id, err := strconv.Atoi(idParam)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
        return
    }

    user, err := services.GetUser(uint(id))
    if err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
        return
    }

    c.JSON(http.StatusOK, user)
}

// 创建用户
func CreateUser(c *gin.Context) {
    var input struct {
        Name  string `json:"name" binding:"required"`
        Email string `json:"email" binding:"required,email"`
        Age   int    `json:"age" binding:"required"`
    }

    if err := c.ShouldBindJSON(&input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    err := services.CreateUser(input.Name, input.Email, input.Age)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "User created successfully"})
}
    1. 路由管理

将路由注册与处理逻辑分离,便于维护。

文件:routes/routes.go

  package routes

  import (
      "github.com/gin-gonic/gin"
      "myapp/controllers"
  )

  func RegisterRoutes(r *gin.Engine) {
      userRoutes := r.Group("/users")
      {
          userRoutes.GET("/:id", controllers.GetUser)   // 获取用户
          userRoutes.POST("/", controllers.CreateUser)  // 创建用户
      }
  }
    1. 主入口文件

启动 Gin 服务并注册路由。

文件:main.go

  import (
      "github.com/gin-gonic/gin"
      "gorm.io/driver/mysql"
      "gorm.io/gorm"
      "myapp/routes"
  )

  func main() {
      // 初始化数据库连接
      dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
      db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
      if err != nil {
          panic("failed to connect to database")
      }
      models.db = db // 给模型层赋值数据库连接

      // 初始化 Gin 路由
      r := gin.Default()

      // 注册路由
      routes.RegisterRoutes(r)

      // 启动服务
      r.Run(":8080")
  }

4 架构特点分析

三层架构的优点,高内聚,低耦合

各层职责明确,业务逻辑与数据操作分离,方便扩展和维护。

  • 易于测试

每层都可以独立进行单元测试(例如测试服务层的业务逻辑)。

  • 可扩展性

方便添加新功能,如更换数据库或新增业务逻辑。

  • 清晰的代码结构

逻辑清晰,便于团队协作。通过三层架构设计,可以构建一个安全、高效且易维护的 Web 服务。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。