网站首页 > 技术文章 正文
每一篇文章只能属于一种分类。比如您写了一篇关于网络协议的文章,可以把它放入“网络”这个分类中。再比如您写了一篇关于程序设计相关的文章,而且内容包含了编程语言、数据库与部署程序使用的操作系统,应该归为哪个分类呢?像这种情况,就要看您这篇文章的主题更突出为哪个方向。而其它内容则可以打上相应的标签。Go语言编写个人博客系列文章后后续也会实现文章标签功能。
要实现文章分类,我们还是先从数据库模型(Go语言结构体)开始编写:
新建一个文件(models/category.go)并写入如下代码:
package models
import (
"gorm.io/gorm"
)
type Category struct {
gorm.Model
Name string `gorm:"type:varchar(63);not null" json:"name"`
}
修改(models/db.go)文件中的代码:
err = db.AutoMigrate(&User{}, &Article{}, &Image{}, &Category{})添加“&Category{}",此处的作用不再解释。
接下来我们在models/user.go文件中写一个获取用户角色的方法,代码如下:
func (u *User) GetRole() (int, error) {
if u.ID == 0 {
return 0, errors.New("用户不存在")
}
result := DB.Where("id = ?", u.ID).First(u)
if result.Error != nil {
return 0, result.Error
}
return u.Role, nil
}
这段代码我们定义了一个名为 GetRole 的方法,属于 User 结构体。目的是从数据库中获取特定用户的角色信息。
func (u *User) GetRole() (int, error) 这个方法没有参数(除了接收者 *User 本身),它返回两个值:用户的角色(int 类型)和一个可能发生的错误(error 类型)。
首先我们使用 if u.ID == 0 检查 User 结构体实例的 ID 字段是否为 0,如果 ID 为 0,则方法立即返回 0 和一个错误信息为 "用户不存在"。接着使用 result := DB.Where("id = ?", u.ID).First(u) 在数据库中查找 ID 字段值等于 u.ID 的第一个 User 记录,并将找到的记录的所有字段值填充到当前的 User 实例 u 中。再用 if 语句处理查询过程中可能发生的错误。最后返回用户角色和空值(nil)。
我们还需要在models/article.go的模型中添加到分类模型的关系,它们的关系从分类模型来说是一对多,一个分类对应多篇文章。反过来就是多对一,多篇文章属于一个分类。请看如下代码:
CategoryID uint `gorm:"not null" json:"category_id" form:"category_id"`
Category Category `gorm:"foreignKey:CategoryID"`
分类模型与文章模型的关联关系写好之后,我们去编写创建分类的代码,api/category.go
package api
import (
"errors"
"net/http"
"xblog/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// CreateCategory 创建新分类
func CreateCategory(c *gin.Context) {
// 从上下文中获取当前用户
currentUser, _ := c.Get("currentUser")
user, ok := currentUser.(*models.JwtClaims)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "无法获取用户认证信息"})
return
}
// 获取用户ID
userID := user.UserID
// 查询用户信息并获取用户角色,使用指针调用 GetRole 方法
var userObj models.User
result := models.DB.Where("id = ?", userID).First(&userObj)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
} else if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error})
return
}
role, err := userObj.GetRole()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 检查用户角色,只有为 1 时才有权限
if role != 1 {
c.JSON(http.StatusForbidden, gin.H{"error": "无权创建分类"})
return
}
// 初始化 Category 结构体
var category models.Category
// 绑定请求体到 Category 结构体
if err := c.ShouldBindJSON(&category); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
return
}
// 保存分类到数据库
if result := models.DB.Create(&category); result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
return
}
// 返回创建的分类
c.JSON(http.StatusOK, gin.H{"category": category})
}
定义一个名为 CreateCategory 的函数,它是一个用于创建新分类的 HTTP API。
首先,从 Gin 上下文 c 中获取当前用户。接着检查 currentUser 是否为 *models.JwtClaims 类型的实例。如果不是,返回一个 401 Unauthorized 状态的 HTTP 响应,并附带错误信息 "无法获取用户认证信息"。从 JwtClaims 实例中获取用户ID。下一步查询数据库,以获取用户ID对应的用户记录,并将查询结果填充到 userObj 实例中。如果查询失败(例如,找不到该用户或数据库错误),返回适当的 HTTP 响应并附带错误信息。调用 userObj.GetRole() 方法获取用户角色。如果获取过程中出错,返回 500 Internal Server Error 状态的 HTTP 响应,并附带错误信息。if role != 1 只有用户角色为 1(表示管理员)时,用户才被允许创建新分类。否则,返回 403 Forbidden 状态的 HTTP 响应,并附带错误信息 "无权创建分类"。
创建一个新的 models.Category 实例,并尝试将请求体(应该是一个 JSON 对象)绑定到这个实例。如果绑定过程中出错,返回 500 Internal Server Error 状态的 HTTP 响应,并附带错误信息。使用 Create 方法将新的分类记录保存到数据库。如果保存过程中出错,返回 500 Internal Server Error 状态的 HTTP 响应,并附带错误信息。新分类被成功创建并保存到数据库,返回 200 OK 状态的 HTTP 响应,并在响应体中返回新创建的分类记录。
最后在受保护的路由组中添加创建分类路由。
protected.POST("category/create", api.CreateCategory)
好,完成了文章分类功能,我去验证一下。
根据图片能看出我们新增分类“网络”已经成功写入数据库。新添加的文章也成功关联到了category_id。
猜你喜欢
- 2024-09-09 混合云资产管理项目(二)(混合云存储产品有哪些)
- 2024-09-09 Go语言进阶之Go语言高性能Web框架Iris项目实战-完善用户管理EP04
- 2024-09-09 数据库与 Go 的交互(go数据库和kegg数据库)
- 2024-09-09 七爪源码:N+1 查询如何烧毁您的数据库
- 2024-09-09 Go的安全编程和防御性编程(防止代码注入)
- 2024-09-09 Vue3+Go 仿抖音项目架构设计与实现
- 2024-09-09 腾讯Go安全指南(腾讯官网最新安全公告)
- 2024-09-09 Grails指南24查询高阶(grails中文参考手册)
- 2024-09-09 Redis优化高并发下的秒杀性能(redis秒杀高并发代码)
- 2024-09-09 Golang database/sql源码分析(golang sqlmock)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)