1 简介:
本文首先概述了N层体系结构的基本概念,说明了不同逻辑功能的应用程序如何被封装到不同的构件中。
接着,详细列出了在Go语言中对应的构件名称,包括前端框架(如Vue.js、React)替代Applet,Gin的处理函数和中间件对应Servlet,依赖注入和配置管理替代EJB容器,使用中间件管理会话对应SessionBean,以及使用ORM库(如gorm或ent)进行数据库交互对应EntityBean。
最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
- 回望N层体系结构
很多平台采用了多层分布式作为应用程序模型,比如J2EE平台实现不同逻辑功能的应用程序被封装到不同的构件中,处于不同层次的构件可被分别部署到不同的机器中。
如下图是已完成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工具此时使用查询生成器更具有优势。