这是我参与「第五届青训营」伴学笔记创作活动的第6天
前言
这是简易笔记项目的第二篇,本篇主要描述路由的定义和具体的逻辑处理函数的实现。
此项目的代码已开源,lhou/easy-note,欢迎访问和提issue。如果能给个star就更好了。
定义路由
根据这篇文章的定义,定义以下路由
| 路由组 | 路由 | 方式 | 说明 |
|---|---|---|---|
| / | /login | post | 登录 |
| /register | post | 注册 | |
| /user | /:id | get | 获取用户信息 |
| /note | /:id | get | 获取笔记信息 |
| / | get | 获取笔记列表 | |
| / | post | 创建笔记 | |
| /:id | put | 修改笔记 | |
| /:id | delete | 删除笔记 |
定义逻辑处理函数
通过分析,逻辑处理函数主要有两部分
- 用户部分
- 笔记部分
下面将逐个实现
用户部分的逻辑处理
通过路由分析可知,我们需要实现注册、登录、获取用户信息三个逻辑。 首先先定义一个userHandler的结构体
type UserHandler struct {
Repo repo.UserRepo
}
这里面的repo是上篇文章编写的用户数据处理,在这引用可以方便开发。
注册逻辑实现
注册逻辑主要有以下几步
- 用户输入校验
- 存入数据库
- 根据返回结果判断注册成功与否
- 将注册结果返回给用户
用户输入校验
首先根据模型,定义一个结构体用于接收用户提供的数据。在本项目中,是用户名、密码、头像和性别。
下面是实现的具体代码,如果校验失败,那么直接返回错误值,结束本次注册流程。这里面我封装了返回函数。原生的函数是c.Json(statusCode,data)。
var registerForm struct {
Username, Password, Avatar string
Gender int
}
err := c.BindAndValidate(®isterForm)
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
return
}
存入数据库
调用已经定义好的插入数据的函数,将数据封装成模型,获取返回值。
result := userHandler.Repo.InsertUser(&models.User{
Username: registerForm.Username,
Password: registerForm.Password,
Gender: registerForm.Gender,
Avatar: registerForm.Avatar,
})
返回注册结果
根据上步的返回结果,判断是否注册成功并将结果返回给用户。
if !result {
resp.BadRequestResponse(c, 2, "注册失败,请检查您输入")
return
}
resp.SuccessResponse(c, "注册成功", nil)
下面是整个注册逻辑实现的代码
func (userHandler *UserHandler) Register(_ context.Context, c *app.RequestContext) {
// 定义一个结构体用于接收用户的注册信息
var registerForm struct {
Username, Password, Avatar string
Gender int
}
err := c.BindAndValidate(®isterForm)
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
return
}
result := userHandler.Repo.InsertUser(&models.User{
Username: registerForm.Username,
Password: registerForm.Password,
Gender: registerForm.Gender,
Avatar: registerForm.Avatar,
})
if !result {
resp.BadRequestResponse(c, 2, "注册失败,请检查您输入")
return
}
resp.SuccessResponse(c, "注册成功", nil)
}
登陆逻辑的实现
登录逻辑与注册逻辑类似,这里不再赘述。下面是实现代码
func (userHandler *UserHandler) Login(_ context.Context, c *app.RequestContext) {
var loginForm struct {
Username, Password string
}
err := c.BindAndValidate(&loginForm)
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
result := userHandler.Repo.CheckUser(loginForm.Username, loginForm.Password)
if !result {
resp.BadRequestResponse(c, 2, "登陆失败,请检查您的用户名和密码")
return
}
resp.SuccessResponse(c, "登陆成功", nil)
return
}
获取用户信息
注意到,在路由参数中,我们定义了id来作为查询用户信息的关键字。这里我们使用c.Param("id")来获取。这里获取的是字符串类型,需要将其转成整形。其他的部分与注册逻辑相同。
func (userHandler *UserHandler) GetUserById(_ context.Context, c *app.RequestContext) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
user := userHandler.Repo.GetUserById(id)
if user != nil {
resp.NotFountResponse(c, "找不到该用户")
}
resp.SuccessResponse(c, "请求成功", user)
}
笔记部分的处理逻辑实现
笔记部分主要包括以下内容
- 创建笔记
- 删除笔记
- 修改笔记
- 获取单个笔记
- 获取笔记列表(分页)
由于已经写好了对应的数据处理函数,因此以上部分的内容大体相同。结构均为获取、校验参数,请求数据库,返回处理结果三部分。代码如下
type NoteHandler struct {
Repo repo.NoteRepo
}
func (noteHandler *NoteHandler) GetNoteById(_ context.Context, c *app.RequestContext) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
note := noteHandler.Repo.GetNoteById(id)
if note == nil {
resp.NotFountResponse(c, "找不到该笔记")
}
resp.SuccessResponse(c, "请求成功", note)
}
func (noteHandler *NoteHandler) ListNote(_ context.Context, c *app.RequestContext) {
page, err := strconv.Atoi(c.Query("page"))
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
size, err := strconv.Atoi(c.Query("size"))
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
userId := c.GetInt("userId")
var total *int64
notes := noteHandler.Repo.ListNote(page, size, userId, total)
if notes == nil {
resp.NotFountResponse(c, "找不到笔记")
}
resp.SuccessResponse(c, fmt.Sprintf("找到%d篇", total), notes)
}
func (noteHandler *NoteHandler) UpdateNote(_ context.Context, c *app.RequestContext) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
var note struct {
Name, Note string
}
err = c.BindAndValidate(¬e)
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
userId := c.GetInt("userId")
result := noteHandler.Repo.UpdateNote(&models.NoteInfo{
BaseModel: models.BaseModel{
Id: id,
},
Name: note.Name,
Note: note.Note,
UserId: userId,
})
if !result {
resp.BadRequestResponse(c, 5, "修改失败")
}
resp.SuccessResponse(c, "修改成功", nil)
}
func (noteHandler *NoteHandler) DeleteNote(_ context.Context, c *app.RequestContext) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
result := noteHandler.Repo.DeleteNote(id, c.GetInt("userId"))
if !result {
resp.BadRequestResponse(c, 6, "删除失败")
}
resp.SuccessResponse(c, "删除成功", nil)
}
func (noteHandler *NoteHandler) CreateNote(_ context.Context, c *app.RequestContext) {
var note struct {
Name, Note string
}
err := c.BindAndValidate(¬e)
if err != nil {
resp.BadRequestResponse(c, 1, "请求参数错误")
}
userId := c.GetInt("userId")
result := noteHandler.Repo.InsertNote(&models.NoteInfo{
Name: note.Name,
Note: note.Note,
UserId: userId,
})
if !result {
resp.BadRequestResponse(c, 5, "创建失败")
}
resp.SuccessResponse(c, "创建成功", nil)
}
路由与处理函数绑定
在完成数据处理函数的编写后,我们需要将其与路由绑定。下面是路由绑定的函数。
func InitRouters(h *server.Hertz) {
var userHandler handler.UserHandler
var noteHandler handler.NoteHandler
h.POST("/login", userHandler.Login)
h.POST("/register", userHandler.Register)
userRouter := h.Group("/user")
{
userRouter.GET("/:id", userHandler.GetUserById)
}
noteRouter := h.Group("/note")
{
noteRouter.GET("/", noteHandler.ListNote)
noteRouter.GET("/:id", noteHandler.GetNoteById)
noteRouter.POST("/", noteHandler.CreateNote)
noteRouter.PUT("/:id", noteHandler.UpdateNote)
noteRouter.DELETE("/:id", noteHandler.DeleteNote)
}
}
添加假数据
在完成上述步骤后,我们已经可以访问了,但是因为数据库中没有数据,我们只能得到查找失败的结果。为了完成测试,我们需要往数据库中添加假数据。这里推荐一个网站代码生成 - SQL之父 (sqlfather.com),这个网站可以快捷的生成假数据。
未完待续