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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/56805.shtml

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

相关文章

2-127基于matlab的非圆齿轮啮合动画设计

基于matlab的非圆齿轮啮合动画设计&#xff0c;可根据需求设置齿数&#xff0c;齿高、平滑系数等&#xff0c;最后输出啮合动画。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&#xff1a;2-127基于matlab的非圆齿轮啮合动画设计

day-13面向对象进阶

面向对象进阶部分学习方法&#xff1a; 特点&#xff1a; ​ 逻辑性没有那么强&#xff0c;但是概念会比较多。 ​ 记忆部分重要的概念&#xff0c;理解课堂上讲解的需要大家掌握的概念&#xff0c;多多练习代码。 day13 第一章 复习回顾 1.1 如何定义类 类的定义格式如…

探索Python配置新维度:Hydra库揭秘

文章目录 探索Python配置新维度&#xff1a;Hydra库揭秘背景&#xff1a;为何选择Hydra&#xff1f;初识Hydra安装Hydra简单的库函数使用方法基础配置覆盖配置组合配置多运行 场景应用数据库配置本地和远程运行多作业运行 常见Bug及解决方案配置加载失败命令行参数解析错误远程…

014_django基于大数据运城市二手房价数据可视化系统的设计与实现2024_3ahrxq75

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

测试右移实践的一些总结思考—稳定监控“及时雨”

随着项目开发的逐渐敏捷化&#xff0c;QA的职能早已不单单是曾经简单对功能的测试&#xff0c;在领域内测试左移和测试右移这两个概念被一再提及。 本文将分别从稳定发布、监控、风险控制三个方面&#xff0c;主要介绍一下目前测试右移概念在组内的落地应用、一些还没有落地的…

Wordpress GutenKit 插件 远程文件写入致RCE漏洞复现(CVE-2024-9234)

0x01 产品简介 GutenKit 是一个WordPress的页面构建器,在 Gutenberg 设计您的下一个 WordPress 网站。借助 Gutenberg 的原生拖放界面、50+ WordPress 块、14+ 多功能模块和 500+ 模板,您可以在几分钟内创建专业、响应迅速的 Web 内容。 0x02 漏洞概述 Wordpress GutenKit…

vue-router钩子中调用ElMessage等样式出错

升级 vue3.5 时遇到奇怪的问题, 页面点击离开没反应 经过排查, 是以下几点相互作用导致此问题 vue 有应用上下文的概念, 例如 runWithContext API,vue-router 在调用钩子时会获取 vue 的应用上下文element-plus 在唤起弹窗时会从 parent 或 应用上下文上拿到 config 信息eleme…

OpenCV高级图形用户界面(20)更改窗口的标题函数setWindowTitle()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在OpenCV中&#xff0c;cv::setWindowTitle函数用于更改窗口的标题。这使得您可以在程序运行时动态地更改窗口的标题文本。 函数原型 void cv::…

浏览器实时更新esp32-c3 Supermini http server 数据

一利用此程序的思路就可以用浏览器显示esp32 采集的各种传感器的数据&#xff0c;也可以去控制各种传感器。省去编写针对各系统的app. 图片 1.浏览器每隔1秒更新一次数据 2.现在更新的是开机数据&#xff0c;运用此程序&#xff0c;可以实时显示各种传感器的实时数据 3.es…

【计算机网络 - 基础问题】每日 3 题(四十七)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质)

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质) 核心代码完整代码在线示例Cesium 给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求; 但是作为 WebGL 引擎,肯定不够丰富,尤其是动态效果样式。 对于实体对象(Entity),可以通过自定义材质,实现各种…

YOLOv11来了 | 自定义目标检测

概述 YOLO11 在 2024 年 9 月 27 日的 YOLO Vision 2024 活动中宣布&#xff1a;https://www.youtube.com/watch?vrfI5vOo3-_A。 YOLO11 是 Ultralytics YOLO 系列的最新版本&#xff0c;结合了尖端的准确性、速度和效率&#xff0c;用于目标检测、分割、分类、定向边界框和…

esp32-c3 Supermini 驱动ds3121的问题

c3 驱动ds3121 ,始终有问题&#xff0c;但把程序用esp32上&#xff0c;一点问题都没有&#xff0c;难道c3 的i2c库是另外的库&#xff0c; 下图只读取秒显示的 错误数据&#xff0c;更换了scl频率&#xff0c;针脚&#xff0c;还是错&#xff0c;但换成esp32 输出是正确连续秒…

字节跳动实习生投毒自家大模型细节曝光 影响到底有多大?

10月19日&#xff0c;字节跳动大模型训练遭实习生攻击一事引发广泛关注。据多位知情人士透露&#xff0c;字节跳动某技术团队在今年6月遭遇了一起内部技术袭击事件&#xff0c;一名实习生因对团队资源分配不满&#xff0c;使用攻击代码破坏了团队的模型训练任务。 据悉&#xf…

鸿蒙开发 四十七 Promise async await

1、Promise是接口 鸿蒙sdk提供的ProPromise版本有点多&#xff0c;是泛型接口&#xff0c;用interface修饰&#xff0c;官网给出的解释是“Represents the completion of an asynchronous operation”&#xff0c;翻译大概意思是&#xff1a;异步操作的完成的处理&#xff0c;总…

全球知名度最高的华人改名大师颜廷利:世界公认的三大哲学家思想家

颜廷利教授&#xff0c;一位享誉全球的思想巨擘与现代国学泰斗&#xff0c;以其卓越的哲学地位和深远的影响力&#xff0c;成为当代思想界的璀璨明星。他的哲学思想深邃而广博&#xff0c;不仅涵盖了人的全面发展、自然社会的深度融合&#xff0c;更在教育理念上独树一帜&#…

2.2机器学习--逻辑回归(分类)

目录 1.算法介绍 2.算法原理 3. API 介绍 4.代码示例 本章节我们来学习线性分类问题&#xff0c;在有监督学习中&#xff0c;最主要的两种学习任务是 回归&#xff08;regression&#xff09; 和 分类&#xff08;classification&#xff09;&#xff0c;而其中线性回归和线…

JR_T0213—2021 金融网络安全 Web应用服务安全测试通用规范.pdf

预览 内容太多&#xff0c;自己下载看吧 https://www.mhtsec.com/667/

精选20个爆火的Python实战项目(含源码),直接拿走不谢!

今天给大家介绍20个非常实用的Python项目&#xff0c;帮助大家更好的学习Python。 完整版Python项目源码&#xff0c;【点击这里】领取&#xff01; ① 猜字游戏 import random def guess_word_game(): words ["apple", "banana", "cherry&quo…

1. 安装框架

一、安装 Laravel 11 框架 按照官方文档直接下一步安装即可 1. 安装步骤 2. 执行数据库迁移 在.env文件中提前配置好数据库连接信息 php artisan migrate二、安装 Filament3.2 参考 中文文档 进行安装 1. 安装 拓展包 composer require filament/filament:"^3.2" -W…