15分钟学 Go 实践项目二:打造博客系统

news2024/11/7 4:50:38

打造博客系统

项目概述

在本项目中,我们将创建一个简单的博客系统,重点实现CRUD(创建、读取、更新、删除)操作和用户管理。这个博客系统将使用户能够发布文章,评论,并管理其个人账户信息。

目标

  1. 实现用户注册、登录、注销功能。
  2. 用户能够创建、查看、更新和删除自己的博客文章。
  3. 实现基本的评论功能。
  4. 使用Go语言的标准库和框架,实现项目结构化管理。

技术栈

  • 编程语言:Go
  • Web框架:Gin
  • 数据库:GORM(Go ORM)
  • 数据库:SQLite(用于简化操作)

系统架构与流程图

以下是该系统的基本架构流程图:

[用户输入] --> [前端页面] --> [Gin路由] --> [控制器] --> [GORM ORM] --> [数据库]

我们将使用Gin作为HTTP框架,GORM作为ORM框架连接至SQLite数据库。

数据库设计

数据表设计

表名字段类型描述
usersidINTEGER用户ID(主键,自增)
usernameVARCHAR(50)用户名(唯一)
passwordVARCHAR(255)密码(哈希)
emailVARCHAR(100)邮箱(唯一)
blogsidINTEGER博客ID(主键,自增)
user_idINTEGER用户ID(外键)
titleVARCHAR(100)博客标题
contentTEXT博客内容
created_atDATETIME创建时间
updated_atDATETIME更新时间
commentsidINTEGER评论ID(主键,自增)
blog_idINTEGER博客ID(外键)
user_idINTEGER用户ID(外键)
contentTEXT评论内容
created_atDATETIME创建时间

数据库初始化

创建一个名为blog_system.db的SQLite数据库,并使用以下代码初始化:

package main

import (
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"log"
)

type User struct {
	ID       uint   `gorm:"primaryKey"`
	Username string `gorm:"unique"`
	Password string
	Email    string `gorm:"unique"`
}

type Blog struct {
	ID        uint   `gorm:"primaryKey"`
	UserID    uint
	Title     string
	Content   string
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Comment struct {
	ID        uint   `gorm:"primaryKey"`
	BlogID    uint
	UserID    uint
	Content   string
	CreatedAt time.Time
}

func InitDB() *gorm.DB {
	db, err := gorm.Open(sqlite.Open("blog_system.db"), &gorm.Config{})
	if err != nil {
		log.Fatalf("failed to connect database: %v", err)
	}
	db.AutoMigrate(&User{}, &Blog{}, &Comment{})
	return db
}

用户管理模块

用户注册

// 注册用户
func Register(db *gorm.DB, username, password, email string) error {
	user := User{Username: username, Password: HashPassword(password), Email: email}
	if err := db.Create(&user).Error; err != nil {
		return err
	}
	return nil
}

用户登录

// 登录用户
func Login(db *gorm.DB, username, password string) (*User, error) {
	var user User
	if err := db.Where("username = ?", username).First(&user).Error; err != nil {
		return nil, err
	}
	if !CheckPasswordHash(password, user.Password) {
		return nil, fmt.Errorf("incorrect password")
	}
	return &user, nil
}

用户注销

用户可以通过服务端清除session实现注销,这里简单演示。

// 注销用户
func Logout(c *gin.Context) {
	session := sessions.Default(c)
	session.Clear()
	session.Save()
	c.JSON(http.StatusOK, gin.H{"message": "logged out"})
}

博客操作模块

创建博客

// 创建博客
func CreateBlog(c *gin.Context) {
	var blog Blog
	if err := c.ShouldBindJSON(&blog); err != nil {
		c.JSON(http.StatusBadRequest, err)
		return
	}
	blog.CreatedAt = time.Now()
	blog.UpdatedAt = time.Now()
	if err := db.Create(&blog).Error; err != nil {
		c.JSON(http.StatusInternalServerError, err)
		return
	}
	c.JSON(http.StatusOK, blog)
}

读取博客

// 读取博客列表
func GetBlogs(c *gin.Context) {
	var blogs []Blog
	db.Find(&blogs)
	c.JSON(http.StatusOK, blogs)
}

// 读取单篇博客
func GetBlog(c *gin.Context) {
	id := c.Param("id")
	var blog Blog
	if err := db.First(&blog, id).Error; err != nil {
		c.JSON(http.StatusNotFound, err)
		return
	}
	c.JSON(http.StatusOK, blog)
}

更新博客

// 更新博客
func UpdateBlog(c *gin.Context) {
	id := c.Param("id")
	var blog Blog
	if err := db.First(&blog, id).Error; err != nil {
		c.JSON(http.StatusNotFound, err)
		return
	}
	if err := c.ShouldBindJSON(&blog); err != nil {
		c.JSON(http.StatusBadRequest, err)
		return
	}
	blog.UpdatedAt = time.Now()
	db.Save(&blog)
	c.JSON(http.StatusOK, blog)
}

删除博客

// 删除博客
func DeleteBlog(c *gin.Context) {
	id := c.Param("id")
	if err := db.Delete(&Blog{}, id).Error; err != nil {
		c.JSON(http.StatusNotFound, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "blog deleted"})
}

评论功能模块

添加评论

// 添加评论
func AddComment(c *gin.Context) {
	var comment Comment
	if err := c.ShouldBindJSON(&comment); err != nil {
		c.JSON(http.StatusBadRequest, err)
		return
	}
	comment.CreatedAt = time.Now()
	if err := db.Create(&comment).Error; err != nil {
		c.JSON(http.StatusInternalServerError, err)
		return
	}
	c.JSON(http.StatusOK, comment)
}

获取评论

// 获取博客的评论
func GetComments(c *gin.Context) {
	blogID := c.Param("blogId")
	var comments []Comment
	db.Where("blog_id = ?", blogID).Find(&comments)
	c.JSON(http.StatusOK, comments)
}

项目结构

以下是我们项目的结构示意:

/blog-system
    ├── main.go
    ├── models.go
    ├── handlers.go
    ├── routes.go
    ├── db.go
  • main.go:主入口文件,负责启动服务。
  • models.go:定义数据库模型。
  • handlers.go:处理请求的相关逻辑。
  • routes.go:定义路由。
  • db.go:数据库初始化和相关操作。

main.go 文件示例

package main

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

var db *gorm.DB

func main() {
	db = InitDB()
	r := gin.Default()
	SetRoutes(r)

	r.Run(":8080")
}

路由配置

package main

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

func SetRoutes(r *gin.Engine) {
	r.POST("/register", func(c *gin.Context) {
		// 处理用户注册
	})
	r.POST("/login", func(c *gin.Context) {
		// 处理用户登录
	})
	r.POST("/blogs", CreateBlog)
	r.GET("/blogs", GetBlogs)
	r.GET("/blogs/:id", GetBlog)
	r.PUT("/blogs/:id", UpdateBlog)
	r.DELETE("/blogs/:id", DeleteBlog)
	r.POST("/blogs/:blogId/comments", AddComment)
	r.GET("/blogs/:blogId/comments", GetComments)
}

安全性与哈希处理

记得在所有密码存储过程中,一定要使用哈希处理,更加安全。例如,使用bcrypt库。

package main

import (
	"golang.org/x/crypto/bcrypt"
)

func HashPassword(password string) string {
	bytes, _ := bcrypt.GenerateFromPassword([]byte(password), 14)
	return string(bytes)
}

func CheckPasswordHash(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

总结

以上内容提供了一个基于Go语言的简单博客系统的创建指南,通过实现用户管理和CRUD操作,你可以深入理解Go语言的应用场景和开发流程。你可以根据该代码扩展新功能,例如用户角色管理、使用JWT进行验证等,进一步提升项目的复杂度与实用性。希望这个项目对你有帮助,勇于实践,将理论转化为生产力。


怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2234763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

13-鸿蒙开发中的综合实战:华为登录界面

大家好,欢迎来到鸿蒙开发系列教程!今天,我们将通过一个综合实战项目来实现一个华为登录界面。这个项目将涵盖输入框组件、按钮组件、文本组件和布局容器的使用,帮助你更好地理解和应用这些组件。无论你是初学者还是有一定经验的开…

LCL三相并网逆变器simulink仿真+说明文档

背景描述: 详细解析了LCL三相并网逆变器的工作原理,强调了准PR比例谐振控制的重要性,讨论了电感、电容参数选择及保护电路设计。通过仿真结果展示了逆变器性能优化的方法,以提升系统效率和稳定性。 模型介绍: 整体模…

突破1200°C高温性能极限!北京科技大学用机器学习合成24种耐火高熵合金,室温延展性极佳

在工程应用中,如燃气轮机、核反应堆和航空推进系统,对具备优异高温机械性能的金属合金需求十分旺盛。由于材料熔点的固有限制,传统镍基 (Ni) 高温合金的耐温能力已接近极限。为满足开发高温结构材料的需求,耐火高熵合金 (RHEAs) 于…

使用GPT-SoVITS训练语音模型

1.项目演示 阅读单句话 1725352713141 读古诗 1725353700203 2.项目环境 开发环境:linux 机器配置如下:实际使用率百分之二十几, 3.开发步骤 1.首先是准备数据集,要求是wav格式,一到两个小时即可, 2.…

react18中redux-promise搭配redux-thunk完美简化异步数据操作

用过redux-thunk的应该知道,操作相对繁琐一点,dispatch本只可以出发plain object。redux-thunk让dispatch可以返回一个函数。而redux-promise在此基础上大大简化了操作。 实现效果 关键逻辑代码 store/index.js import { createStore, applyMiddlewar…

【JS学习】10. web API-BOM

文章目录 Web APIs - 第5天笔记js组成window对象定时器-延迟函数location对象navigator对象histroy对象本地存储(今日重点)localStorage(重点)sessionStorage(了解)localStorage 存储复杂数据类型 综合案例…

The First项目报告:MANTRA如何实现世界金融区块链化?

RWA(现实世界资产)代币化被视为加密领域的下一个财富增长点,它作为桥梁连接传统金融与加密世界,潜力覆盖数十万亿美元资产市场。尽管面临技术、监管及市场挑战,RWA项目正逐步获得广泛关注。MANTRA是一个Cosmos SDK基L1…

DAY21|二叉树Part08|LeetCode: 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

目录 LeetCode: 669. 修剪二叉搜索树 基本思路 C代码 LeetCode: 108.将有序数组转换为二叉搜索树 基本思路 C代码 LeetCode: 538.把二叉搜索树转换为累加树 基本思路 C代码 LeetCode: 669. 修剪二叉搜索树 力扣代码链接 文字讲解:LeetCode: 669. 修剪二叉搜…

大模型LLama3!!!Ollama下载、部署和应用(保姆级详细教程)

首先呢,大家在网站先下载ollama软件 这就和anaconda和python是一样的 废话不多说 直接上链接:Download Ollama on Windows 三个系统都支持 注意: 这里的Models,就是在上面,大家点开之后,里面有很多模型…

C++转义序列

\b \b是一个退格符(backspace character),它的作用是将光标向左移动一个位置,但并不会删除光标位置上的字符。这个行为在某些情况下可能会导致视觉上的字符“消失”,但实际上这些字符仍然存在于输出缓冲区中&#xf…

[渲染层网络层错误] net::ERR_CONTENT_LENGTH_MISMATCH 问题解决

问题描述 问题背景 微信小程序访问后端img资源的时候,偶尔出现这个感叹号,图片加载不出来,但是对应的url贴出来在浏览器中访问,或者重新加载是可以访问的。 错误描述 经查询前端报错 [渲染层网络层错误] net::ERR_CONTENT_LE…

初始JavaEE篇 —— 网络编程(1):基础的网络知识

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏:JavaEE 目录 前言: 网络的发展历程 网络通信基础 IP地址 端口号 网络协议 网络通信的流程 前言: 我们现在所…

基于SSM+小程序的高校寻物平台管理系统(失物1)

👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 本基于微信小程序的高校寻物平台有管理员,用户以及失主三个角色。 1、管理员功能有个人中心,用户管理,失主管理,寻物启示管理,拾…

leetcode21:合并两个有序列表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 [1,2,4], l2 [1,3,4] 输出:[1,1,2,3,4,4]示例 2: 输入:l1 [], l2 [] 输出:[]示…

【c++丨STL】vector的使用

🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C、STL 目录 前言 vector简要介绍 一、vector的默认成员函数 构造函数(constructor) 析构函数(destructor) 赋值运算符重载operator 二、vector的容量接口…

【数据分享】2024年我国省市县三级的生活服务设施数量(46类设施/Excel/Shp格式)

人才市场、售票处、旅行社等生活服务设施的配置情况是一个城市公共基础设施完善程度的重要体现,一个城市生活服务设施种类越丰富,数量越多,通常能表示这个城市的公共服务水平越高! 本次我们为大家带来的是我国各省份、各地级市、…

自定义SpringBoot的Start应用场景及常见错误

开发背景 为了将环信(即使通讯)的模块独立出来实现复用&#xff0c;提供给多个模块使用。 实现方式 1.目录结构 2.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> &l…

gdb和make工具

gdb工具&#xff1a; GDB的主要功能 断点设置&#xff1a;允许开发者在特定的代码行设置断点&#xff0c;当程序执行到该行时会自动暂停&#xff0c;方便开发者进行调试和分析。 变量查看与修改&#xff1a;在程序运行过程中&#xff0c;可以查看和修改变量的值&#xff0c;以…

Ceisum无人机巡检视频投放

公司投标内容有个视频投放的功能动画&#xff0c;原本想实现这么一个效果&#xff1a; 案例效果来自别人的展示作品&#xff0c;Leader一眼就相中了这个效果&#xff0c;可惜别人的终究是别人的&#xff0c;又不会白白给你&#xff0c;终究是要自己动手尝试。 动画方面的展示…

Spring:Bean(创建方式,抽象继承,工厂Bean,生命周期)

1&#xff0c;Bean的创建 1.1&#xff0c;调用构造器创建Bean 调用Bean类的无参构造函数来创造对象&#xff0c;因此要求提供无参构造函数。在这种情况下class元素是必须的&#xff0c;值就是Bean对象的实现类。 如果采用设值注入&#xff0c;Spring容器将使用默认的构造器来创…