使用 Go、Gin、MySQL 和 Docker 构建博客项目 - 第一部分
内容
目标受众
本系列教程不侧重于 Go 语言的基础知识,而是着重讲解如何构建后端服务。对使用 Gin 框架进行 Web 开发感兴趣的人士是理想的学习对象。
学习目标
本系列教程将教你使用 Go 构建 REST API 的基础知识。完成本系列教程后,你将掌握以下技能:
- 配置 Golang、MySQL 和 Docker 以进行本地开发
- 用于 CRUD API 的 Gin 框架。
- 领域驱动开发
- 使用 Go 进行依赖注入
- 使用 Firebase 等进行身份验证
要求
- Go 已安装(版本:go1.16.3 linux/amd64)
- Docker(版本 20.10.6)和 Docker-compose(版本 1.29.1)。
- 最好是Linux机器(因为我会使用Linux系统,但任何系统都可以)。
- 对RESTful服务/API的总体理解。
以上版本已安装在我的机器上。您可以在此仓库
中找到该系列的完整源代码,欢迎 fork:
入门
首先,blog在您选择的位置创建一个文件夹。然后,使用以下命令在该文件夹内初始化一个新的Go 模块。blog
go mod init blog
上述命令会创建一个go.mod文件,用于管理项目依赖项。我们来添加一些依赖项。
go get github.com/gin-gonic/gin
上述命令将安装Gin Framework和Gorm,并创建go.sum一个文件。该文件存储有关依赖项及其版本的信息。
Gin是一个轻量级、文档齐全且速度极快的 HTTP Web 框架。其创建者声称 Gin 比其他类似框架快 40 倍。
起床 你好世界服务器
在根目录下创建一个main.go文件;打开你喜欢的编辑器,并输入以下代码
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default() //new gin router initialization
router.GET("/", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{"data": "Hello World !"})
}) // first endpoint returns Hello World
router.Run(":8000") //running application, Default port is 8080
}
让我们一起来看一下代码。main.go
-
package main:每个 Go 文件都是一个包。main 包始终是 Gin 项目的入口点。
-
**导入**:导入项目依赖项。
-
** main 函数 **:每次运行应用程序时都会触发 main 函数。在函数内部,
Gin router会初始化一个新的变量。同时,会在路由器上设置router一个新的端点。 *设置路由/端点需要两件事:*/- 端点:它是获取数据的路径。例如,如果访问者想要获取所有帖子,他们将获取该
/posts端点。 - 处理程序:它决定了如何向端点提供数据。业务逻辑包括从数据库获取/保存数据、验证用户输入等等。上下文对象的 JSON 方法用于以 JSON 格式发送数据。此方法接受 HTTP状态码和 JSON 响应作为参数。
- 端点:它是获取数据的路径。例如,如果访问者想要获取所有帖子,他们将获取该
使用以下命令启动服务器。
go run main.go
如果看到类似以下的输出,则表示一切就绪。
[GIN-debug] GET / --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8000
在浏览器中访问http://localhost:8000/。{"data":"Hello World !"}你应该会看到。
设置 Docker
上述服务器运行方式是 Go 语言的默认应用运行方式。接下来,我们通过 Docker 的方式来配置它。在项目根目录
创建一个文件,并添加以下代码。Dockerfile
FROM golang:alpine
RUN mkdir /app
WORKDIR /app
ADD go.mod .
ADD go.sum .
RUN go mod download
ADD . .
RUN go get github.com/githubnemo/CompileDaemon
EXPOSE 8000
ENTRYPOINT CompileDaemon --build="go build main.go" --command=./main
要构建上述 Docker 容器,Dockerfile请使用以下命令
docker build -t hello_world :1.0 .
docker ps -a您可以在终端上查看集装箱列表。您应该可以看到带有其他信息的集装箱。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
62cddf7c2659 hello_world:1.0 "/bin/sh -c 'Compile…" 23 minutes ago Exited (0) 23 minutes ago gifted_kilby
要启动容器,请使用以下命令
docker run -p 8000:8000 hello_world:1.0
在浏览器中访问http://localhost:8000/。{"data":"Hello World !"}你应该会看到。
让我们回顾一下上面 Dockerfile 中提到的 Docker 命令:
-
FROM:FROM 指的是容器使用的基础镜像。golang:1.16 镜像是一个基于 Linux 的镜像,其中安装了 golang,但没有其他额外的程序或软件。
-
WORKDIR:WORKDIR 参数用于更改工作目录。在本例中,它更改为 /app。此参数为后续命令设置工作目录。
-
ADD指令的作用是将文件从一个位置复制到另一个位置。
ADD [SOURCE] [DESTINATION]这是该命令的语法。类似地,也有 COPY 命令用于相同的目的。这里,我们首先复制 go.sum 和 go.mod 文件,以便在复制所有文件之前安装所有库。 -
RUN:RUN 指令会在当前镜像之上创建一个新层,并执行所有命令,然后提交结果。提交后的镜像将用于 Dockerfile 中的下一步操作。
-
EXPOSE:EXPOSE 指示在 Docker 容器上运行的服务可通过端口 8000 访问。
-
入口点 (Entrypoint):入口点会在从镜像创建容器后,在容器内部运行命令。一个容器中只能有一个入口点指令
Dockerfile。如果使用了多个入口点指令,则会执行最后一个。在这里,容器创建完成后,入口点命令将运行我们的 Go 语言项目。
设置数据库
需要安装 MySQL 软件包才能将数据库与应用程序连接。请使用以下命令进行安装。
go get gorm.io/driver/mysql gorm.io/gorm
Gorm是一个非常棒的 Golang ORM 库。
由于连接数据库是应用程序构建的关键部分,我们来创建一个文件夹infrastructure,并db.go在其中创建一个文件infrastructure。让我们往里面写一些内容db.go。
package infrastructure
import (
"fmt"
"os"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
//Database struct
type Database struct {
DB *gorm.DB
}
//NewDatabase : intializes and returns mysql db
func NewDatabase() Database {
USER := os.Getenv("DB_USER")
PASS := os.Getenv("DB_PASSWORD")
HOST := os.Getenv("DB_HOST")
DBNAME := os.Getenv("DB_NAME")
URL := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", USER, PASS,
HOST, DBNAME)
fmt.Println(URL)
db, err := gorm.Open(mysql.Open(URL))
if err != nil {
panic("Failed to connect to database!")
}
fmt.Println("Database connection established")
return Database{
DB: db,
}
}
函数内部NewDatabase正在执行以下工作:
- 数据库凭据 USER、PASS、HOST 和 DBNAME 是从环境变量中获取的。
- 数据库 URL 是利用环境变量构建并保存到
URL变量中的。 - 使用以下方法
mysql打开一个新连接。gorm.OpenURL - 最后,返回数据库结构体,其中包含 gorm 数据库实例作为参数,该实例稍后将在应用程序中用于访问数据库。
环境变量
项目中有两种类型的变量program variables。environment variables程序变量是普通变量,用于存储代码块或模块内的值;而环境变量则在整个项目中全局可用。
设置环境变量
环境变量可以通过多种方式设置。这里,我们将使用.env文件来设置它们。.env在项目根目录下创建一个文件,并添加以下变量。
MYSQL_ROOT_PASSWORD=root
DB_USER=user
DB_PASSWORD=Password@123
DB_HOST=db
DB_PORT=3306
DB_NAME=golang
SERVER_PORT=8000
ENVIRONMENT=local
阅读环境变量
现在,我们来编写读取文件的代码。在文件夹中.env创建一个文件,并将以下代码填充到该文件中。env.goinfrastructure
package infrastructure
import (
"log"
"github.com/joho/godotenv"
)
//LoadEnv loads environment variables from .env file
func LoadEnv() {
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("unable to load .env file")
}
}
使用以下命令安装 godotenv 软件包
go get github.com/joho/godotenv
*为了加载.env文件和数据库,我们需要main.go按如下方式进行编辑 *
func main() {
router := gin.Default()
router.GET("/", func(context *gin.Context) {
infrastructure.LoadEnv() //loading env
infrastructure.NewDatabase() //new database connection
context.JSON(http.StatusOK, gin.H{"data": "Hello World !"})
})
router.Run(":8000")
}
Docker Compose 文件
我们需要使用 Docker Compose 来定义和运行多容器 Docker 应用程序。在本例中,这些应用程序包括数据库和 Gin 应用程序。请docker-compose.yml在项目级别创建一个文件,并填充以下代码。
version: '3'
services:
db:
image: mysql/mysql-server:5.7
ports:
- "3305:3306"
environment:
- "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}"
- "MYSQL_USER=${DB_USER}"
- "MYSQL_PASSWORD=${DB_PASSWORD}"
- "MYSQL_DATABASE=${DB_NAME}"
web:
build: .
ports:
- "8000:8000"
volumes:
- ".:/app"
depends_on:
- db
links:
- "db:database"
让我们回顾一下compose文件中提到的术语。
-
版本“3”:Docker Compose 版本,最新版本为 3.7
-
服务:服务部分定义了所有要创建的不同容器。我们有两个服务,分别是
web和db。 -
web:这是我们 Gin 应用服务的名称。它可以是任何名称。Docker Compose 将创建以此名称命名的容器。
-
build:此子句指定 Dockerfile 的位置。
.它表示 docker-compose.yml 文件所在的当前目录,Dockerfile 用于构建镜像并从中运行容器。我们也可以在此处输入 Dockerfile 的路径。 -
ports:ports 子句用于将容器端口映射到宿主机。这里映射的是端口
"8000:8000",以便我们可以通过8000宿主机的端口访问我们的服务。 -
卷:这里我们将代码文件目录(./app 目录)附加到容器中,这样每次文件更改时就无需重新构建镜像。这也有助于在调试模式下自动重新加载服务器。
-
链接:链接顾名思义,就是将一个服务连接到另一个服务。在这里,我们将数据库容器连接到 Web 容器,以便我们的 Web 容器可以通过桥接网络访问数据库。(注意:涉及网络!)如果您想详细了解 Docker 中的网络,请参阅:网络容器
-
镜像:如果我们没有 Dockerfile,并且想要直接使用已构建的镜像运行服务,我们可以使用 `image` 子句指定镜像位置。Compose 会拉取镜像并从中 fork 一个容器。在本例中,我们为数据库服务指定了 `mysql/mysql-server:5.7`。
-
环境:任何需要在容器中设置的环境变量都可以使用“environment”子句创建。
environment:
- "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}"
值${MYSQL_ROOT_PASSWORD}和其他变量均已读取.env。
现在,您已准备好启动容器。使用以下命令开始构建并运行。
docker-compose up --build
如果你的终端显示类似以下内容,则表示服务器正在运行:
db_1 | 2021-05-24T09:18:02.841094Z 0 [Note] Event Scheduler: Loaded 0 events
db_1 | 2021-05-24T09:18:02.841370Z 0 [Note] mysqld: ready for connections.
db_1 | Version: '5.7.34' socket: '/var/lib/mysql/mysql.sock' port: 3306 MySQL Community Server (GPL)
web_1 | 2021/05/24 09:18:06 Running build command!
web_1 | 2021/05/24 09:18:17 Build ok.
web_1 | 2021/05/24 09:18:17 Restarting the given command.
web_1 | 2021/05/24 09:18:17 stdout: [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
web_1 | 2021/05/24 09:18:17 stdout:
web_1 | 2021/05/24 09:18:17 stdout: [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
web_1 | 2021/05/24 09:18:17 stdout: - using env: export GIN_MODE=release
web_1 | 2021/05/24 09:18:17 stdout: - using code: gin.SetMode(gin.ReleaseMode)
web_1 | 2021/05/24 09:18:17 stdout:
web_1 | 2021/05/24 09:18:17 stdout: [GIN-debug] GET / --> main.main.func1 (3 handlers)
web_1 | 2021/05/24 09:18:17 stdout: [GIN-debug] Listening and serving HTTP on :8000
访问http://localhost:8000/并在终端中检查,Database connection established应该会打印在标准输出上。
包起来
本系列第一部分到此结束。
下一部分我们将继续探讨:
- 向应用程序添加模型(结构体)
- 采用领域驱动开发模式
请务必关注我以获取下一部分的更新信息,或者订阅我的频道,这样您就不会错过我即将发表的文章。
谢谢 !!
文章来源:https://dev.to/umschaudhary/blog-project-with-go-gin-mysql-and-docker-part-1-3cg1