如何将数据库实例从我的route.go传递到我的controller.go文件?

问题描述 投票:0回答:2

我需要将一个数据库实例从我的route.go 文件传递到gin 中的控制器文件。

我尝试传递服务器结构,但我得到了循环导入。另外,即使在同一个文件中,我也无法使用任何 *sql.DB 函数。我正在使用 melkey 的 go-blueprint 包。

这是我的 server.go 文件

er

import (
    "backend/internal/database"
    "fmt"
    "net/http"
    "os"
    "strconv"
    "time"

    _ "github.com/joho/godotenv/autoload"
)

type Server struct {
    port int

    db database.Service
}

func NewServer() *http.Server {
    port, _ := strconv.Atoi(os.Getenv("PORT"))
    NewServer := &Server{
        port: port,

        db: database.New(),
    }

    // Declare Server config
    server := &http.Server{
        Addr:         fmt.Sprintf(":%d", NewServer.port),
        Handler:      NewServer.RegisterRoutes(),
        IdleTimeout:  time.Minute,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 30 * time.Second,
    }

    return server
}

这是我的route.go 文件

package server

import (
    "backend/internal/controllers"
    "net/http"

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

func (s *Server) RegisterRoutes() http.Handler {
    r := gin.Default()

    r.GET("/", s.HelloWorldHandler)

    r.GET("/health", s.healthHandler)
    r.GET("/test", controllers.TestController)
    auth := r.Group("/auth")
    AuthRoute(auth)
    return r
}

func (s *Server) HelloWorldHandler(c *gin.Context) {
    resp := make(map[string]string)
    resp["message"] = "Hello World"
        // Unable to use s.db.Query() or something
    c.JSON(http.StatusOK, resp)
}

func (s *Server) healthHandler(c *gin.Context) {
        
    c.JSON(http.StatusOK, s.db.Health())
}

控制器文件

package controllers

import (
    "net/http"

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

func TestController(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "message": "Hello World from the controllers package",
    })
}

这是Database.go 文件

package database

import (
    "context"
    "database/sql"
    "fmt"
    "log"
    "os"
    "time"

    _ "github.com/jackc/pgx/v5/stdlib"
    _ "github.com/joho/godotenv/autoload"
)

type Service interface {
    Health() map[string]string
}

type service struct {
    db *sql.DB
}

var (
    database   = os.Getenv("DB_DATABASE")
    password   = os.Getenv("DB_PASSWORD")
    username   = os.Getenv("DB_USERNAME")
    port       = os.Getenv("DB_PORT")
    host       = os.Getenv("DB_HOST")
    dbInstance *service
)

func New() Service {
    // Reuse Connection
    if dbInstance != nil {
        return dbInstance
    }
    connStr := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", username, password, host, port, database)
    db, err := sql.Open("pgx", connStr)
    if err != nil {
        log.Fatal(err)
    }
    dbInstance = &service{
        db: db,
    }

    // We Migrate all the data by calling the migrate Function
    Migrate(dbInstance)
    return dbInstance
}

func (s *service) Health() map[string]string {
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    err := s.db.PingContext(ctx)
    if err != nil {
        log.Fatalf(fmt.Sprintf("db down: %v", err))
    }

    return map[string]string{
        "message": "It's healthy",
    }
}
go go-gin
2个回答
0
投票

有多种方法可以做到这一点:

  1. 使用结构体作为控制器:
type Controller struct {
   DB database.Service
}

func (c Controller) TestController(c *gin.Context) {...}

然后,在您的服务器中使用

Controller
的初始化实例:

ctr:=controller.Controller{
   DB: server.DB,
}

r.GET("/test", ctr.TestController)
  1. 使用闭包:
func GetTestController(db database.Service) func(*gin.Context) {
   return func(c *gin.Context) {
      ...
   }
}

然后就可以注册了:

r.GET("/test", controller.GetTestController(db))
  1. 您甚至可以使用包级全局变量:
package controller

var db database.Service

func InitController(svc database.Service) {
   db=svc
}

func TestController(c *gin.Context) {...}

然后在您的路线设置中:

controller.InitController(db)

0
投票

我建议您通过在需要的地方传递数据库来使用依赖注入。请允许我提出以下重构。

数据库.go

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

func NewDatabase(dbUser, dbPassword, dbHost, dbName, dbPort string) (*sql.DB, error) {
    connectionStr := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", dbUser, dbPassword, dbHost, dbPort, dbName)
    return sql.Open("postgres", connectionStr)
}

服务.去

package main

import "database/sql"

type User struct {
    Id     string `json:"id"`
    Name   string `json:"name"`
    Email  string `json:"email"`
    Gender string `json:"gender"`
}
type UserLoader interface {
    GetAll() ([]User, error)
    GetUserByEmail(string) (User, error)
}

type userLoader struct {
    dbCon *sql.DB
}

func NewUserLoader(dbCon *sql.DB) UserLoader {
    return &userLoader{dbCon: dbCon}
}

func (l *userLoader) GetAll() ([]User, error) {
    rows, err := l.dbCon.Query("SELECT * FROM users")
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    users := make([]User, 0)
    for rows.Next() {
        var user User
        if err := rows.Scan(&user.Id, &user.Name, &user.Email, &user.Gender); err != nil {
            return nil, err
        }
        users = append(users, user)
    }
    return users, nil
}

func (l *userLoader) GetUserByEmail(email string) (User, error) {
    panic("implement me")
}

路由器.go

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func NewRouter(userLoader UserLoader) *gin.Engine {
    r := gin.Default()

    r.GET("/", HelloWorld)

    r.GET("/health", Health)
    api := r.Group("/api")
    api.GET("/users", GetAllUsers(userLoader))
    return r
}

func GetAllUsers(loader UserLoader) gin.HandlerFunc {
    return func(c *gin.Context) {
        users, err := loader.GetAll()
        if err != nil {
            c.AbortWithStatus(http.StatusInternalServerError)
        }
        c.JSON(http.StatusOK, users)
    }
}

func HelloWorld(c *gin.Context) {
    c.JSON(200, gin.H{"message": "Hello World from the controllers package"})
}

func Health(c *gin.Context) {
    c.JSON(200, gin.H{"status": "ok"})
}

main.go

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "os"
)

func main() {
    database := os.Getenv("DB_DATABASE")
    dbPassword := os.Getenv("DB_PASSWORD")
    dbUsername := os.Getenv("DB_USERNAME")
    dbPort := os.Getenv("DB_PORT")
    host := os.Getenv("DB_HOST")
    serverPort := os.Getenv("SERVER_PORT")

    dbCon, err := NewDatabase(dbUsername, dbPassword, host, database, dbPort)
    if err != nil {
        panic(err)
    }

    userLoader := NewUserLoader(dbCon)

    router := gin.Default()
    router.Use(gin.Recovery())

    router.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{})
    })

    NewRouter(userLoader).Run(fmt.Sprintf(":%s", serverPort))
}

© www.soinside.com 2019 - 2024. All rights reserved.