这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
前置知识
Gorm
Gorm 中文文档 GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
定义Gorm model。
注意:
- 如果不写函数TableName(),会使用结构体名的蛇形负数加上 s 作为表名。
- 使用
delete_at作为软删除字段,使用create_at作为创建时间,使用update_at作为更新时间。 - gorm使用名为id的字段作为主键,如果定义。
- gorm.Model 相当于自带了 ID uint 默认主键,CreatedAt time.Time 创建时间,UpdatedAt time.Time 更新时间,DeletedAt DeletedAt 软删除时间
type User struct {
gorm.Model
UserAccount string `gorm:"column:user_account;type:varchar(255);" json:"account"`
UserPassword string `gorm:"column:user_password;type:varchar(255);" json:"password"`
}
func (table *User) TableName() string {
return "user"
}
链接数据库
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
CRUD ,仅列举常用
// 创建数据
db.Create(&User{UserAccount:"rheght", UserPassword:"123456"})
// 查找数据
var User user
db.First(&user, 1) // 根据主键查找
db.First(&user, "user_account", "rheght")// 查找user_account为rheght的用户
// 更新数据
db.Model(&user).Update("user_password", "111111") // 将 user 的 user_password 更新为 111111
db.Model(&user).updates(User{UserAccount:"rheght123", UserPassword:"123123"}) // 仅更新为零值字段
db.MOdel(&user).updates(map[string]interface{}{UserAccount:"rheght", UserPassword:"123456"}) // 可更新零值
// 删除
db.Delete(&user, 1)
Hertz
Hertz 中文文档快速开始 | CloudWeGo
下面是一个简单接口,可以运行测试环境是否配置完成。
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
})
h.Spin()
}
接下来是需要用到的方法,接收前端传来的请求体,将 json 数据转成结构体对象,
bytes, err := ctx.Body()
if err != nil {
panic(err)
}
var user models.User
if err = json.Unmarshal(bytes, &user); err != nil {
panic(err)
}
result := models.MatchUser(user.UserAccount, user.UserPassword) // 此时的user已经存有数据
ctx.JSON(consts.StatusOK, result)
代码实现
首先先创建软件包,参考 Hertz 的自动生成代码的目录
- router
- models
- common
- handler
- test
- service
数据库建表
user
- id bigint
- user_account varchar(25)
- user_password varchar(25)
- deleted_at datetime
- create_at datetime
- update_at datetime
main.go
package main
import (
"hertz_demo/router"
)
func main() {
h := router.Router()
h.Spin()
}
在router 包内创建app.go
package router
import (
"github.com/cloudwego/hertz/pkg/app/server"
"hertz_demo/handler"
)
func Router() *server.Hertz {
h := server.Default()
userGroup := h.Group("/user")
{
userGroup.POST("/login", handler.UserLogin)
userGroup.POST("/register", handler.UserRegister)
}
return h
}
在 common 包下创建init.go
package common
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
var DB = Init()
func Init() *gorm.DB {
dsn := "root:123456@tcp(127.0.0.1:3306)/test_gorm_hertz?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
return db
}
在 common 包下创建 response.go ,封装统一返回结构体,通常需要前后端沟通。
package common
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
func Success(data interface{}) Response {
return Response{
Code: 20000,
Msg: "Success",
Data: data,
}
}
func Fail(code int) Response {
return Response{
Code: code,
Msg: "System error",
Data: nil,
}
}
func FailWithMsg(code int, msg string) Response {
return Response{
Code: code,
Msg: msg,
Data: nil,
}
}
在 models 包下创建 user.go ,作为与数据库一一对应的实体,实际业务中应该进行包装成 dto ,例如本次登录返回时就可以隐藏掉密码
package models
type User struct {
UserAccount string `gorm:"column:user_account;type:varchar(255);" json:"account"`
UserPassword string `gorm:"column:user_password;type:varchar(255);" json:"password"`
}
func (table *User) TableName() string {
return "user"
}
在 service 包下创建 userService.go ,从 java 来的习惯,不一定适用全部人
package service
import (
"errors"
"fmt"
"hertz_demo/common"
"hertz_demo/models"
)
func MatchUser(userAccount, userPassword string) (models.User, error) {
user := models.User{}
err := common.DB.First(&user, "user_account = ? and user_password = ?", userAccount, userPassword).Error
return user, err
}
func AddUser(user models.User) error {
tempUser := models.User{}
common.DB.Find(&tempUser, "user_account = ?", user.UserAccount)
if tempUser != (models.User{}) {
return errors.New("账号重复")
}
err := common.DB.Model(&user).Create(user).Error
if err != nil {
return err
}
return nil
}
在 handler 包下 创建 userHandler.go
package handler
import (
"context"
"encoding/json"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/protocol/consts"
"hertz_demo/common"
"hertz_demo/models"
"hertz_demo/service"
"log"
)
func UserLogin(c context.Context, ctx *app.RequestContext) {
bytes, err := ctx.Body()
if err != nil {
panic(err)
}
var user models.User
if err = json.Unmarshal(bytes, &user); err != nil {
panic(err)
}
result, err := service.MatchUser(user.UserAccount, user.UserPassword)
if err != nil {
ctx.JSON(consts.StatusOK, common.Fail(40001))
return
}
ctx.JSON(consts.StatusOK, common.Success(result))
}
func UserRegister(c context.Context, ctx *app.RequestContext) {
bytes, err := ctx.Body()
if err != nil {
ctx.JSON(consts.StatusOK, common.FailWithMsg(40001, "wrong params"))
panic(err)
}
var user models.User
err = json.Unmarshal(bytes, &user)
if err != nil {
ctx.JSON(consts.StatusOK, common.Fail(50000))
panic(err)
}
log.Println(user)
if err = service.AddUser(user); err != nil {
ctx.JSON(consts.StatusOK, common.FailWithMsg(50000, err.Error()))
panic(err)
}
ctx.JSON(consts.StatusOK, common.Success("注册成功"))
}
至此,登录注册功能已经开发完成,显然在代码实现和业务场景都比较简单,只能用作学习。