GO 入门小项目-博客-结合Gin Gorm

引言

在现代 Web 开发中,Go 语言以其高效、简洁和并发性能优异而受到广泛欢迎。Gin 是 Go 生态中最受欢迎的轻量级 Web 框架之一,它提供了高性能的路由、中间件支持以及灵活的 API 设计能力。本文将介绍如何使用 Gin 构建一个完整的博客系统,并结合 GORM 实现数据库操作,使用 JWT 实现用户认证。

bolg入门教程-github地址

复制代码
项目结构
为了提高代码的可维护性和模块化程度,我们将整个项目分为以下几个核心模块:
main.go:主程序入口,负责初始化数据库连接并启动 HTTP 服务器。
models/:存放数据模型,包括用户(User)、文章(Post)和评论(Comment)。
database/:负责数据库的初始化与连接管理。
handlers/:处理所有 HTTP 请求逻辑。
middleware/:实现 JWT 认证中间件。

数据库设计

我们使用 GORM 作为 ORM 工具来简化数据库操作。以下是三个主要的数据模型:

User 用户模型

Go 复制代码
type User struct {
	gorm.Model
	Username string `gorm:"unique;not null"`
	Password string `gorm:"not null"`
}

用户表包含用户名和密码字段,其中用户名是唯一的且不能为空。密码通过 bcrypt 加密存储

Post 文章模型

Go 复制代码
type Post struct {
	gorm.Model
	Title   string `gorm:"not null"`
	Content string `gorm:"not null"`
	UserID  uint
}

每篇文章都属于一个用户,通过 UserID 建立外键关联。

Comment 评论模型

Go 复制代码
type Comment struct {
	gorm.Model
	Content string `gorm:"not null"`
	UserID  uint
	PostID  uint
}

评论表记录评论内容、所属用户和对应的文章。

数据库连接与初始化

我们在 database/db.go 中封装了数据库的连接和初始化逻辑:

Go 复制代码
var DB *gorm.DB

func InitDB() {
	var err error
	DB, err = gorm.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/bolg?charset=utf8mb4&parseTime=True&loc=Local")
	if err != nil {
		panic("failed to connect database")
	}
	DB.AutoMigrate(&models.User{}, &models.Post{}, &models.Comment{})
}

这段代码实现了以下功能:

使用 GORM 连接 MySQL 数据库。

自动创建或更新数据表结构。

将数据库连接对象保存到全局变量 DB 中,供其他模块调用。

路由与业务逻辑

在 handlers/handlers.go 中,我们定义了所有的业务逻辑,包括用户注册、登录、文章发布、评论等操作。

用户注册

Go 复制代码
func RegisterUser(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		var user models.User
		if err := c.ShouldBindJSON(&user); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if err := user.SetPassword(c.PostForm("password")); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to set password"})
			return
		}
		db.Create(&user)
		c.JSON(http.StatusCreated, gin.H{"message": "User registered successfully"})
	}
}

该函数接收 JSON 格式的用户注册请求,验证输入后加密密码并保存到数据库。

用户登录

Go 复制代码
func LoginUser(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		var user models.User
		username := c.PostForm("username")
		password := c.PostForm("password")

		if err := db.Where("username = ?", username).First(&user).Error; err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
			return
		}

		if !user.CheckPassword(password) {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
			return
		}

		token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
			"user_id": user.ID,
			"exp":     time.Now().Add(time.Hour * 24).Unix(),
		})

		tokenString, err := token.SignedString([]byte("your-secret-key"))
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
			return
		}

		c.JSON(http.StatusOK, gin.H{"token": tokenString})
	}
}

登录成功后,生成 JWT Token 并返回给客户端,不了解jwt的可以看我上篇博客go引入jwt

创建文章

Go 复制代码
func CreatePost(c *gin.Context) {
	userID := c.GetUint("user_id")

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

	post.UserID = userID
	if err := db.Create(&post).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create post"})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"message": "Post created successfully", "post": post})
}

该函数会从上下文中获取当前用户的 ID,并将其设置为文章的作者。

认证中间件

我们使用 JWT 来实现用户身份验证,在 middleware/auth.go 中定义了一个中间件:

Go 复制代码
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenString := c.GetHeader("Authorization")
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization token"})
			c.Abort()
			return
		}

		token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
			return []byte("your-secret-key"), nil
		})

		if err != nil || !token.Valid {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
			c.Abort()
			return
		}

		claims := token.Claims.(jwt.MapClaims)
		userID := uint(claims["user_id"].(float64))
		c.Set("user_id", userID)
		c.Next()
	}
}

该中间件会在每次请求时验证 JWT Token 的有效性,并将用户 ID 存储在上下文中,供后续处理函数使用。

总结

本项目展示了如何使用 Gin 和 GORM 构建一个功能完善的博客系统。通过模块化的代码结构,我们实现了清晰的职责划分和良好的扩展性。JWT 的引入使得用户认证更加安全可靠,同时也为后续的功能扩展打下了基础。

如果你对该项目感兴趣,可以继续扩展以下功能:

分页查询文章列表

支持 Markdown 编辑器

添加文章分类与标签

实现点赞、收藏等社交功能

希望这篇技术博客能帮助你更好地理解 Gin 和 GORM 的使用,并激发你在 Web 开发领域的灵感!

相关推荐
cyc&阿灿27 分钟前
Java中extends与implements深度解析:继承与接口实现的本质区别
java·开发语言
liujing102329292 小时前
Day13_C语言基础&项目实战
c语言·开发语言
周振超的2 小时前
c++编译第三方项目报错# pragma warning( disable: 4273)
开发语言·c++
JH30733 小时前
Java Stream API 在企业开发中的实战心得:高效、优雅的数据处理
java·开发语言·oracle
呆呆的小草6 小时前
Cesium距离测量、角度测量、面积测量
开发语言·前端·javascript
uyeonashi6 小时前
【QT系统相关】QT文件
开发语言·c++·qt·学习
冬天vs不冷7 小时前
Java分层开发必知:PO、BO、DTO、VO、POJO概念详解
java·开发语言
sunny-ll7 小时前
【C++】详解vector二维数组的全部操作(超细图例解析!!!)
c语言·开发语言·c++·算法·面试
猎人everest8 小时前
Django的HelloWorld程序
开发语言·python·django
嵌入式@秋刀鱼8 小时前
《第四章-筋骨淬炼》 C++修炼生涯笔记(基础篇)数组与函数
开发语言·数据结构·c++·笔记·算法·链表·visual studio code