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

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: Go语言web极速入门-(Gin+Mysql实现后端接口)

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

Gin 的特点有:

简单易用:Gin 提供了一组简单的 API,使用起来非常方便。

高性能:Gin 在性能方面表现优秀,常常可以达到接近原生性能的水平。

支持中间件:Gin 支持使用中间件来扩展框架的功能,可以方便地实现认证、日志、跨域等功能。

支持多种模板引擎:Gin 可以使用多种模板引擎来渲染 HTML 模板,例如 Pongo2、Amber、Gin-Artemis 等。

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

安装 Gin 框架:使用 go get 命令安装 Gin 框架,或者在你的代码中导入 github.com/gin-gonic/gin 包。

初始化 Gin 应用:使用 gin.Default() 函数初始化一个新的 Gin 应用,或者使用 gin.New() 函数创建一个新的 Gin 应用并自定义配置。

定义路由和路由处理器:使用 Gin 应用的 GET、POST、`

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

结果

73d8c9be8b2a4960a39693770de0ac9a.png

查询数据库,发现数据已写入

73d8c9be8b2a4960a39693770de0ac9a.png

业务代码:保存多条信息(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”}]

73d8c9be8b2a4960a39693770de0ac9a.png

结果

{“message”: “Data saved successfully”}

数据库信息

73d8c9be8b2a4960a39693770de0ac9a.png

业务代码:上传文件并保存(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上传文件

image.png

运行结果

File uploaded successfully

73d8c9be8b2a4960a39693770de0ac9a.png


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
5月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
495 4
|
5月前
|
Cloud Native 安全 Java
Go语言深度解析:从入门到精通的完整指南
🌟蒋星熠Jaxonic,Go语言探索者。深耕云计算、微服务与并发编程,以代码为笔,在二进制星河中书写极客诗篇。分享Go核心原理、性能优化与实战架构,助力开发者掌握云原生时代利器。#Go语言 #并发编程 #性能优化
537 43
Go语言深度解析:从入门到精通的完整指南
|
10月前
|
存储 Go
Go语言之接口与多态 -《Go语言实战指南》
Go 语言中的接口是实现多态的核心机制,通过一组方法签名定义行为。任何类型只要实现接口的所有方法即视为实现该接口,无需显式声明。本文从接口定义、使用、底层机制、组合、动态行为到工厂模式全面解析其特性与应用,帮助理解 Go 的面向接口编程思想及注意事项(如 `nil` 陷阱)。
276 22
|
5月前
|
Java 编译器 Go
【Golang】(5)Go基础的进阶知识!带你认识迭代器与类型以及声明并使用接口与泛型!
好烦好烦好烦!你是否还在为弄不懂Go中的泛型和接口而烦恼?是否还在苦恼思考迭代器的运行方式和意义?本篇文章将带你了解Go的接口与泛型,还有迭代器的使用,附送类型断言的解释
274 3
|
5月前
|
开发框架 前端开发 Go
【GoGin】(0)基于Go的WEB开发框架,GO Gin是什么?怎么启动?本文给你答案
Gin:Go语言编写的Web框架,以更好的性能实现类似Martini框架的APInet/http、Beego:开源的高性能Go语言Web框架、Iris:最快的Go语言Web框架,完备的MVC支持。
519 1
|
6月前
|
Cloud Native 安全 Java
Go语言深度解析:从入门到精通的完整指南
🌟 蒋星熠Jaxonic,执着的星际旅人,用Go语言编写代码诗篇。🚀 Go语言以简洁、高效、并发为核心,助力云计算与微服务革新。📚 本文详解Go语法、并发模型、性能优化与实战案例,助你掌握现代编程精髓。🌌 从goroutine到channel,从内存优化到高并发架构,全面解析Go的强大力量。🔧 实战构建高性能Web服务,展现Go在云原生时代的无限可能。✨ 附技术对比、最佳实践与生态全景,带你踏上Go语言的星辰征途。#Go语言 #并发编程 #云原生 #性能优化
|
9月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
9月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。
|
10月前
|
存储 JSON Go
Go语言之空接口与类型断言
本文介绍了 Go 语言中空接口(`interface{}`)和类型断言的核心概念及其应用。空接口可存储任意类型数据,适用于通用函数、动态数据结构与 JSON 解析等场景;类型断言用于将接口变量还原为具体类型,推荐使用带 `ok` 的写法以避免程序崩溃。此外,文章通过示例讲解了 `type switch` 类型判断与 JSON 处理技巧,并总结了空接口的注意事项,强调滥用可能导致类型安全性降低。内容深入浅出,帮助开发者灵活运用这些特性。
287 15
|
10月前
|
Go
Go语言接口的定义与实现
Go 语言的接口提供了一种灵活的多态机制,支持隐式实现和抽象编程。本文介绍了接口的基本定义、实现方式、空接口的使用、类型断言以及接口组合等核心概念,并探讨了接口与 nil 的关系及应用场景。通过示例代码详细说明了如何利用接口提升代码的可扩展性和可测试性,总结了接口的关键特性及其在依赖注入、规范定义和多态调用中的重要作用。
383 14