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.rhkb.cn/news/453705.html

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

相关文章

跨界创新|使用自定义YOLOv11和Ollama(Llama 3)增强OCR文本识别

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

Electron-(三)网页报错处理与请求监听

在前端开发中&#xff0c;Electron 是一个强大的框架&#xff0c;它允许我们使用 Web 技术构建跨平台的桌面应用程序。在开发过程中&#xff0c;及时处理网页报错和监听请求是非常重要的环节。本文将详细介绍 Electron 中网页报错的日志记录、webContents 的监听事件以及如何监…

CTFHUB技能树之XSS——过滤关键词

开启靶场&#xff0c;打开链接&#xff1a; 看上去跟上一题应该差不多&#xff0c;应该只是添加多点过滤规则吧 直接拿xss平台的代码试试&#xff1a; <sCRiPt sRC//xs.pe/6b6></sCrIpT> 这时候突然听到xss平台的上线语音提醒&#xff1a; 成功得到flag&#xff1…

react里实现左右拉伸实战

封装组件&#xff1a; 我自己写的一个简单的组件&#xff0c;可能有bug。不想自己写&#xff0c;建议用第三方库实现。 新建一个resizeBox.tsx文件写上代码如下&#xff1a; import React, { ReactNode, useState, useEffect, useRef } from react; import styles from &quo…

具备哪些特质的内外网文件交换系统 才是高科技企业需要的?

高科技企业是指涉及对国家产生深远和积极影响的先进技术的产业集群&#xff0c;它们以持续的创新和高研发投入为核心&#xff0c;推动科技进步和产业升级。高科技企业是市场经济的重要组成&#xff0c;为经济发展和技术进步提供充足动力&#xff0c;因此&#xff0c;高科技企业…

LeetCode刷题日记之贪心算法(五)

目录 前言无重叠区间划分字母区间合并区间单调递增的数字监控二叉树总结 前言 随着对贪心算法的不断深入&#xff0c;本篇文章将继续挑战一些经典的题目&#xff0c;进一步巩固这一算法的应用技巧。希望博主记录的内容能够帮助大家更好地掌握贪心算法的解题思路✍✍✍ 无重叠区…

【K8S系列】Kubernetes Pod节点CrashLoopBackOff 状态及解决方案详解【已解决】

在 Kubernetes 中&#xff0c;Pod 的状态为 CrashLoopBackOff 表示某个容器在启动后崩溃&#xff0c;Kubernetes 尝试重启该容器&#xff0c;但由于持续崩溃&#xff0c;重启的间隔时间逐渐增加。下面将详细介绍 CrashLoopBackOff 状态的原因、解决方案及相关命令的输出解释。 …

Openlayers高级交互(3/20):动态添加 layer 到 layerGroup,并动态删除

layerGroup 是 OpenLayers 库中的一个类,用于创建图层组。图层组允许您将多个图层组合在一起,并作为一个整体来控制它们的可见性和其他属性。本示例动态添加layer到layerGroup,并动态删除。 效果图 专栏名称内容介绍Openlayers基础实战 (72篇)专栏提供73篇文章,为小白群…

回归预测||时序预测||基于灰狼优化的时域卷积TCN连接Transformer-BiLSTM的数据回归预测|时序预测Matlab程序

回归预测||时序预测||基于灰狼优化的时域卷积TCN连接Transformer-BiLSTM的数据回归预测|时序预测Matlab程序 文章目录 一、基本原理一、基本概念二、原理和流程1. 数据准备2. 模型构建3. 灰狼优化算法设计4. 模型训练与优化5. 模型评估与预测 三、优势与应用四、总结 二、实验结…

Docker 用例:15 种最常见的 Docker 使用方法

容器化应用程序而不是将它们托管在虚拟机上是过去几年一直流行的概念&#xff0c;使容器管理流行起来。Docker 处于这一转变的核心&#xff0c;帮助组织无缝地采用容器化技术。最近&#xff0c;Docker 用例遍布所有行业&#xff0c;无论规模大小和性质如何。 什么是Docker&…

Windows--使用node.js的免安装版本

原文网址&#xff1a;Windows--使用node.js的免安装版本_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Windows下如何使用node.js的免安装版本。 下载 1.访问官网 https://nodejs.org/en 记住这个版本号&#xff0c;这个是长期支持的版本。 2.找到压缩包 点击其他下载&#…

windows系统中,在cmd窗口演练 Redis 基本操作命令

文章目录 一、Redis 介绍1.1 Redis 的应用场景1.2 Redis 的特点 二、Windows版Redis安装三、Redis Desktop Manager安装四、Redis 常用基本操作4.1 查看操作4.2 操作string类型的命令4.2.1 设置获取Key4.2.2 MSET&#xff08;Multi&#xff09;支持批量设置key、MGET支持批量获…

平时使用Xshell能连接虚拟机,现在突然连接不上

问题&#xff1a;平时使用Xshell能连接虚拟机&#xff0c;现在突然连接不上&#xff0c;使用ip addr 命令查看ip地址 ens33 接口状态为 DOWN&#xff0c;没有分配IP地址&#xff0c;这通常意味着该网络接口未激活或存在配置问题。&#xff08;因为平时能连接&#xff0c;就说明…

DNS代理是什么?浅析DNS代理的工作原理及应用

DNS代理作为计算机网络中重要的一环&#xff0c;扮演着连接用户和互联网服务的关键角色。来了解DNS代理的定义、功能、工作原理以及在网络中的应用场景和重要性吧。 一、理解DNS代理。 DNS代理充当在用户和真正的DNS服务器之间的中介。它接收来自用户端的DNS查询请求&#xf…

std::function和bind绑定器

本文来自《深入应用C11 代码优化与工程级应用》 std::function和std::bind&#xff0c;使我们使用标准库函数时更加方便&#xff0c;且还能方便地实现延迟求值。 1.可调用对象(Callable Objects) 可调用对象有如下几种定义&#xff1a; (1)是一个函数指针 #include<ios…

php elasticsearch/elasticsearch使用apikey访问接口

此处使用的windows版es和kibana。 1.前提&#xff1a;以安装好es和kibana并正常运行&#xff0c;记得保存es安装完成时提示的账号密码。 2.登录kibana,创建索引并加入几条数据,可以通过kibana界面添加或者通过调用接口添加&#xff0c;非重点不赘述了。 3.添加ApiKey, 使用…

Linux 部署 Harbor 镜像仓库详解

文章目录 安装 Docker安装 Harbor访问 Harbor 安装 Docker 本次部署流程使用的是1台阿里云ECS&#xff0c;Ubuntu 22.04&#xff0c;2核4G。 首先需要做的是在当前服务器上&#xff0c;安装好 Docker&#xff0c;参考链接如下&#xff1a; https://blog.csdn.net/weixin_4659…

ESD防静电闸机如何保护汽车电子产品

随着汽车电子技术的快速发展&#xff0c;汽车中集成了越来越多的电子设备&#xff0c;如车载信息娱乐系统、自动驾驶传感器、驾驶辅助系统等。静电放电可能导致电子组件的损坏、性能下降&#xff0c;甚至使整个系统失效。因此&#xff0c;如何有效保护汽车电子产品免受静电损害…

【【自动驾驶】车辆运动学模型】

【自动驾驶】车辆运动学模型 1. 引言2. 以车辆重心为中心的单车模型2.1 模型介绍2.2 滑移角 β \beta β 的推导2.2 航向角 ψ \psi ψ推导过程&#xff1a;2.3 滑移角 β \beta β2.3 Python代码实现2.4 C代码实现 3. 前轮驱动的单车模型3.1 模型介绍3.3 Python代码实现3.4 …

软件I2C的代码

I2C的函数 GPIO的配置——scl和sda都配置为开漏输出 void MyI2C_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruture;GPIO_InitStruture.GPIO_Mode GPIO_Mode_Out_OD;GPIO_InitStruture.GPIO_PinGPIO_Pin_10 | GPIO_Pin_…