Go-Web-Echo框架
1. 前言说明
Echo 项目是一个功能强大且用途广泛的 Web 框架,用于使用 Go 编程语言构建可扩展且高性能的 Web 应用程序。它遵循简单性、灵活性和性能的原则,为开发人员提供了一个高效的工具包,用于构建强大的 Web 应用程序。
资源 系列教程
https://polarisxu.studygolang.com/posts/go/echo/basic01-env/
Bind
是 Echo 框架提供的一个方法,用于将请求中的数据绑定到指定的结构体实例上。它支持多种数据格式,包括 JSON、XML、表单数据等。
以下是 Bind
方法的一些关键点:
- JSON 数据:如果请求的 Content-Type 是
application/json
,Bind
会尝试将请求体中的 JSON 数据解析并绑定到指定的结构体实例上。 - 表单数据:如果请求的 Content-Type 是
application/x-www-form-urlencoded
或multipart/form-data
,Bind
会尝试将请求中的表单数据解析并绑定到指定的结构体实例上。 - 查询参数:
Bind
还可以将查询参数绑定到结构体实例上,但需要结构体字段带有form
标签,例如form:"name"
。 - 路径参数:
Bind
也可以将路径参数绑定到结构体实例上,但需要结构体字段带有param
标签,例如param:"id"
。
2. 安装Echo 框架
初始化项目:
创建一个项目文件并进去
代码语言:shell复制$ mkdir myapp && cd myapp
这将会在你项目的根目录中创建一个go.mod
文件
$ go mod init myapp
接着安装Echo
代码语言:shell复制$go get -u github.com/labstack/echo/v4
3. 编写main文件,启动服务
创建一个main文件
代码语言:go复制package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
在终端上,进入到正确目录中 输入
代码语言:shell复制$ go run main.go
看到这个就说明成功启动了, 然后访问http://localhost:1323/
,就会看到映入眼帘的Hello, World!
这几个字眼.
上方文件的代码, 我们等下去解释.
4. 安装air, 热重启
Air 是一个为 Go 项目提供自动重载功能的工具。通过监听项目中文件的变化,自动重新编译并运行你的应用,从而达到热重载的效果,极大地提升开发效率。
安装下载:
代码语言:shell复制go get github.com/air-verse/air@latest
安装好之后, 在项目根目录下创建一个和.air.toml
的配置文件(如果项目中没有这个文件,Air 会使用默认配置)来监听文件变化。一旦检测到文件更改,Air 会自动编译并重启你的应用。
配置内容如下: (可参考)
代码语言:json复制# .air.toml
# 设置项目根目录
root = "."
# [build] 部分用于定义编译命令和其他编译选项
[build]
cmd = "go build -o main.exe ." # Windows 上生成 .exe 文件
bin = "main.exe" # 指定生成的 .exe 文件名称
include = ["*.go", "config/**/*.yaml"] # 监视的文件变化
exclude = ["vendor/**", "node_modules/**"] # 不监视的文件或目录
# [run] 部分用于定义运行命令和环境变量
[run]
cmd = "./main.exe" # 指定运行的可执行文件
env = ["PORT=8080"] # 设置运行时的环境变量
# [watch] 部分用于定义监视的文件和目录
[watch]
include = ["*.go"]
exclude = ["vendor/**", "node_modules/**"]
# [logger] 部分用于定义日志级别
[logger]
level = "info"
打开终端, 在项目的根目录中运行
代码语言:shell复制air
这就表示项目成功启动了.
5. 安装Gorm 和 mysql驱动
gorm : go中较流行的ORM库.
以下是官网描述的特性:
- 全功能 ORM
- 关联 (拥有一个,拥有多个,属于,多对多,多态,单表继承)
- Create,Save,Update,Delete,Find 中钩子方法
- 支持 Preload、Joins 的预加载
- 事务,嵌套事务,Save Point,Rollback To to Saved Point
- Context、预编译模式、DryRun 模式
- 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
- SQL 构建器,Upsert,锁,Optimizer/Index/Comment Hint,命名参数,子查询
- 复合主键,索引,约束
- 自动迁移
- 自定义 Logger
- 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
- 每个特性都经过了测试的重重考验
- 开发者友好
安装:
代码语言:shell复制go get -u gorm.io/gorm
接着去下载安装mysql驱动
代码语言:shell复制go get gorm.io/driver/mysql
6. 连接mysql
我们将连接mysql 的 DSN 存入在.env 环境变量当中.
代码语言:json复制DSN(DataSourceName)是用于标识和定位数据库的字符串,包含数据库类型、主机、端口等信息。它通过驱动程序解析,建立与数据库的连接,提供了一种标准化的连接方式,增强了应用程序的灵活性和可移植性。
DSN=用户名:密码@tcp(127.0.0.1:3306)/数据库
然后在main文件中,进行加载环境变量
, 读取环境变量
, grom mysql连接
等等
func main() {
// 加载环境变量
loadEnv()
// 初始化数据库连接
initDataBases()
// 启动 HTTP 服务器
startServer()
}
加载环境变量
代码语言:go复制func loadEnv() {
env := os.Getenv("ENV")
fmt.Println("环境变量", env)
if env != "production" { // 生产环境是用docker运行的,会用--env-file参数指定.env文件,不需要手动加载
err := godotenv.Load()
if err != nil {
log.Fatalf("Error loading .env file: %v", err)
}
}
}
初始化数据库连接
代码语言:go复制func initDataBases() {
// 获取.env的DSN变量
dsn := os.Getenv("DSN")
fmt.Println("dsn", dsn)
// 调用 Open 方法,传入驱动名和连接字符串
var err error
db.DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 检查是否有错误
if err != nil {
fmt.Println("连接数据库失败:", err)
return
}
// 打印成功信息
fmt.Println("连接数据库成功", db.DB)
}
启动服务器
代码语言:go复制func startServer() {
// 初始化 Echo 实例
e := echo.New()
// 启动服务器
e.Logger.Fatal(e.Start(":8080"))
}
看到这个就说明数据库成功连接了.
接下来,我们继续完善我们的项目的目录搭建工作
7. 采用MVC的风格整理目录
代码语言:go复制https://learnku.com/go/t/48112
my-go-project/
|-- cmd/ # 应用程序的启动点
| |-- main.go # 主入口文件
|-- config/ # 配置文件
| |-- database.go # 数据库配置
| |-- server.go # 服务器配置
| |-- env.example # 环境变量示例文件
|-- db/ # 数据库相关文件
| |-- migrations/ # 数据库迁移文件
| | |-- 20230801_create_users_table.go
| | |-- 20230802_add_roles_to_users_table.go
|-- |models/ # 数据库模型
| | |-- user.go # 用户模型
| | |-- role.go # 角色模型
| |repositories/ # 数据访问层 (DAL)
| | |-- user.go # 用户数据访问层
| | |-- role.go # 角色数据访问层
|-- handlers/ # HTTP 请求处理器
| |-- user.go # 用户请求处理器
| |-- role.go # 角色请求处理器
|-- middleware/ # 中间件
| |-- auth.go # 认证中间件
| |-- logging.go # 日志记录中间件
|-- routes/ # 路由配置
| |-- user.go # 用户路由
| |-- role.go # 角色路由
|-- services/ # 业务逻辑层
| |-- user.go # 用户服务
| |-- role.go # 角色服务
|-- utils/ # 辅助函数和工具
| |-- jwt.go # JWT 工具
| |-- validators.go # 验证工具
|-- internal/ # 内部模块或包
| |-- ...
|-- static/ # 静态文件
|-- templates/ # 模板文件
|-- go.mod # Go 模块元数据
|-- go.sum # Go 模块校验和
|-- .gitignore # Git 忽略文件列表
|-- .env # 环境变量文件
|-- .dockerignore # Docker 忽略文件列表
|-- Dockerfile # Docker 镜像构建文件
|-- Makefile # 自动化任务管理文件
|-- README.md # 项目说明文件
|-- LICENSE # 许可证文件
我们先这样分好目录. 方便我们之后的代码开发.
model
: 包含数据模型和它们的相关操作。这些模型通常对应于数据库中的表,并使用 Gorm 提供的方法进行CRUD
操作。dal
: 数据访问对象(DAO)
层,负责执行实际的数据库操作。DAO 类似于传统的 Repository,它封装了数据库操作,使得模型和业务逻辑层不需要直接与数据库打交道。service
: 业务逻辑层,它调用 DAO 层的方法来获取或修改数据
。业务逻辑层是应用程序的核心部分
,它定义了应用程序的行为和规则。handler
: HTTP 请求处理器,它们处理来自客户端的请求,调用服务层的方法获取所需的数据,并返回适当的响应
。
各层之间的一般交互流程:
- 客户端发送 HTTP 请求到服务器。
- Echo 根据路由配置找到对应的 Handler 函数。
- Handler 函数调用 Service 层的方法来处理请求。
- Service 层调用 Model 层的方法来获取或修改数据。
- Model 层使用 Gorm 对数据库进行操作。
- Service 层将处理后的数据返回给 Handler 函数。
- Handler 函数将数据格式化为合适的响应,并将其发送回客户端。
8. 定义模型,创建表
首先我们在model文件夹下方新建一个user.go的文件
如果数据库中还没有我们需要的表,我们可以使用 gorm 的 AutoMigrate
方法来自动创建表。这个方法会根据我们的模型来生成对应的 SQL 语句,并执行它。
package model
import "time"
// 定义一个User 结构体,用来表示user表
// User 结构体表示用户表
type User struct {
ID uint `gorm:"primaryKey;autoIncrement"` // 主键,自动递增
Name string `gorm:"size:10;not null"` // 用户名,最大长度10,不能为空
Email string `gorm:"unique;size:20;not null"` // 邮箱,唯一索引,最大长度20,不能为空
Password string `gorm:"size:18; not null"` // 密码,不能为空
CreatedAt time.Time `gorm:"autoCreateTime;"` // 在创建时,如果该字段值为零值,则使用当前时间填充
UpdatedAt time.Time `gorm:"autoUpdateTime;"` // 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充
}
在db文件夹下的db文件中, 新增一个方法
代码语言:go复制package db
import (
"fmt"
"gorm.io/gorm"
"quick-start/model"
)
var DB *gorm.DB
// 自动迁移
func AutoMigrate() {
err := DB.AutoMigrate(&model.User{})
if err != nil {
fmt.Println("创建表失败", err)
panic(err)
return
}
fmt.Println("创建表成功")
}
然后再去main.go文件中去使用
代码语言:go复制func main() {
// 加载环境变量
loadEnv()
// 初始化数据库连接
initDataBases()
db.AutoMigrate()
// 启动 HTTP 服务器
startServer()
}
9. 编写第一个请求,创建一个用户
9.1 编写handle层代码.
本部分的主要内容及时获取解析前端传过来的参数,然后传递给
service层
去进行操作. 最后由handle层将数据进行响应返回
新建一个user_handle.go
文件
package handle
import (
"fmt"
"github.com/labstack/echo/v4"
"net/http"
"quick-start/model"
"quick-start/service"
)
// 定义一个UserHandler结构体
type UserHandler struct {
UserService service.UserService
}
// POST 创建一个user 用户
func (h *UserHandler) Create(c echo.Context) error {
name := c.FormValue("name")
email := c.FormValue("email")
password := c.FormValue("password")
fmt.Println("111111111111111")
fmt.Println(name, email, password)
// 三者都不能为空,
if name == "" || email == "" || password == "" {
return c.JSON(http.StatusNotFound, "参数不全")
}
// 创建 User 模型实例
user := &model.User{
Name: name,
Email: email,
Password: password,
}
err := h.UserService.Create(user)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
return c.JSON(http.StatusOK, "创建成功")
}
9.2 完善service层的代码
代码语言:go复制package service
import (
"quick-start/db"
"quick-start/model"
)
type UserService struct {
}
// 调取数据库,向数据库插入一条新数据
func (u *UserService) Create(user *model.User) error {
return db.DB.Create(user).Error
}
9.3 路由定义
在router文件夹下面定义一个index.go
和 一个user_router.go
文件.
我们目前采用这种方式管理路由
代码语言:txt复制router/
user_routes.go
order_routes.go
product_routes.go
index.go
其中每个模块用一个对应文件来表示. 最后在index.go 进行统一管理.
user_router.go
代码语言:go复制package router
import (
"github.com/labstack/echo/v4"
"quick-start/handle"
)
var userHandle = handle.UserHandler{}
// 定义user相关的路由
func SetupUserRoutes(e *echo.Echo) {
e.POST("/user/create", userHandle.Create)
}
index.go
代码语言:go复制package router
import (
"github.com/labstack/echo/v4"
)
// 统一管理路由
func SetupRoutes(e *echo.Echo) {
SetupUserRoutes(e)
}
9.4 接口测试
打开任意一款测试软件, 我这里使用的是APIPOST
创建一个post
请求, 请求地址为http://127.0.0.1:8080/user/create
创建成功