项目介绍

  之前使用的技术栈是java和vue,由于一些原因需要使用go和react进行开发,虽然语言学习起来比较简单,但是想要做到非常熟练还要大量的练习,本着练习的想法打算写一个简单的博客项目

技术栈

前端:react、zustand、antd、react-router-dom
后端: go、goframe
数据库:mysql

提示:使用的node.js版本是20.16.0,go版本为1.19.13,mysql版本为9.0.1,请注意版本不一致可能引起的问题

设计说明

  项目分为三个模块:文章(article)、用户(user)、评论(comment),设计上就是这三个模块的增删改查,计划使用markdown作为编辑引擎,由于是练手项目,一切从简,可能存在部分不合理的地方。

库表设计

用户 user

 用户只设计用户名、密码,用户名做唯一性验证,其他不过度设计

CREATE TABLE landc_blog_user (
    id int NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'Primary Key',
    name VARCHAR(255) NOT NULL COMMENT '用户名',
    password VARCHAR(255) NOT NULL COMMENT '用户密码'
) COMMENT '用户表';

文章 article

 文章主要包含三部分:作者、标题、内容

CREATE TABLE landc_blog_article (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '文章ID',
    title VARCHAR(255) NOT NULL COMMENT '文章标题',
    content TEXT NOT NULL COMMENT '文章内容',
    author_id INT NOT NULL COMMENT '作者ID'
) COMMENT = '博客文章表';

评论 comment

 评论复杂一点,需要支持嵌套回复,所以需要特殊设计,除文章id、用户id、评论内容这三个,还额外增加了父评论id字段

CREATE TABLE landc_blog_comment (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '评论ID',
    article_id INT NOT NULL COMMENT '文章ID',
    author_id INT NOT NULL COMMENT '用户ID',
    content TEXT NOT NULL COMMENT '评论内容',
    parent_id INT DEFAULT NULL COMMENT '父评论ID(用于回复)'
) COMMENT = '博客评论表';

后端准备

后端初始化

 后端使用的是goframe框架,它有自己的框架工具,提供了项目脚手架、代码生成工具,具体的安装教程官网上有,在这里不过多赘述,请确保安装完成之后继续跟进下面的操作。
 使用脚手架创建项目模版,我将项目命名为’landc_blog’,创建命令就是:

gf init landc_blog -u

命令执行之后出现以下字样表示初始化完成
请添加图片描述
在执行命令的文件夹下也会出现以项目名为命名的文件夹:
请添加图片描述
直接使用goland或者vscode打开项目即可。

提示:goframe框架生成的项目结构比较复杂,可先在官网了解目录结构之后再进行后续开发。

自动生成dao层代码

 在项目目录的hack文件夹下存在一个配置文件:config.yaml,这个配置文件主要是框架工具的配置文件。暂时不需要关心生成的内容,我们要在文件中配置一下自己的数据库,最后的配置文件内容如下方所示:

gfcli:
  docker:
    build: "-a amd64 -s linux -p temp -ew"
    tagPrefixes:
      - my.image.pub/my-app
# 下方为自己添加的内容
  gen:
    dao:
      - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/landc_blog"

之后在项目文件夹下执行命令:

gf gen dao

就能够看到以下输出:
请添加图片描述
 至此我们的dao层代码生成结束

目录清理

 goframe自动生成了一个helloworld的项目,现在要将其中的一些内容清理掉,在api文件夹下,直接将hello包删除就好了
请添加图片描述
之后是/internal/controller包下面,同样删掉"hello"包
请添加图片描述
最后是在/internal/cmd包中有一个"cmd.go"文件,这个文件里是http server的配置信息,当前配置了helloworld的路由信息,我们要把它去掉请添加图片描述
关于这里更多的信息,建议去goframe官网了解Web服务开发模块.这样,我们就清理好了后端项目,可以开始我们的代码编写了。

后端接口设计

 后端接口无非就是增删改查,得益于gf框架的代码生成功能,我们设计出接口对应的Req和Res就可以生成对应的接口,但是gf的代码生成有比较严格的规范,希望大家命名时和我保持一致,如果对gf有所了解可以自行修改。

文章 article

 文章除单个文章的CRUD外,还需要列表的获取。首先在/api包下面创建article文件夹,之后在article下面创建v1文件夹请添加图片描述

创建文章 CreateArticle

 创建文章不需要多说什么,请求中除了主键id,其他的都是需要的,返回中就返回插入数据之后的id吧,方便前端再查询展示。在/api/article/v1文件夹下创建文件"create_article.go",编写创建文章的Req和Res

type CreateArticleReq struct {
	g.Meta   `path:"/CreateArticle" method:"post"`
	Title    string `json:"title"`
	Content  string `json:"content"`
	AuthorId int    `json:"authorId"`
}

type CreateArticleRes struct {
	Id int `json:"id"`
}
修改文章 ModifyArticle

 修改文章和创建文章需要的请求数据相同,只是多加了一个文章的id用来定位,返回内容设置为一个布尔值和字符串,用来表示成功或者失败以及失败原因。在/api/article/v1文件夹中创建"modify_article.go"文件

type ModifyArticleReq struct {
	g.Meta   `path:"/ModifyArticle" method:"post"`
	Id       int    `json:"id"`
	Title    string `json:"title"`
	Content  string `json:"content"`
	AuthorId int    `json:"authorId"`
}

type ModifyArticleRes struct {
	Success bool   `json:"success"`
	Info    string `json:"info"`
}
删除文章 DeleteArticle

 删除文章需要用户id和文章id,返回和修改文章相同。在/api/article/v1文件夹中创建"delete_article.go"文件

type DeleteArticleReq struct {
	g.Meta   `path:"/DeleteArticle" method:"post"`
	Id       int `json:"id"`
	AuthorId int `json:"authorId"`
}

type DeleteArticleRes struct {
	Success bool   `json:"success"`
	Info    string `json:"info"`
}
获取文章列表 DescribeArticleList

 获取文章列表的请求需要复用,一个是普通用户获取,一个是作者自己获取,因此需要用户id和关键词两个参数,关键词主要用来做模糊搜索。返回就是返回列表,既然存在列表首先要有item,item不搞太复杂,就文章id、文章标题以及用户名即可。在/api/article/v1文件夹中创建"describe_article_list.go"文件

type DescribeArticleListReq struct {
	g.Meta    `path:"/DescribeArticleList" method:"post"`
	Id        int    `json:"id"`
	SearchKey string `json:"searchKey"`
}

type DescribeArticleListRes struct {
	ArticleList []ArticleListItem `json:"articleList"`
}

type ArticleListItem struct {
	Id         int    `json:"id"`
	Title      string `json:"title"`
	AuthorName string `json:"authorName"`
}
获取文章内容 DescribeArticle

 获取文章内容只需要一个id就够了,返回则需要文章和用户信息都返回,由于信息比较少,可以集成在一起,如果信息多的话,建议分开写。在/api/article/v1文件夹中创建"describe_article.go"文件

type DescribeArticleReq struct {
	g.Meta `path:"/DescribeArticle" method:"post"`
	Id     int `json:"id"`
}

type DescribeArticleRes struct {
	Id         int    `json:"id"`
	Title      string `json:"title"`
	Content    string `json:"content"`
	AuthorId   int `json:"authorId"`
	AuthorName string `json:"authorName"`
}

用户 user

 针对用户我们设计的内容同样不复杂,也是只有CRUD,用户需要一个登录接口,但是登录接口可以通过复用查询接口实现,因为查询用户信息接口对我们来说是不需要的,毕竟用户只有三个字段,并不存在查询用户的场景。在/api文件夹下创建"user"文件夹,在"user"文件夹下创建"v1"文件夹

查询/登录 DescribeUser

 由于我们使用这个接口进行登录,所以需要用户名和密码,返回只要返回用户的id就好,因为用户只有这三个字段,而两个是从前端拿取的。在api/user/v1文件夹下创建文件"describe_user.go"

type DescribeUserReq struct {
	g.Meta   `path:"/DescribeUser" method:"post"`
	Name     string `json:"name"`
	Password string `json:"password"`
}

type DescribeUserRes struct {
	Id int `json:"id"`
}
创建/注册 CreateUser

 创建其实和登录一样,用户输入用户名和密码,后端校验,返回id。在api/user/v1文件夹下创建文件"create_user.go"

type CreateUserReq struct {
	g.Meta   `path:"/CreateUser" method:"post"`
	Name     string `p:"name"`
	Password string `p:"password"`
}

type CreateUserRes struct {
	Id int `json:"id"`
}
修改用户 ModifyUser

 修改用户需要用户的三个字段,返回和之前并无不同。在api/user/v1文件夹下创建文件"modify_user.go"

type ModifyUserReq struct {
	g.Meta   `path:"/ModifyUser" method:"post"`
	Id       int    `json:"id"`
	Name     string `json:"name"`
	Password string `json:"password"`
}

type ModifyUserRes struct {
	Success bool   `json:"success"`
	Info    string `json:"info"`
}
删除用户 DeleteUser

 虽然这个接口不一定会用到,但是它比较简单,因此实现也无妨。在api/user/v1文件夹下创建文件"delete_user.go"

type DeleteUserReq struct {
	g.Meta `path:"/DeleteUser" method:"post"`
	Id     int `json:"id"`
}

type DeleteUserRes struct {
	Success bool   `json:"success"`
	Info    string `json:"info"`
}

评论 comment

 评论内容就更简单了,只需要三个接口,创建、删除、获取列表,不建议修改评论内容,推荐先删除再创建。在/api文件夹下创建"comment",并且在"comment"下创建"v1"文件夹。

创建评论 CreateComment

 仍旧是老套路,除了id外,其他字段都是需要的。在/api/comment/v1文件夹下创建"create_comment.go"文件

type CreateCommentReq struct {
	g.Meta    `path:"/CreateComment" method:"post"`
	ArticleId int    `json:"articleId"`
	AuthorId  int    `json:"authorId"`
	Content   string `json:"content"`
	ParentId  int    `json:"parentId" `
}

type CreateCommentRes struct {
	Id int `json:"id"`
}
删除评论

 删除评论需要id和用户id,返回仍旧同之前。在/api/comment/v1文件夹下创建"delete_comment.go"文件

type DeleteCommentReq struct {
	g.Meta   `path:"/DeleteComment" method:"post"`
	Id       int    `json:"id"`
	AuthorId int `json:"authorId"`
}

type DeleteCommentRes struct {
	Success bool   `json:"success"`
	Info    string `json:"info"`
}
获取评论列表 DescribeCommentList

 获取评论列表的请求仅需要文章id就可以了,但是返回内容是一个值得考虑的问题,实现的方式有很多种,我才用的方式是嵌套返回,item中存在childrenList用来存放它的回复。

type DescribeCommentListReq struct {
	g.Meta `path:"/DescribeCommentList" method:"post"`
	Aid    int `json:"aid"`
}

type DescribeCommentListRes struct {
	CommentList []CommentItem `json:"commentList"`
}

type CommentItem struct {
	Id           int           `json:"id"`
	AuthorId     int           `json:"authorId"`
	AuthorName   int           `json:"authorName"`
	Content      string        `json:"content"`
	ChildrenList []CommentItem `json:"childrenList"`
}

生成接口gen ctrl

 在项目文件夹下输入以下命令,就可以在/internal/controller文件夹中生成我们的接口

gf gen ctrl

看到如下内容即算完成请添加图片描述

结语

 项目第一期的内容就到这里了,主要是利用gf框架的代码生成工具做了一些准备,篇幅已经挺长了,下一篇会进行后端代码开发,很快就发出来,发送之后我会把链接补充在这里。另外关于项目实现上,还是说这次仅仅是一个简单实现,有很多会导致bug和信息泄漏的地方,大家仅做学习框架使用,请不要实际使用。

大家如果有什么疑问或者建议,欢迎提出,祝大家1024程序员节快乐!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐