Go语言Gin框架的常规配置和查询数据返回json示例
文章目录
- 路由文件分组
- 查询数据库并返回json
- service层
- controller
- 路由
- 运行效果
- 启动多个服务
在 上一篇文章《使用Go语言的gorm框架查询数据库并分页导出到Excel实例》 中主要给大家分享了较多数据的时候如何使用go分页导出多个Excel文件并合并的实现方案,这一篇文章继续分享一下go语言的Gin框架的一些常规配置和业务中常用的查询数据库并返回json的实现方案。
Gin是一个golang的微框架,基于 httprouter,具有快速灵活,容错率高,高性能等特点。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。
Gin框架官网:https://gin-gonic.com/zh-cn/,新增一个Go文件,引入 github.com/gin-gonic/gin 即可使用Gin框架。
路由文件分组
正常情况下,Gin框架通过如下代码即可快速实现一个路由和方法:
// router/router.go
package routerfunc Router() *gin.Engine {r := gin.Default()r.GET("/json", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"success": true,})})
}// main.go
package mainimport ("go-demo-2025/router"
)
func main() {r := router.Router()r.Run(":8080") // listen and serve on 0.0.0.0:8080
}
但是,随着项目接口的不断增多,如果把所有的路由都写在一个文件里面的话,不易维护。因此,可以在项目一开始就对路由分成多个文件。实现如下:
- 客户相关路由:
router/customer.go
package routerfunc CustomerRouter(e *gin.Engine) {customer := e.Group("/customer"){customer.GET("/list", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"success": "获取客户列表",})})customer.GET("/info", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"success": "获取客户详情",})}) }
}
- 订单相关路由:
router/order.go
package router// Order 路由
func OrderRouter(e *gin.Engine) {order := e.Group("/order"){order.GET("/list", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"success": "获取订单列表",})})order.GET("/info", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"success": "获取订单详情",})})}// 可以设定多层路由分组orders := e.Group("/orders"){ordersTeacher := orders.Group("/ordersHistory"){ordersTeacher.GET("/list", func(c *gin.Context) { //访问: http://127.0.0.1:8080/orders/ordersHistory/listc.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"success": "/orders/ordersHistory/list",})})}}
}
- 修改
main.go文件:
// main.go
package mainimport ("go-demo-2025/router"
)
func main() {r := router.Router()router.CustomerRouter(r)router.OrderRouter(r)r.Run(":8080") // listen and serve on 0.0.0.0:8080
}
运行效果:




查询数据库并返回json
service层
在 上一篇文章 中,我们已经通过 gorm_generate_db_struct.go 自动生成了数据表的结构体:
type User struct {ID int64 `gorm:"column:id;type:int(11) unsigned;primaryKey;autoIncrement:true;comment:ID" json:"id"` // IDUserID int64 `gorm:"column:user_id;type:bigint(20) unsigned;not null;comment:用户编号" json:"user_id"` // 用户编号Name string `gorm:"column:name;type:varchar(255);not null;comment:用户姓名" json:"name"` // 用户姓名Age int64 `gorm:"column:age;type:tinyint(4) unsigned;not null;comment:用户年龄" json:"age"` // 用户年龄Address string `gorm:"column:address;type:varchar(255);not null;comment:地址" json:"address"` // 地址CreateTime time.Time `gorm:"column:create_time;type:datetime;not null;default:CURRENT_TIMESTAMP;comment:添加时间" json:"create_time"` // 添加时间UpdateTime time.Time `gorm:"column:update_time;type:datetime;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
}
那么,在service层直接进行查询操作即可。gorm框架支持同时查询列表和总数,这一点非常好。
参考文档:
https://gorm.io/zh_CN/docs/query.html
https://www.cnblogs.com/rainbow-tan/p/15822714.html
首先,定义两个结构体,分别用来处理 客户端请求的参数 和 服务端返回的结构:
// 获取用户列表, 客户端的请求参数
type UserListRequest struct {Address string `json:"address" binding:"required"` //用户地址关键词,假设此处要求检索的时候必填Name string `json:"name"` //用户姓名common.CommonListRequest
}// 获取用户列表, 服务端的响应结构体, 在原有的数据表结构的基础上进行扩展
type UserListResponse struct {model.UserNamePinyin string `json:"name_pinyin"` //姓名拼音AgeDesc string `json:"age_desc"` //年龄描述
}
在 service/users/userService.go 中的查询逻辑代码如下:
func (ctx *UserService) QueryUserList(params UserListRequest) ([]UserListResponse, int64) {//查询条件//fmt.Println(params)where := "1=1"if params.Address != "" {where += " and address like '%" + params.Address + "%'"}if params.Name != "" {where += " and name = '" + params.Name + "'"}//查询总数和列表var dataList []UserListResponsevar count int64page := params.Page //当前第几页pageSize := params.PageSize //每页查询多少条offset := (page - 1) * pageSize //偏移量err := ctx.GormDB.Model(&model.User{}).Select("*").Where(where).Order("id desc").Limit(pageSize).Offset(offset).Scan(&dataList).Limit(-1).Offset(-1).Count(&count).Errorif err != nil {fmt.Println(fmt.Sprintf("数据库查询错误:%s", err))return nil, 0}fmt.Println(fmt.Sprintf("总条数:%d", count))for k, v := range dataList { //这里简单示例 对查询的结果进行二次处理var ageDesc stringif v.Age >= 18 {ageDesc = "成年"} else {ageDesc = "未成年"}dataList[k].AgeDesc = ageDescdataList[k].NamePinyin = common.ConvertChineseToPinyin(v.Name)}return dataList, count
}
controller
接下来,将service层查询到的结果返回给 controller进一步处理:
//controllers/customerController/customer.gofunc GetCustomerList(c *gin.Context) {//入参校验var requestData users.UserListRequesterr := c.Bind(&requestData) //执行绑定//fmt.Println("获取客户端请求的参数:", requestData)if err != nil {controllers.ReturnError(c, 1001, fmt.Sprintf("请求参数错误: %s", err))return}//调用service查询数据service := users.NewUserService()dataList, count := service.QueryUserList(requestData)//自定义要返回的字段showFields := []string{"id", "name", "name_pinyin", "age", "age_desc", "address"}var resultList []map[string]anyfor _, item := range dataList {//fmt.Println(item)itemMap := funcUtils.ConvertToFlatMap(item, "") // 通过反射将嵌套结构体转换为一维 map//fmt.Println(itemMap)itemData := make(map[string]any)for _, field := range showFields {itemData[field] = itemMap[field]}resultList = append(resultList, itemData)}controllers.ReturnSuccess(c, 200, "success", resultList, int(count))
}
- 通过
err := c.Bind(&requestData)将客户端传来的参数和结构体的字段进行绑定 showFields中自定义了需要返回给客户端的字段funcUtils.ConvertToFlatMap(item, "")将数据表的结构体转换为map,为了方便和上面的showFields进行比对,并且不需要再额外定义新的结构体了(go里面动不动就要定义结构体,确实挺烦人的,干脆转为map处理通用业务逻辑,方便省事!)。需要注意的是,由于我们前面定义的服务端返回数据结构体采用了结构体嵌套的形式:
type UserListResponse struct {model.UserNamePinyin string `json:"name_pinyin"` //姓名拼音AgeDesc string `json:"age_desc"` //年龄描述
}
因此,这里通过结构体转换map的时候,需要使用反射和递归的思路去处理,核心代码如下:
// 通过反射将嵌套结构体转换为一维 map
func ConvertToFlatMap(obj interface{}, prefix string) map[string]interface{} {val := reflect.ValueOf(obj)result := make(map[string]interface{})// 递归处理结构体flatten(val, prefix, &result)return result
}// 递归处理结构体
func flatten(val reflect.Value, prefix string, result *map[string]interface{}) {// 如果当前值是结构体类型if val.Kind() == reflect.Struct {for i := 0; i < val.NumField(); i++ {field := val.Type().Field(i)fieldValue := val.Field(i)// 检查字段是否导出if field.PkgPath == "" {//newPrefix := field.NamenewPrefix := field.Tag.Get("json")// 递归处理子字段flatten(fieldValue, newPrefix, result)}}} else if val.Kind() == reflect.Slice {// 如果当前值是切片类型for i := 0; i < val.Len(); i++ {elem := val.Index(i)// 递归处理切片中的元素newPrefix := strconv.Itoa(i)flatten(elem, newPrefix, result)}} else {// 如果当前值不是结构体或切片类型(*result)[prefix] = val.Interface()}
}
路由
在上面定义好的一个路由文件中添加相关路由入口: router/customer.go
package routerfunc CustomerRouter(e *gin.Engine) {customer.POST("/list", customerController.GetCustomerList)}
}
运行效果


启动多个服务
示例代码如下:
// run_multiple_server.go// 运行多个服务
package mainimport ("fmt""github.com/gin-gonic/gin""golang.org/x/sync/errgroup""net/http""time"
)var g errgroup.Groupfunc main() {//服务器1:http://127.0.0.1:8081/server01 := &http.Server{Addr: ":8081",Handler: router01(),ReadTimeout: 5 * time.Second, //读取超时时间WriteTimeout: 10 * time.Second, //写入超时时间}//服务器2:http://127.0.0.1:8082/server02 := &http.Server{Addr: ":8082",Handler: router02(),ReadTimeout: 5 * time.Second,WriteTimeout: 10 * time.Second,}//开启服务g.Go(func() error { //开启服务器程序1return server01.ListenAndServe()})g.Go(func() error { //开启服务器程序2return server02.ListenAndServe()})//让监听程序一直处于等待状态if err := g.Wait(); err != nil {fmt.Println("执行失败:", err)}
}func router01() http.Handler {r1 := gin.Default()r1.GET("/", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg": "服务器01的响应",},)})return r1
}func router02() http.Handler {r1 := gin.Default()r1.GET("/", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg": "服务器02的响应",},)})return r1
}//解决包:golang.org/x/sync/errgroup 无法 go get的问题
// cd $GOPATH/src/golang.org/x
// git clone https://github.com/golang/sync.git
// git clone https://github.com/golang/crypto.git
// git clone https://github.com/golang/sys.git
此时,两个站点可以同时访问:

完整源代码:https://gitee.com/rxbook/go-demo-2025
相关文章:
Go语言Gin框架的常规配置和查询数据返回json示例
文章目录 路由文件分组查询数据库并返回jsonservice层controller路由运行效果 启动多个服务 在 上一篇文章《使用Go语言的gorm框架查询数据库并分页导出到Excel实例》 中主要给大家分享了较多数据的时候如何使用go分页导出多个Excel文件并合并的实现方案,这一篇文章…...
JavaEE----多线程(二)
文章目录 1.进程的状态2.线程的安全引入3.线程安全的问题产生原因4.synchronized关键字的引入4.1修饰代码块4.2修饰实例方法4.3修饰静态方法4.4对象头介绍4.5死锁-可重入的特性 5.关于死锁的分析总结5.1死锁的分析5.2死锁成因的必要条件5.3死锁的解决方案 1.进程的状态 public…...
【K8S】快速入门Kubernetes
之前企业都是使用容器化和来构建自己的服务和应用程序,其中容器化优点有很多:提升了部署效率、稳定性、提高了资源的利用率降低了成本。 但是也带来了一些新的问题:容器的数量变得很多,管理就是一个新的问题。所以Kubernetes就出…...
如何在 MySQL 中处理大量的 DELETE 操作??
全文目录: 开篇语前言摘要简介概述DELETE 操作的基本概念常用的 DELETE 方法 核心源码解读简单 DELETE 语句批量 DELETE 示例 案例分析案例1:使用简单 DELETE 删除用户数据案例2:使用分批 DELETE 应用场景演示场景1:用户管理系统场…...
LabVIEW中句柄与引用
在LabVIEW中,句柄(Handle) 是一种用于引用特定资源或对象的标识符。它类似于指针,允许程序在内存中管理和操作复杂的资源,而不需要直接访问资源本身。句柄用于管理动态分配的资源,如队列、文件、网络连接、…...
【三十四】【QT开发应用】音量图标以及滑动条,没有代码补全的小技巧
效果展示 鼠标位于音量图标区域内,显示出滑动条。鼠标移出音量图标区域内滑动条隐藏。鼠标点击音量图标,如果此时音量为0,音量变成50,如果此时音量不为零,音量变为0。 CVolumeButton.h 音量图标头文件 #pragma once …...
Android修改第三方应用相机方向
以下修改基于Android7.1 diff --git a/frameworks/base/core/java/android/hardware/Camera.java b/frameworks/base/core/java/android/hardware/Camera.java index 8c7434b..7201481 100755 --- a/frameworks/base/core/java/android/hardware/Camera.java b/frameworks/ba…...
Python 读取文件汇总
readline和readlines的区别 使用 open()读取文件时,readline是读取文件的一行;而readlines是加载全部文档,以list形式保存每一行内容。 使用with避免资源泄露 with语句不仅限于open()函数,任何实现了上下文管理协议的对象都可以…...
云原生:一张图了解devops 中CI/CD
一个典型的云原生应用的开发和部署过程,其中涉及到的主要工具有 Git、Docker、Jenkins/CircleCI、Ansible、Kubernetes 等。以下是每个步骤的简要说明: 开发人员(Developers)使用 Git 进行版本控制,他们将代码推送到 G…...
无人机之自组网通信技术篇
无人机的自组网通信技术是一种利用无人机作为节点,通过无线通信技术实现节点间自主组网、动态路由和数据传输的技术。 一、技术原理与特点 技术原理:无人机自组网技术基于自组织网络(Ad-Hoc Network)的原理,通过无线…...
【WebLogic】Oracle发布2024年第四季度中间件安全公告
Oracle于美国时间2024年10月15日发布了 WebLogic 12c(12.2.1.4.0)和14c(14.1.1.0.0)两个大版本2024年第4季度的安全公告,涉及漏洞ID共计 6 个,包含2个高危漏洞 2 个,4个中危漏洞,其中…...
Java集合(3:Set和Map)
文章目录 Set概述哈希值HashSet去重原理LinkedHashSetTreeSet自定义排序规则 Map概述Map的基本方法Map集合的获取功能哈希表HashMap底层源码 特点注意 Set 概述 Set集合也是一个接口,继承自Collection,与List类似,都需要通过实现类来进行操…...
【Golang】Gin框架中如何定义路由
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
CPU内存飙升
CPU 飙升介绍 CPU 飙升是指中央处理器(CPU)的使用率在短时间内急剧上升,达到一个较高的水平。正常情况下,CPU 会根据系统和应用程序的需求合理分配资源,使用率会在一定范围内波动。但当 CPU 飙升时,可能会导…...
【Java】LinkedList实现类的使用
LinkedList实现类的使用 package com.star.test04;import java.util.Iterator;import java.util.LinkedList;/** * author : Starshine */public class Test { //这是main方法,程序的入口 public static void main(String[] args) { /* LinkedL…...
创建人物状态栏
接下来,我们来尝试制作一下我们的UI,我们会学习unity基本的UI系统 ************************************************************************************************************** 我们要先安装一个好用的插件到我们的unity当中,帮助…...
django5入门【01】环境配置
注意: ⭐前提:安装了annaconda(python版本管理工具),如果没有安装,强烈建议安装一下!!!操作: 前言: 这里新创建一个名为“python_3.11_start_dja…...
1000集《楼兰》系列短剧开机仪式在疆举行,开启全球传播新篇章
2024年10月18日,光明媚,秋风送爽。 在这个收获的季节里,倍受期待的楼兰系列短剧《楼兰之天女归来》和《楼兰之时空秘宝》在新疆吐鲁番东方红卓览文化博物馆举行了隆重的开机仪式,正式拉开了摄制的序幕。 1000集《楼兰》系列短剧…...
【景观生态学实验】实验五 景观生态脆弱性评价
实验目的 1.学习层次分析模型思路,对丹江口库区2000年景观生态脆弱性评价建模:通过实验课的学习,深入理解层次分析(Analytic Hierarchy Process,AHP)理论与模型,了解其在决策问题中的应用&…...
ChatGPT 现已登陆 Windows 平台
今天,OpenAI 宣布其人工智能聊天机器人平台 ChatGPT 已开始预览专用 Windows 应用程序。OpenAI 表示,该应用目前仅适用于 ChatGPT Plus、Team、Enterprise 和 Edu 用户,是一个早期版本,将在今年晚些时候推出"完整体验"。…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
