实践Golang语言N层应用架构

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,182元/月
可观测监控 Prometheus 版,每月50GB免费额度
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。

1 简介:

本文首先概述了N层体系结构的基本概念,说明了不同逻辑功能的应用程序如何被封装到不同的构件中。

接着,详细列出了在Go语言中对应的构件名称,包括前端框架(如Vue.js、React)替代Applet,Gin的处理函数和中间件对应Servlet,依赖注入和配置管理替代EJB容器,使用中间件管理会话对应SessionBean,以及使用ORM库(如gorm或ent)进行数据库交互对应EntityBean。

最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。

  • 回望N层体系结构

很多平台采用了多层分布式作为应用程序模型,比如J2EE平台实现不同逻辑功能的应用程序被封装到不同的构件中,处于不同层次的构件可被分别部署到不同的机器中。

question_ans.png

如下图是已完成N层体系结构,

客户端         Web               (EJB容器)       DB

浏览器      Web服务器         Simple 
                               Bean   -->      (EntityBean)  -->  ----
HTML        <--  JSP              --->              <---   |  |
(Applet)  -->   (Servlet) <---    (SessionBean)   <--          ----

    J2EE 的N层体系结构示意图。

在该平台的N层体系结构应用程序模型中,实现不同逻辑功能的应用程序被封装到不同的构件中,
比如浏览器 HTML对应构件Applet,JSP对应构件Servlet,EJB容器对应 Bean(包括Simple Bean,SessionBean),与数据库交互有EntityBean,这样对应用程序就有较好的整体一致性的开发体验,

2 实现N层体系结构

假如我们要在golang语言中利用Gin框架的构件实现N层结构,或者借助其他web开发框架对应构件,以下为go语言中对应的构件名称

  • Applet

在现代 web 开发中,Applet 已不再常用。
一般使用前端框架如 Vue.js、React 或 Angular 来实现类似的功能。
它们与服务器通过 RESTful API 进行交互。

  • Servlet

在go语言框架中,比如Gin 的处理函数(Handler)和中间件(Middleware)可以看作是 Servlet 的对应物。它们负责处理 HTTP 请求和生成响应。

  • EJB 容器。

Go 语言中没有直接对应的 EJB 容器,但 Gin 框架及其生态系统中有很多库和工具可以实现类似的功能。
例如:

Dependency Injection (DI):可以使用依赖注入库如 google/wire 或 uber/dig。
Configuration Management:可以使用 viper 来管理配置。
  • SessionBean

在 Gin 框架中,可以使用中间件来管理会话。
常用的会话中间件包括 gin-contrib/sessions,它可以处理会话数据的存储和管理。

  • EntityBean

对应于与数据库交互的 EntityBean,在 Go 语言中,常用 ORM 库如 gorm 或 ent 可以实现类似的功能。
它们提供了与数据库进行 CRUD 操作的方便方法。

3 go 语言N层体系实例:

实现 Handler(Servlet)

package main

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

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run() // listen and serve on 0.0.0.0:8080
}

实现 Session Management(SessionBean)

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/gin-contrib/sessions"
    "github.com/gin-contrib/sessions/cookie"
)

func main() {
    r := gin.Default()
    store := cookie.NewStore([]byte("secret"))
    r.Use(sessions.Sessions("mysession", store))

    r.GET("/session", func(c *gin.Context) {
        session := sessions.Default(c)
        var count int
        v := session.Get("count")
        if v == nil {
            count = 0
        } else {
            count = v.(int)
            count++
        }
        session.Set("count", count)
        session.Save()
        c.JSON(200, gin.H{"count": count})
    })

    r.Run(":8080")
}

4 实现数据库ORM操作实例 Database Interaction(EntityBean)

  • 使用gorm

          package main
    
          import (
              "github.com/gin-gonic/gin"
              "gorm.io/driver/sqlite"
              "gorm.io/gorm"
          )
    
          type User struct {
              ID   uint   `json:"id" gorm:"primaryKey"`
              Name string `json:"name"`
          }
    

创建ORM对象映射并操作数据

        func main() {
            db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
            if err != nil {
                panic("failed to connect database")
            }

    db.AutoMigrate(&User{})

    r := gin.Default()

    r.POST("/users", func(c *gin.Context) {
        var user User
        if err := c.ShouldBindJSON(&user); err == nil {
            db.Create(&user)
            c.JSON(200, user)
        } else {
            c.JSON(400, gin.H{"error": err.Error()})
        }
    })

    r.GET("/users/:id", func(c *gin.Context) {
        var user User
        if err := db.First(&user, c.Param("id")).Error; err != nil {
            c.JSON(404, gin.H{"error": "User not found"})
        } else {
            c.JSON(200, user)
        }
    })

    r.Run(":8080")
}

5 使用ent的ORM数据操作

  • 使用 ent

结合 ent 作为 ORM 的完整示例,包括处理 HTTP 请求(Servlet)、会话管理(SessionBean)和数据库交互(EntityBean)。

项目结构

myapp/
├── main.go
├── ent/
│   ├── generate.go
│   ├── schema/
│   │   └── user.go
go.mod

首先,初始化一个新的 Go 模块并添加所需的依赖:

go mod init myapp
go get github.com/gin-gonic/gin
go get github.com/gin-contrib/sessions
go get github.com/gin-contrib/sessions/cookie
go get entgo.io/ent
go get entgo.io/ent/entc
go get entgo.io/ent/dialect/sqlite
ent/schema/user.go

创建 User 数据模型:

package schema

import (
    "entgo.io/ent"
    "entgo.io/ent/schema/field"
)

type User struct {
    ent.Schema
}

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("name").NotEmpty(),
    }
}

func (User) Edges() []ent.Edge {
    return nil
}
ent/generate.go

生成 ent 代码:

package ent

//go:generate go run entgo.io/ent/cmd/ent generate ./schema

然后运行 go generate ./ent 生成代码。

main.go

在 main.go 中,设置 Gin 框架,配置会话管理,并实现 CRUD 操作:

package main

import (
    "context"
    "log"
    "net/http"

    "github.com/gin-contrib/sessions"
    "github.com/gin-contrib/sessions/cookie"
    "github.com/gin-gonic/gin"
    "entgo.io/ent/dialect/sqlite"
    "entgo.io/ent/dialect"
    "myapp/ent"
    _ "github.com/mattn/go-sqlite3"
)

func main() {

使用ent实例化数据库操作

    // Initialize ent client
    client, err := ent.Open(dialect.SQLite, "file:ent?mode=memory&cache=shared&_fk=1")
    if err != nil {
        log.Fatalf("failed opening connection to sqlite: %v", err)
    }
    defer client.Close()
    // Run the auto migration tool.
    if err := client.Schema.Create(context.Background()); err != nil {
        log.Fatalf("failed creating schema resources: %v", err)
    }

    r := gin.Default()

设置会话存储和数据库操作

    // Set up session store
    store := cookie.NewStore([]byte("secret"))
    r.Use(sessions.Sessions("mysession", store))

    // Routes
    r.POST("/users", func(c *gin.Context) {
        var user struct {
            Name string `json:"name"`
        }
        if err := c.ShouldBindJSON(&user); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        u, err := client.User.Create().SetName(user.Name).Save(context.Background())
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }
        c.JSON(http.StatusOK, u)
    })

    r.GET("/users/:id", func(c *gin.Context) {
        id := c.Param("id")
        u, err := client.User.Get(context.Background(), id)
        if err != nil {
            c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
            return
        }
        c.JSON(http.StatusOK, u)
    })

会话接口中实现了一个访问计数器,每次GET调用该接口将增加计数并保存到会话数据中。

    r.GET("/session", func(c *gin.Context) {
        session := sessions.Default(c)
        var count int
        v := session.Get("count")
        if v == nil {
            count = 0
        } else {
            count = v.(int)
            count++
        }
        session.Set("count", count)
        session.Save()
        c.JSON(http.StatusOK, gin.H{"count": count})
    })

    r.Run(":8080")
}

6 运行项目

确保所有依赖和生成的代码都已经准备好,然后运行应用:

go run main.go

现在,应用将在 http://localhost:8080 运行,可以使用 curl 或 Postman 等工具测试以下接口:

创建用户:POST /users
获取用户:GET /users/:id
会话管理:GET /session

7 小结

本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。

示例中使用了gorm和ent作为ORM工具,展示了如何创建用户、获取用户信息以及管理会话数据。最后,强调了运行项目的步骤,并总结了如何在Gin框架中结合ent实现N层体系结构的基本功能。

这两个示例展示了如何在 Gin 框架中使用ORM来处理数据库交互,同时实现会话管理和基本的 HTTP 请求处理,实际的项目开发中可能需要更深入更自由地使用SQL编写复杂的查询,相比ORM工具此时使用查询生成器更具有优势。

目录
相关文章
|
8天前
|
数据采集 监控 API
移动端性能监控探索:iOS RUM SDK 技术架构与实践
阿里云 RUM SDK 作为一款性能体验监控采集工具,可以作为辅助 App 运维的强有力助手,提升您的问题排查效率。
|
15天前
|
存储 运维 分布式计算
零售数据湖的进化之路:滔搏从Lambda架构到阿里云Flink+Paimon统一架构的实战实践
在数字化浪潮席卷全球的今天,传统零售企业面临着前所未有的技术挑战和转型压力。本文整理自 Flink Forward Asia 2025 城市巡回上海站,滔搏技术负责人分享了滔搏从传统 Lambda 架构向阿里云实时计算 Flink 版+Paimon 统一架构转型的完整实战历程。这不仅是一次技术架构的重大升级,更是中国零售企业拥抱实时数据湖仓一体化的典型案例。
|
1月前
|
数据采集 运维 数据可视化
AR 运维系统与 MES、EMA、IoT 系统的融合架构与实践
AR运维系统融合IoT、EMA、MES数据,构建“感知-分析-决策-执行”闭环。通过AR终端实现设备数据可视化,实时呈现温度、工单等信息,提升运维效率与生产可靠性。(238字)
|
10天前
|
存储 SQL 消息中间件
从 ClickHouse 到 StarRocks 存算分离: 携程 UBT 架构升级实践
查询性能实现从秒级到毫秒级的跨越式提升
|
1月前
|
数据采集 存储 运维
MyEMS:技术架构深度剖析与用户实践支持体系
MyEMS 是一款开源能源管理系统,采用分层架构设计,涵盖数据采集、传输、处理与应用全流程,支持多协议设备接入与多样化能源场景。系统具备高扩展性与易用性,结合完善的文档、社区、培训与定制服务,助力不同技术背景用户高效实现能源数字化管理,降低使用门槛与运维成本,广泛适用于工业、商业及公共机构等场景。
76 0
|
10天前
|
设计模式 前端开发 Java
《深入理解Spring》:Spring MVC架构深度解析与实践
Spring MVC是基于Spring框架的Web开发核心模块,实现Model-View-Controller设计模式。它通过DispatcherServlet统一调度请求,结合注解驱动的控制器、灵活的数据绑定与验证、丰富的视图支持及拦截器、异常处理等机制,提升开发效率与系统可维护性,助力构建高性能、易测试的现代Web应用。
|
19天前
|
人工智能 JavaScript 前端开发
GenSX (不一样的AI应用框架)架构学习指南
GenSX 是一个基于 TypeScript 的函数式 AI 工作流框架,以“函数组合替代图编排”为核心理念。它通过纯函数组件、自动追踪与断点恢复等特性,让开发者用自然代码构建可追溯、易测试的 LLM 应用。支持多模型集成与插件化扩展,兼具灵活性与工程化优势。
87 6
|
19天前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
72 1
|
1月前
|
人工智能 Cloud Native 中间件
划重点|云栖大会「AI 原生应用架构论坛」看点梳理
本场论坛将系统性阐述 AI 原生应用架构的新范式、演进趋势与技术突破,并分享来自真实生产环境下的一线实践经验与思考。
|
1月前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的&quot;神经网络&quot;,强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,

推荐镜像

更多