Go语言web极速入门-(Gin+Mysql实现后端接口)

news2025/1/11 10:03:47


        在写代码之前,我们先了解一下Gin框架,Gin 是一个轻量级的 Go 语言 Web 框架,旨在提供一种简单、快速的方式来构建 Web 应用程序。它提供了一组简单的 API,可以让你轻松地处理 HTTP 请求、路由、模板渲染、中间件等功能。

Gin 的特点有:

  • 简单易用:Gin 提供了一组简单的 API,使用起来非常方便。
  • 高性能:Gin 在性能方面表现优秀,常常可以达到接近原生性能的水平。
  • 支持中间件:Gin 支持使用中间件来扩展框架的功能,可以方便地实现认证、日志、跨域等功能。
  • 支持多种模板引擎:Gin 可以使用多种模板引擎来渲染 HTML 模板,例如 Pongo2、Amber、Gin-Artemis 等。

使用 Gin 框架开发 Web 应用程序的一般流程如下:

  1. 安装 Gin 框架:使用 go get 命令安装 Gin 框架,或者在你的代码中导入 github.com/gin-gonic/gin 包。
  2. 初始化 Gin 应用:使用 gin.Default() 函数初始化一个新的 Gin 应用,或者使用 gin.New() 函数创建一个新的 Gin 应用并自定义配置。
  3. 定义路由和路由处理器:使用 Gin 应用的 GETPOST、`

Gin框架github地址 ⬅️点击此处

接下来我们来解决框架安装问题,使用官方的方式安装会超时

安装Gin及安装框架超时问题解决参考地址 ⬅️点击此处

除了gin之外还需要安装Mysql相关包~

go get -u github.com/go-sql-driver/mysql

Mysql操作

建表

DROP TABLE IF EXISTS `user_test`;
CREATE TABLE `user_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户主键id',
  `name` varchar(50) NOT NULL COMMENT '用户姓名',
  `phone` varchar(50) NOT NULL COMMENT '用户手机号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


增加测试数据

insert into user_test(`name`, `phone`) values ("Mary", "13111110000");
insert into user_test(`name`, `phone`) values ("Mr Li", "13989890000");

代码实现

需要导的包

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/http"
	"strconv"
)

数据库连接函数及常量、数据传输结构体

// 数据库连接信息参数
const (
	USERNAME = "root"      //mysql账号用户名
	PASSWORD = "rootroot"  //mysql账号密码
	NETWORK  = "tcp"       //连接方式
	SERVER   = "127.0.0.1" //ip
	PORT     = 3306        //port
	DATABASE = "mysql"     //库名
)

// 用于信息传输的结构体数据
type User_Test struct {
	Name  string `json:"name"` //起别名
	Id    int    `json:"id"`
	Phone string `json:"phone"`
}

// 数据库相关函数
func getDBConnect() (*sql.DB, error) {
	conn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s", USERNAME, PASSWORD, NETWORK, SERVER, PORT, DATABASE)
	//获取DB连接驱动
	db, err := sql.Open("mysql", conn)
	if err != nil {
		log.Println("do connect db error:", err.Error())
	}
	return db, err
}

业务代码:获取一条信息(GET请求)

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()
	//(根据id获取用户)启动后的访问路径http://localhost:8080/getUserById?id=1
	r.GET("/getUserById", func(c *gin.Context) {
		// 接口参数获取
		id := c.Query("id")
		fmt.Println("ID:", id)
		// 接口参数获取
		params := c.Request.URL.Query()
		fmt.Println("Params:", params)
		//调用数据库函数
		resultInfo := getOneInfoFromDB(id)
		//接口返回数据组装
		c.JSON(http.StatusOK, gin.H{
			"user": resultInfo,
		})
	})

	r.Run() // listen and serve on 0.0.0.0:8080
	//r.Run("8888") // listen and serve on 0.0.0.0:8888
}


func getOneInfoFromDB(userId string) string {
	if "" == userId || 0 == len(userId) {
		//do nothing
		return ""
	}

	// Connect to the database
	db, err := getDBConnect()

	if err != nil {
		log.Println("do saveUser error:", err.Error())
	}

	//Passing parameters using placeholders
	rows, err := db.Query("SELECT * FROM `user_test` where id = ?", userId)
	if nil != err {
		log.Println("do query error:", err)
		return ""
	}

	//close
	defer rows.Close()
	var result string
	for rows.Next() {
		var user User_Test
		//fill information
		err = rows.Scan(&user.Id, &user.Name, &user.Phone)
		if err != nil {
			panic(err.Error())
		}
		//serialize information
		marshal, err := json.Marshal(&user)
		if nil != err {
			log.Println("发生错误", err)
			return ""
		}
		result = string(marshal)
	}

	defer db.Close()

	// Make sure the connection is available
	err = db.Ping()
	if err != nil {
		log.Println("do db.Ping() error:", err.Error())
	}
	return result
}

运行后浏览器访问:http://localhost:8080/getUserById?id=1

结果

{“user”:“{“name”:“Mary”,“id”:1,“phone”:“13111110000”}”}

业务代码:获取多条信息(GET请求)

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()

	//(获取所有用户)启动后的访问路径http://localhost:8080/getMultipleUsers?limit=3
	r.GET("/getMultipleUsers", func(c *gin.Context) {
		// 获取参数
		limit, err := strconv.Atoi(c.Query("limit"))
		if err != nil {
			// 如果参数不合法,返回错误
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit parameter"})
			return
		}

		//调用数据库函数
		resultInfo := getMultipleUserFromDB(limit)
		//接口返回数据组装
		c.JSON(http.StatusOK, gin.H{
			"users": resultInfo,
		})
	})

	r.Run() // listen and serve on 0.0.0.0:8080
	//r.Run("8888") // listen and serve on 0.0.0.0:8888
}

// 获取多条用户信息
// limit:返回条数
func getMultipleUserFromDB(limit int) []User_Test {
	resultUsers := make([]User_Test, 0, limit)

	// Connect to the database
	db, err := getDBConnect()

	if err != nil {
		log.Println("do saveUser error:", err.Error())
	}

	//Passing parameters using placeholders
	rows, err := db.Query("SELECT * FROM `user_test` limit ?", limit)
	if nil != err {
		log.Println("do query error:", err)
		return resultUsers
	}

	//close
	defer rows.Close()
	for rows.Next() {
		var user User_Test
		//fill information
		err = rows.Scan(&user.Id, &user.Name, &user.Phone)
		if err != nil {
			panic(err.Error())
		}
		//append info slice
		resultUsers = append(resultUsers, user)
	}

	defer db.Close()

	// Make sure the connection is available
	err = db.Ping()
	if err != nil {
		log.Println("do db.Ping() error:", err.Error())
	}

	return resultUsers
}

运行后浏览器访问http://localhost:8080/getMultipleUsers?limit=3,获取三条信息

结果

{“users”:[{“name”:“Mary”,“id”:1,“phone”:“13111110000”},{“name”:“Mr Li”,“id”:2,“phone”:“13989890000”},{“name”:“路人一”,“id”:3,“phone”:“13674749999”}]}

业务代码:保存一条信息(POST请求)

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()
	//POST请求(保存用户),使用postman操作
	r.POST("/saveUser", func(c *gin.Context) {
		// 接口参数获取
		name := c.PostForm("name")
		phone := c.PostForm("phone")
		user := User_Test{Name: name, Phone: phone}
		// 接口参数获取
		params := c.Request.URL.Query()
		log.Println("Params:", params)
		//调用数据库函数
		resultFlag := saveUser(user)
		if true == resultFlag {
			//接口返回数据组装
			c.JSON(http.StatusOK, gin.H{
				"message": "Data saved successfully",
			})
		} else {
			c.JSON(http.StatusExpectationFailed, gin.H{
				"message": "Data saved failed!",
			})
		}
	})

	r.Run() // listen and serve on 0.0.0.0:8080
	//r.Run("8888") // listen and serve on 0.0.0.0:8888
}

func saveUser(user User_Test) bool {
	var flag bool = false
	// Connect to the database
	db, err := getDBConnect()

	//操作成功返回true,保存出错打印错误返回false
	_, err = db.Exec("INSERT INTO user_test (`name`, `phone`) VALUES (?, ?)", user.Name, user.Phone)
	if err != nil {
		log.Println("do saveUser error:", err.Error())
		flag = false
	}

	flag = true

	defer db.Close()

	// Make sure the connection is available
	err = db.Ping()
	if err != nil {
		log.Println("do db.Ping() error:", err.Error())
	}

	return flag
}

运行后使用postman操作
url:localhost:8080/saveUser

结果
在这里插入图片描述
查询数据库,发现数据已写入

在这里插入图片描述

业务代码:保存多条信息(POST请求)[使用mysql事务]

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()
	//POST请求(保存多个用户),使用postman操作
	r.POST("/saveMultipleUser", func(c *gin.Context) {
		// 接口参数获取
		recordsParam := c.PostForm("records")
		log.Println(recordsParam)
		// 定义一个结构体数组
		var records []User_Test
		//BindJSON方法是一个函数,用于解析 JSON(JavaScript 对象表示法)字符串并将其绑定到结构体中。
		err := json.Unmarshal([]byte(recordsParam), &records)

		if err != nil {
			log.Println("json.Unmarshal error:", err)
			c.JSON(http.StatusExpectationFailed, gin.H{
				"message": "Data saved failed!",
			})
			return
		}

		//调用数据库函数
		//如果有一个保存失败返回失败
		resultFlag := saveUsers(records)
		if resultFlag == false {
			c.JSON(http.StatusExpectationFailed, gin.H{
				"message": "Data saved failed!",
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"message": "Data saved successfully",
		})
	})

	r.Run() // listen and serve on 0.0.0.0:8080
	//r.Run("8888") // listen and serve on 0.0.0.0:8888
}


//保存多条用户,加入事务管理,全部保存成功提交事务,只要部分数据失败执行数据回滚
func saveUsers(users []User_Test) bool {
	saveFlag := true
	// Connect to the database
	db, err := getDBConnect()

	//开启数据库事务,用于保存失败后回滚数据
	tx, err := db.Begin()
	if err != nil {
		// handle error
	}

	for _, user := range users {
		//操作成功返回true,保存出错打印错误返回false
		_, err = db.Exec("INSERT INTO user_test (`name`, `phone`) VALUES (?, ?)", user.Name, user.Phone)
		if err != nil {
			log.Println("do saveUser error:", err.Error())
			saveFlag = false
		}
	}

	//如果有数据保存失败,执行回滚
	if false == saveFlag {
		tx.Rollback()
		return saveFlag
	}

	//全部保存成功后提交事务
	err = tx.Commit()
	if err != nil {
		// handle error
	}

	return saveFlag
}

使用postman请求,参数:

records : [{“name”:“Lilei”,“phone”:“14133331111”},{“name”:“Mr Zhang”,“phone”:“15122223333”},{“name”:“路人二”,“phone”:“18113131111”}]

在这里插入图片描述

结果

{“message”: “Data saved successfully”}

数据库信息

在这里插入图片描述

业务代码:上传文件并保存(POST请求)

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()
	//上传文件并保存
	r.POST("/upload", func(c *gin.Context) {
		// Get the uploaded file from the request
		file, err := c.FormFile("file")
		if err != nil {
			c.AbortWithError(http.StatusBadRequest, err)
			return
		}

		// Save the uploaded file to a specified directory
		if err := c.SaveUploadedFile(file, "file/"+file.Filename); err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		// Return a success response
		c.String(http.StatusOK, "File uploaded successfully")
	})
	r.Run() // listen and serve on 0.0.0.0:8080
	//r.Run("8888") // listen and serve on 0.0.0.0:8888
}

使用postman上传文件
在这里插入图片描述
运行结果

File uploaded successfully

在这里插入图片描述

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

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

相关文章

指令重排现象,多线程情况下,你的代码执行顺序可能不是顺序执行,结果会不一致

一、思考多线程情况下,程序执行顺序是否是按顺序执行 首先定义x 0; y 0; a 0; b 0;然后思考a 1;x b;两行代码谁先执行问题? 二、实战测试 2.1 测试逻辑 首先默认为x 0; y 0; a 0; b 0;然后开启两个线程;线程1执行:a…

java 瑞吉外卖day6 移动端 套餐 菜品展示 购物车加减,清空,用户下单

导入用户地址簿相关功能代码 菜品展示 购物车模块 加入购物车: PostMapping("/add") public R add(RequestBody ShoppingCart shoppingCart){//获取当前线程用户的id并设置到shoppingCart中Long currentId BaseContext.getCurrentId();shoppingCart.set…

使用3种不同的算法从倾斜风速计中检索3个风分量(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

如何确保电子招标的透明度、公正性和及时性?

采购的主要目标是确保以竞争的方式及时获得货物、工程和服务,确保资金的最佳价值,同时保持透明度和公正性。特别是在公共或非盈利组织中,他们利用捐助者的资金来完成任务,必须强调透明度、公平性和及时性。因此,更需要…

图像分类:Pytorch图像分类之--AlexNet模型

文章目录前言数据的处理数据集的下载数据集的划分AlexNet介绍程序的实现model.pyDropout()函数train.py数据预处理导入数据集前言 搭建AlexNet来进行分类模型的训练,大致训练流程和图像分类:Pytorch图像分类之–LetNet模型差不多,两者最大的…

NewStarCTF公开赛week4密码学题目wp

目录前言一、LCG Revenge1.原题2.解题思路1) 考察知识2) 分析本质3.解题Python脚本二、代数关系1.原题2.解题思路3.解题Python脚本前言 哎呦喂,第三周勉强做了一道题,果然第四周就爆零了QAQ ———————————悲伤的分割线——————————— …

Apache Flink 作业图 JobGraph 与执行图 ExecutionGraph

由 Flink 程序直接映射成的数据流图(dataflow graph),也被称为逻辑流图(logical StreamGraph)。到具体执行环节时,Flink 需要进一步将逻辑流图进行解析,转换为物理执行图。 在这个转换过程中&am…

思派健康在港交所上市:九成收入靠“卖药”,持续大额亏损

12月23日,思派健康(HK:00314)在港交所上市。本次上市,思派健康的发行价格为18.60港元/股,全球发售991.94万股。据此前招股书介绍,思派健康将自全球发售收取所得款项净额约1.204亿港元。 招股书显示&#x…

每月明星计划(12 月),ECHO:我们的意见万岁!

我们很高兴 12 月的 MSP 比我们预期的要成功得多。提交项目的数量和质量甚至优于 11 月的 MSP。 在 11 月的 MSP 竞赛中,被选中的项目Owlando以其先进的 UGC Metaverse 概念及其与朋友创建、交流和玩耍的有趣方式引起了评委的注意,最终将结果构建到 NFT…

百度百科创建词条步骤是怎样的?

互联网时代,在百度上搜索人物、企业、品牌、作品之类的信息都会出现相关百科词条,一般在首页前几名的位置,权重非常高,获得的用户流量也是非常庞大的。 基于百度百科的宣传背书,大大提高了内容的可信度和知名度&#…

【详细学习SpringBoot源码之属性配置文件加载原理(application.properties|application.yaml)-7】

一.知识回顾 【0.SpringBoot专栏的相关文章都在这里哟,后续更多的文章内容可以点击查看】 【1.SpringBoot初识之Spring注解发展流程以及常用的Spring和SpringBoot注解】 【2.SpringBoot自动装配之SPI机制&SPI案例实操学习&SPI机制核心源码学习】 【3.详细学…

教室管理系统

开发工具(eclipse/idea/vscode等):idea 数据库(sqlite/mysql/sqlserver等):mysql 功能模块(请用文字描述,至少200字): 关于这个系统的具体功能主要包括教师,学生,课程,教室还有班级这几个实体。…

acwing基础课——二分图

由数据范围反推算法复杂度以及算法内容 - AcWing 常用代码模板3——搜索与图论 - AcWing 基本思想: 二分图:在一张图中,如果能把全部点分到两个集合,且保证两个集合内部没有任何一条边,图中的边只存在于两个集合之间&#xff0c…

制造业ERP如何做好成本核算管理?

随着制造业的不断发展,制造业成本管理中存在的问题已成为制造业企业关注的焦点。在传统粗放的手工模式下,制造企业成本核算工作量会非常巨大,不能对成本信息进行实时监控,只能在成本费用发生后进行归集核算,数据有滞后…

PS CS6视频剪辑基本技巧(四)字幕居中和滚动字幕

在第三讲中介绍了添加字幕的方法,但有的读者可能会发现,字幕模板设定的字幕起始是固定不变的,假如设定的起始位置是最左边,那么无论一行字多有多少个,都是从最左边开始排。那么有没有办法可以让字幕可以批量居中呢&…

大数据技术之SparkCore

文章开篇先简单介绍一下SparkCore: Spark Core是spark的核心与基础,实现了Spark的基本功能,包含任务调度,内存管理,错误恢复与存储系统交互等模块 Spark Core中包含了对Spark核心API——RDD API(弹性分布式数据集)的定…

你以为传切片就是传引用了吗?

xdm ,我们在写 golang 的时候,引用和传值傻傻分不清,就例如我们传 切片 的时候,你能分清楚你传的切片是传值还是传引用呢? 引用是什么? 引用就是给对象起另一个名字,引用类型引用另一种类型 引…

【自省】线程池里的定时任务跑的可欢了,可咋停掉特定的任务?

客户端抢到分布式锁之后开始执行任务,执行完毕后再释放分布式锁。持锁后因客户端异常未能把锁释放,会导致锁成为永恒锁。为了避免这种情况,在创建锁的时候给锁指定一个过期时间。到期之后锁会被自动删除掉,这个角度看是对锁资源的…

Going Home(二分图最大权匹配KM算法)

C-Going Home_2022图论班第一章图匹配例题与习题 (nowcoder.com) 在网格地图上有n个小人和n座房子。在每个单位时间内,每个小人都可以水平或垂直地移动一个单位步到相邻点。对于每个小矮人,你需要为他每走一步支付1美元的旅费,直到他进入一所…

Git命令笔记,下载、提交代码、解决冲突、分支处理

下载代码,复制https地址到本地文件夹,鼠标右键选择git bash后输入命令 git clone https://gitee.com/View12138/ViewFaceCore.git 下载后初始化:git init 下载代码后不运行报错(如下),需要执行初始化命令…