16-路由模型及处理函数探索

思考并回答以下问题:

实验介绍

本实验将介绍路由(Router)、模型(Model)以及处理函数(Handler),这是本次Gin框架项目实战的核心部分。通过本次实验,我们将学习到如何在Gin框架中编写路由以及对应的业务逻辑处理函数,对于模型该如何实现和应用。完成本次实验后,我们将能够在Gin框架中顺利的实现简单模型的增删改查的功能。

知识点

  • 路由
  • 模型
  • 处理函数

路由

回顾

我们在之前的Gin框架基础章节的控制器(Controller)以及路由(Router)实验中已经介绍了相关的基础知识。这里我们稍微回顾一下。

控制器是一个包含Gin上下文(Context)为参数的函数,路由是包含HTTP方法(Method)、控制器处理函数(HandlerFunction)的注册功能,如下是示例代码。

1
2
3
app.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello World!")
})

打开IDE,在之前实验的基础上增加一部分内容。

打开routes/user.go,输入以下内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package routes

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

// GetUsers 获取用户列表
func GetUsers(c *gin.Context) {
// TODO: implement me
}

// CreateEditUser 创建或更新用户
func CreateEditUser(c *gin.Context) {
// TODO: implement me
}

// DeleteUser 删除用户
func DeleteUser(c *gin.Context) {
// TODO: implement me
}

在这里,我们定义了用户的增删改查的基本路由函数,具体实现我们稍后再说。

然后,我们需要注册它们。打开main.go,加入控制器函数注册逻辑,即路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

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

func main() {
// 创建 Gin 引擎
app := gin.New()

// 注册路由
app.GET("/users", routes.GetUsers)
app.POST("/users", routes.CreateEditUser)
app.POST("/users/delete", routes.DeleteUser)

// 运行 Gin 引擎
app.Run(":8080")
}

在这里,我们使用了RESTfulAPI设计模式。

模型
接下来我们需要定义模型(Model)。模型通常是指应用程序中用于表示和处理数据的结构或对象。模型用于定义数据的结构、属性和行为,以及对数据执行的操作。在Gin框架中,模型是一个结构体(struct),它定义了应用程序中的数据实体。这些结构体通常与数据库中的表或其他外部数据源的实体相对应。

在Gin框架基础章节的数据库集成实验中,我们已经涉及了模型的定义。下面我们在实战练习中实现一下。

实战练习
在蓝桥云课IDE中打开models/user.go,输入以下内容。

1
2
3
4
5
6
7
8
package models

type User struct {
Id int `json:"id"` // 用户 ID
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
Role string `json:"role"` // 角色
}

这样我们就清楚的定义了用户模型。

处理函数
我们在本次项目中所指代的处理函数(Handlers)并不是之前说的控制器处理函数(ControllerHandlerFunction),而是指通常意义上的业务处理函数。在大型Web应用中,我们的模块系统较为复杂,因此需要对其进行分层(Layering)。而处理函数就是将控制器函数的核心业务逻辑抽象为处理函数层的一层模块,有时候我们会称这一层模块为业务层(BusinessLayer)。

实战练习
首先,我们将编写处理函数逻辑。

在蓝桥云课IDE中打开handlers/user.go,输入以下内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package handlers

import (
"errors"
"gin-project/models"
)

// 所有用户列表
var allUsers = []models.User{
{Id: 1, Username: "admin", Password: "password", Role: "admin"},
{Id: 2, Username: "user", Password: "password", Role: "user"},
}

// 当前用户 ID
var currentUserId = 2

// GetUsers 获取用户列表
func GetUsers(page, size int) (users []models.User) {
if page == 0 {
page = 1
}
if size == 0 {
size = 10
}
if page*size > len(allUsers) {
return allUsers[(page-1)*size:]
}
return allUsers[(page-1)*size : page*size]
}

// GetUserById 获取指定用户
func GetUserById(id int) (user *models.User, err error) {
for _, u := range allUsers {
if u.Id == id {
return &u, nil
}
}
return nil, errors.New("user not found")
}

// CreateUser 创建用户
func CreateUser(user *models.User) (id int, err error) {
currentUserId++
user.Id = currentUserId
for _, u := range allUsers {
if u.Id == user.Id {
return 0, errors.New("user already exists")
}
}
allUsers = append(allUsers, *user)
return user.Id, nil
}

// EditUser 更新指定用户
func EditUser(id int, user *models.User) (err error) {
for i, u := range allUsers {
if u.Id == id {
allUsers[i] = *user
return nil
}
}
return errors.New("user not found")
}

// DeleteUser 删除指定用户
func DeleteUser(id int) (err error) {
for i, u := range allUsers {
if u.Id == id {
allUsers = append(allUsers[:i], allUsers[i+1:]...)
return nil
}
}
return errors.New("user not found")
}

这里,我们定义了全局变量allUsers来存储所有用户。这相当于将用户数据存储在内存中,而不是在数据库,当然在生产环境中我们需要存到数据库,这里为了演示方便我们存储在内存中。关于如何与数据库进行集成,请参考Gin框架基础章节的数据库集成实验。此外,在上面的代码中,我们还定义了全局ID变量currentUserId,用作新创建用户的ID生成。

思考题:除了内存存储以外,上面代码在查询方面还有优化空间,而这一部分可以留给学员自己来思考如何进一步优化用户数据的查询。

好了,当我们创建好用户处理函数之后,我们需要将其集成到路由中。

在蓝桥云课IDE中打开routes/user.go,输入以下内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package routes

import (
"gin-project/handlers"
"gin-project/models"
"github.com/gin-gonic/gin"
"strconv"
)

// GetUsers 获取用户列表
func GetUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.Query("page"))
size, _ := strconv.Atoi(c.Query("size"))
users := handlers.GetUsers(page, size)
c.JSON(200, users)
}

// CreateEditUser 创建或编辑用户
func CreateEditUser(c *gin.Context) {
var user models.User
c.BindJSON(&user)
if user.Id > 0 {
// 更新用户
err := handlers.EditUser(user.Id, &user)
if err != nil {
c.JSON(404, gin.H{"error": err.Error()})
}
c.JSON(200, gin.H{"msg": "user updated"})
} else {
// 创建用户
id, err := handlers.CreateUser(&user)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(201, gin.H{"id": id})
}
}

// DeleteUser 删除用户
func DeleteUser(c *gin.Context) {
var user models.User
c.BindJSON(&user)
err := handlers.DeleteUser(user.Id)
if err != nil {
c.JSON(404, gin.H{"error": err.Error()})
}
c.JSON(200, gin.H{"msg": "user deleted"})
}

这样,我们就实现了处理函数的逻辑以及集成到路由。

完成后,我们可以通过终端运行gorunmain.go启动程序,可以看到如下日志。

如何验证用户的增删改查在本次实验中不再赘述,因为此前在数据库集成实验中有涉及。请学员通过ThunderClient来自行验证。

实验总结

本次实验介绍了如何在Gin框架中生成路由、模型以及处理函数,并通过实战练习实现了用户列表的增删改查接口。接下来的部分,我们将实现用户增删改查的界面,以及如何与后端进行交互。

0%