Go开发指南-Gin与Web开发

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

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"}错误。

路由分组

上文中设置鉴权中间件时对路由进行了分组。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.mzph.cn/bicheng/60344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3.2 软件需求:面对过程分析模型

面对过程分析模型 1. 需求分析的模型概述1.1 面对过程分析模型-结构化分析方法1.2 结构化分析的过程 2. 功能模型:数据流图初步2.1 加工2.2 外部实体(数据源点/终点)2.3 数据流2.4 数据存储2.5 注意事项 3. 功能模型:数据流图进阶…

Android Studio 运行模拟器无法打开avd

问题:已经下载了HAXM 打开模拟器时还是提示未下载HAXM,无法打开avd 解决方案: 控制面板 -> 启动或关闭Windows功能,打开图下两项,后重启电脑重启Android Studio:

Qt文件系统-二进制文件读写

实例功能概述 除了文本文件之外,其他需要按照一定的格式定义读写的文件都称为二进制文件。每种格式的二进制文件都有自己的格式定义,写入数据时按照一定的顺写入,读出时也按照相应的顺读出。例如地球物理中常用的SEG-Y格式文件,必…

ARXML汽车可扩展标记性语言规范讲解

ARXML: Automotive Extensible Markup Language (汽车可扩展标记语言) xmlns: Xml name space (xml 命名空间) xsd: Xml Schema Definition (xml 架构定义) 1、XML与HTML的区别,可扩展。 可扩展,主要是…

游戏引擎学习第六天

这节讲的内容比较多: 参考视频:https://www.bilibili.com/video/BV1apmpYVEQu/ XInput 是微软提供的一个 API,用于处理 Windows 平台上 Xbox 控制器(包括有线和无线)及其他游戏控制器的输入。它为开发者提供了一组函数,用于查询控…

vivado+modelsim: xxx is not a function name

xxx is not a function name vivado问题:xxx is not a function name原因 vivado问题:xxx is not a function name 在写verilog modelsim仿真时,遇到error:xxx is not a function name。 原因 该变量xxx在仿真文件里,如下图红框所示&#…

云计算在教育领域的应用

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 云计算在教育领域的应用 云计算在教育领域的应用 云计算在教育领域的应用 引言 云计算概述 定义与原理 发展历程 云计算的关键技…

立体工业相机提升工业自动化中的立体深度感知

深度感知对仓库机器人应用至关重要,尤其是在自主导航、物品拾取与放置、库存管理等方面。 通过将深度感知与各种类型的3D数据(如体积数据、点云、纹理等)相结合,仓库机器人可以在错综复杂环境中实现自主导航,物品检测…

模拟鼠标真人移动轨迹算法-易语言

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…

JavaWeb——Web入门(8/9)- Tomcat:基本使用(下载与安装、目录结构介绍、启动与关闭、可能出现的问题及解决方案、总结)

目录 基本使用内容 下载与安装 目录结构介绍 启动与关闭 启动 关闭 可能出现的问题及解决方案 问题一:启动时窗口一闪而过 问题二:端口号冲突 问题三:部署应用程序 总结 基本使用内容 Tomcat 服务器在 Java Web 开发中扮演着至关重…

PostgreSQL中如果有Left Join的时候索引怎么加

在PostgreSQL中,当你的查询包含多个LEFT JOIN和WHERE条件时,合理地添加索引可以显著提高查询性能。以下是一些具体的优化步骤和建议: 1. 分析查询 使用 EXPLAIN ANALYZE 命令分析你的查询,了解查询的执行计划,识别出连…

通过DNS服务器架构解释DNS请求过程

在前面的章节,这里,基于PCAP数据包和RFC文档详细介绍了DNS请求和响应的每个字段的含义。但是在现实的网络世界中,DNS请求和响应的数据包是怎么流动的,会经过哪些设备。本文将着重说明一下目前网络空间中DNS请求和响应的流动过程。 当前网络空间中比较常见DNS请求的流程如下…

aspose如何获取PPT放映页“切换”的“持续时间”值

aspose如何获取PPT放映页“切换”的“持续时间”值 项目场景问题描述问题1:从官方文档和资料查阅发现并没有对切换的持续时间进行处理的方法问题2:aspose的依赖包中,所有的关键对象都进行了混淆处理 解决方案1、找到ppt切换的持续时间对应的混…

GIT:如何查找已删除的文件的历史记录

首先你得知道文件的名称和路径 然后打开 gitlab,到项目中,仓库-> 文件 查找文件 复制文件名到可能存在过这个文件的分支当中,就能看到了

自动渗透测试与手动渗透测试

根据《渗透测试中发现的 5 种常见网络安全威胁》报告,渗透测试越来越受欢迎。预计到 2025 年,渗透测试市场规模将达到 45 亿美元。 什么是自动渗透测试? 自动化渗透测试工具可以快速有效地检查系统中是否存在已知的安全问题,即使…

使用elementUI实现表格行拖拽改变顺序,无需引入外部库

前言: 使用vue2element UI,且完全使用原生的拖拽事件,无需引入外部库。 如果表格数据量较大,或需要更多复杂功能,可以考虑使用 vuedraggable库,提供更多配置选项和拖拽功能。 思路: 1. 通过el-table的ro…

WPF Prism框架

Prism 是一个开源框架,专门用于开发可扩展、模块化和可测试的企业级 XAML 应用程序,适用于 WPF(Windows Presentation Foundation)和 Xamarin Forms 等平台。它基于 MVVM(Model-View-ViewModel)设计模式&am…

C#开发流程

注:检查数据库链接 设置搜索 1.新建模块文件夹 对应应用 右键-添加-新建文件夹 2.新建类 在新建模块下右键 新建-类,修改类名称 修改internal为public 新建所需字段,注意类型声明及必填设置 [SugarColumn(IsNullable false)]public strin…

区块链应用第1讲:基于区块链的智慧货运平台

基于区块链的智慧货运平台 网络货运平台已经比较成熟,提供了给货源方提供找司机的交易匹配方案;其中包含这几个角色:货主、承运人(司机、车队长)、监管机构、平台。司机要想接单,依赖于多个中心化的第三方平台,且三方平…

计算机毕业设计 | SpringBoot智慧⾼校学术报告系统 AI写作大模型生成平台(附源码)

1,项目介绍 智慧⾼校学术报告系统是⼀个基于 SpringBoot 开发的标准 Java Web 项⽬。系统整体⻚⾯设计简约⼤⽓,巧妙融合了⽬前备受瞩⽬的 AIGC ⽣成式 AI 技术,选择了阿⾥通⽤千问⼤语⾔模型,以智能⽣成趣味报告标题和润⾊报告内…