当前位置: 首页 > news >正文

Go开发指南-Gin与Web开发

目录:
(1)Go开发指南-Hello World
(2)Go开发指南-Gin与Web开发
(3)Go开发指南-Gorouting

Gin 是一个用 Go 语言编写的轻量级、高性能的 Web 框架,主要用于构建 API 服务和微服务。由于其简洁的 API 设计和强大的路由功能,Gin 在 Go 社区中广受欢迎。

运行Web程序

创建一个目录web-service-gin,初始化模块

go mod init example/web-service-gin

创建main.go

package mainimport ("net/http""github.com/gin-gonic/gin"
)type album struct {ID     string  `json:"id"`Title  string  `json:"title"`Artist string  `json:"artist"`Price  float64 `json:"price"`
}func main() {router := gin.Default()router.GET("/albums", getAlbums)router.Run("localhost:8080")
}var albums = []album{{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}func getAlbums(c *gin.Context) {c.IndentedJSON(http.StatusOK, albums)
}

将其运行起来: go run .,就能访问http://lcoalhost:8080/albums了。

再新增一个POST接口:


// add post handler
func postAlbums(c *gin.Context) {var newAlbum albumif err := c.BindJSON(&newAlbum); err != nil {return}albums = append(albums, newAlbum)c.IndentedJSON(http.StatusCreated, newAlbum)
}// update router
router.POST("/albums", postAlbums)

此时用POST方法来访问就可以来新增album了。

根据指定id返回

新增一个接口:

// add getById handler
func getAlbumByID(c *gin.Context) {id := c.Param("id")for _, a := range albums {if a.ID == id {c.IndentedJSON(http.StatusOK, a)return}}c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
}// update router
router.GET("/albums/:id", getAlbumByID)

发起请求:curl http://localhost:8080/albums/1 即可获取第一个album了。

连接数据库

Web服务中访问数据库是必不可少的,下面以postgresql数据库为例来演示如何连接数据库。

先创建数据库和表:

CREATE DATABASE music;CREATE TABLE album(id SERIAL PRIMARY KEY,title VARCHAR(36) NOT NULL,artist VARCHAR(36) NOT NULL,price NUMBRIC(10, 2) NOT NULL
) ;INSERT INTO album(title, artist, price) VALUES
('Album A', 'Artist 1', 9.99),
('Album B', 'Artist 1', 14.99),
('Album C', 'Artist 2', 19.99);

创建main.go:

package mainimport ("database/sql""fmt""log""net/http""github.com/gin-gonic/gin"_ "github.com/lib/pq"
)type Album struct {ID     string  `json:"id"`Title  string  `json:"title"`Artist string  `json:"artist"`Price  float64 `json:"price"`
}var db *sql.DBfunc main() {dsn := "user=postgres password=admin dbname=music sslmode=disable"var err errordb, err = sql.Open("postgres", dsn)if err != nil {log.Fatal("Failed to connect to database", err)}pingErr := db.Ping()if pingErr != nil {log.Fatal("Failed to ping database", pingErr)}fmt.Println("Connected!")router := gin.Default()router.GET("/albums/:artist", getAlbumsByArtist)router.Run("localhost:8080")
}func getAlbumsByArtist(c *gin.Context) {artist := c.Param("artist")albums, err := queryAlbumsByArtist(artist)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}if len(albums) == 0 {c.JSON(http.StatusNotFound, gin.H{"message": "No albums found for artist"})return}c.JSON(http.StatusOK, albums)
}func queryAlbumsByArtist(artist string) ([]Album, error) {rows, err := db.Query("SELECT * FROM album WHERE artist = $1", artist)if err != nil {return nil, err}defer rows.Close()var albums []Albumfor rows.Next() {var album Albumif err := rows.Scan(&album.ID, &album.Title, &album.Artist, &album.Price); err != nil {return nil, err}albums = append(albums, album)}if err = rows.Err(); err != nil {return nil, err}return albums, nil
}

注意,在导入包时使用了 _ "github.com/lib/pq", 此处_表示该包被导入,但不直接在代码中使用,其作用是执行该包的初始化函数。这种用法称为空白标识符导入,通常用于以下几种情况:

  • 注册驱动程序或插件
  • 执行包的初始化代码

访问curl http://localhost:8080/albums/Artist%201,即可获取返回结果。

Gin的中间件

Gin的中间件函数可以在请求到达handler之前做一些前置处理或者在响应返回给客户端之前做后置处理。Gin提供了很多内置的中间件函数,比如常见的日志记录,CORS处理等。开发者也可以根据需要自己定制中间件函数。

日志中间件

下面以日志中间件函数为例来说明如何做日志前处理:

package mainimport ("log""time""github.com/gin-gonic/gin"
)func LoggerMiddleware() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()c.Next()duration := time.Since(start)log.Printf("Request - Method: %s | Status : %d | Duration: %v", c.Request.Method, c.Writer.Status(), duration)}
}func main() {router := gin.Default()router.Use(LoggerMiddleware())router.GET("/", func(c *gin.Context) {c.String(200, "Hello, World!")})router.Run(":8080")
}

访问 http://localhost:8080/, 会看到输出日志中打印日志:

Request - Method: GET | Status : 200 | Duration: 24.291µs

鉴权中间件

假设我们需要在请求被处理之前对其进行鉴权,可以定义鉴权中间件:

package mainimport ("github.com/gin-gonic/gin"
)func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {apiKey := c.GetHeader("X-API-Key")if apiKey == "" {c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})return}c.Next()}
}func main() {router := gin.Default()authGroup := router.Group("/api")authGroup.Use(AuthMiddleware()){authGroup.GET("/data", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Authenticated and authorized!"})})}router.Run(":8080")
}

当访问http://localhost:8080/api/data时,返回{"error":"Unauthorized"}错误。

注意,中间件可以是全局生效的,也可以是局部生效的,取决于其使用的位置。例如authGroup.Use(AuthMiddleware()) 表明此中间件只在authGroup这个路由中生效。

路由分组

上文中设置鉴权中间件时对路由进行了分组。Gin允许对路由进行分组,以便更好地组织和维护代码。

下面继续展示路由分组功能:

package mainimport ("github.com/gin-gonic/gin"
)func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {apiKey := c.GetHeader("X-API-Key")if apiKey == "" {c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})return}c.Next()}
}func main() {router := gin.Default()public := router.Group("/public"){public.GET("/info", func(c *gin.Context) {c.String(200, "Public information")})public.GET("/products", func(c *gin.Context) {c.String(200, "Public product list")})}private := router.Group("/private")private.Use(AuthMiddleware()){private.GET("/data", func(c *gin.Context) {c.String(200, "Private data accessible after authentication")})private.POST("/create", func(c *gin.Context) {c.String(200, "Create a new resource")})}router.Run(":8080")
}

控制器与Handlers

当后端接口不断增加时,如果将所有的业务逻辑全部放在路由的handlers里面是不明智的。

最好是增加控制器来处理业务逻辑,如下所示:

package mainimport ("github.com/gin-gonic/gin"
)type UserController struct{}func (uc *UserController) GetUserInfo(c *gin.Context) {userID := c.Param("id")c.JSON(200, gin.H{"id": userID, "name": "John Doe", "email": "john@example.com"})
}func main() {router := gin.Default()userController := &UserController{}router.GET("/users/:id", userController.GetUserInfo)router.Run(":8080")
}

参考资料

[1]. https://go.dev/doc/tutorial/web-service-gin


http://www.mrgr.cn/news/71221.html

相关文章:

  • 【前端】JavaScript高级教程:线程机制与事件机制
  • 深入理解指针
  • 图形 2.7 LDR与HDR
  • 使用docker-compose单点搭建社区版seafile+onlyoffice在线word编辑平台
  • 【数据库】数据库设计
  • Request和Response
  • android studio 配置过程
  • 开启鸿蒙开发之旅:核心组件及其各项属性介绍——布局容器组件2
  • Mysql高可用架构方案
  • 如何在60分钟内进行ASO竞争对手分析(App Store 和 Google Play Store)
  • seatunnel常用集群操作命令
  • 鸿蒙系统(HarmonyOS)与OpenHarmony
  • notepad++下载安装教程
  • 全球碳循环数据集(2000-2023)包括总初级生产力、生态系统净碳交换和生态系统呼吸变量
  • upload-labs通关练习---更新到15关
  • 【Conda】Windows下conda的安装并在终端运行
  • 第三百二十节 Java线程教程 - Java线程中断、Java Volatile变量
  • 3349、检测相邻递增子数组 Ⅰ
  • golang如何实现sse
  • 一文熟悉redis安装和字符串基本操作
  • 37 string类关键函数的模拟实现
  • 【网络安全渗透测试零基础入门】之Vulnhub靶场PWNOS: 2.0 多种渗透方法,收藏这一篇就够了!
  • FAS在数据库环境中应用详解
  • 逻辑数据编织平台现代企业数据管理和分析的理想选择
  • SQL面试题——奔驰面试题
  • 创业铁盘论