连接数据库
到目前为止,我们的后端运行良好。我们可以创建用户和登录名,但是一旦我们重新启动服务器,该用户数据就会丢失,因为它仅在应用程序运行时保存在内存中。当然这是不现实的情况,即使服务器重新启动,我们也希望保存所有用户数据。为此,所有数据都将保存到数据库中。我们将使用的数据库是介绍中提到的 PostgreSQL。我们不会介绍 PostgreSQL 的安装,因为官方页面上有关于它的文档。对于接下来的步骤,我们将假设 PostgreSQL 已安装和配置。在所有示例中,我们将使用默认用户postgres和密码postgres。
让我们首先连接到 PostgreSQL 以创建新数据库。如果 PostgreSQL 服务没有运行,你必须先启动它,然后连接postgres用户:
sudo service postgresql start
sudo -u postgres psql
进入全屏模式 退出全屏模式
连接后,创建新数据库:
CREATE DATABASE rgb;
进入全屏模式 退出全屏模式
对于数据库通信,我们将使用go-pg模块。您可以通过运行go get github.com/go-pg/pg/v10来安装它。这将安装go-pg模块的第 10 版,这是编写本指南时的最新版本。现在在其中创建新目录internal/database/和文件database.go。
package database
import (
"github.com/go-pg/pg/v10"
)
func NewDBOptions() *pg.Options {
return &pg.Options{
Addr: "localhost:5432",
Database: "rgb",
User: "postgres",
Password: "postgres",
}
}
进入全屏模式 退出全屏模式
这只会创建用于连接数据库的新选项。创建新文件internal/store/store.go,我们将在其中设置数据库连接以供我们的store包使用,这将是唯一与数据库通信的包。
package store
import (
"log"
"github.com/go-pg/pg/v10"
)
// Database connector
var db *pg.DB
func SetDBConnection(dbOpts *pg.Options) {
if dbOpts == nil {
log.Panicln("DB options can't be nil")
} else {
db = pg.Connect(dbOpts)
}
}
func GetDBConnection() *pg.DB { return db }
进入全屏模式 退出全屏模式
这里我们有一个变量db,它将作为 store 包的数据库连接器。我们还有两个函数,一个是设置数据库连接器,一个是获取它。函数SetDBConnection()将立即使用,因为我们需要设置我们的数据库连接器。如前所述,只有 store 包将连接到数据库,并且db变量在整个包中可用。那么,我们需要GetDBConnection()做什么?好吧,我们实际上还不需要它,但我们将在下一节中需要它来运行迁移,因为这将在单独的小应用程序中发生,正如您很快就会看到的那样。现在,我们只通过添加第store.SetDBConnection(database.NewDBOptions())行在internal/server/server.go文件中设置数据库连接器:
package server
import (
"rgb/internal/database"
"rgb/internal/store"
)
func Start() {
store.SetDBConnection(database.NewDBOptions())
router := setRouter()
// Start listening and serving requests
router.Run(":8080")
}
进入全屏模式 退出全屏模式
有了这些,我们准备在internal/store/users.go文件中实现创建和验证用户的方法:
package store
import "errors"
type User struct {
ID int
Username string `binding:"required,min=5,max=30"`
Password string `binding:"required,min=7,max=32"`
}
func AddUser(user *User) error {
_, err := db.Model(user).Returning("*").Insert()
if err != nil {
return err
}
return nil
}
func Authenticate(username, password string) (*User, error) {
user := new(User)
if err := db.Model(user).Where(
"username = ?", username).Select(); err != nil {
return nil, err
}
if password != user.Password {
return nil, errors.New("Password not valid.")
}
return user, nil
}
进入全屏模式 退出全屏模式
上述函数将在internal/server/user.go中使用:
package server
import (
"net/http"
"rgb/internal/store"
"github.com/gin-gonic/gin"
)
func signUp(ctx *gin.Context) {
user := new(store.User)
if err := ctx.Bind(user); err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := store.AddUser(user); err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{
"msg": "Signed up successfully.",
"jwt": "123456789",
})
}
func signIn(ctx *gin.Context) {
user := new(store.User)
if err := ctx.Bind(user); err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user, err := store.Authenticate(user.Username, user.Password)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Sign in failed."})
return
}
ctx.JSON(http.StatusOK, gin.H{
"msg": "Signed in successfully.",
"jwt": "123456789",
})
}
进入全屏模式 退出全屏模式
如果我们现在尝试创建新帐户,我们将收到错误消息。这是意料之中的,因为我们正在尝试将我们的数据添加到尚不存在的用户表中。我们将在下一节中通过使用迁移来解决这个问题。
更多推荐
所有评论(0)