Go之Web急速入门Gin+Gorm框架

简介

只作为快速入门、了解Go的Gin+Gorm框架的demo,不能作为企业级开发。

详细用法请看官网
《Gin官网》
《Gorm官网》

使用GoLand创建Go项目(默认modules)

go版本1.22.2

需要设置代理下载go相关软件包,否则软件包可能无法下载。

go 复制代码
https://goproxy.cn

目录结构

go.mod就是管理相关软件的版本信息,如果你学习过Java,可以简单理解mod就是maven、gradle等构建工具

安装 Gin + Gorm 软件包

控制台执行以下三条命令,否则启动会报错。

gin web框架

gorm orm框架

gorm mysql 数据库驱动

shell 复制代码
go get -u github.com/gin-gonic/gin
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

创建mysql数据库

创建main.go文件

go有且仅有一个main函数,这个是跟java不太一样的地方,java是允许有多个main函数的。

go 复制代码
//包的概念
package main

//引入的包路径
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"net/http"
	"path"
	"time"
)

//定义一个结构体
type UserInfo struct {
	gorm.Model        //gorm模型默认包含 ID、CreatedAt、UpdatedAt、DeletedAt 4个变量
	Username   string `gorm:"index" form:"username" json:"username" binding:"required"`
	Password   string `form:"password" json:"password" binding:"required"`
}

// 自定义 gin 中间件 MyHandlerFunc
func MyHandlerFunc(invoke bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		if invoke {
			fmt.Println("请求开始......")
			start := time.Now()
			//在请求上下文中设置值,后续的处理函数可以获取到该值
			c.Set("token", "1")
			token, ok := c.Get("token")
			if !ok {
				c.JSON(http.StatusUnauthorized, gin.H{
					"code":    http.StatusUnauthorized,
					"message": "未授权",
				})
				return
			}
			fmt.Printf("token =  %v\n", token)
			c.Next()
			//c.Abort()表示阻止代码继续往下执行
			//c.Abort()
			//计算请求耗时
			cost := time.Since(start)
			fmt.Println("请求耗时:", cost)
			fmt.Println("请求结束......")
		} else {
			c.Next()
		}
	}
}

//main函数
func main() {
	//0.在控制台输入 go get -u github.com/gin-gonic/gin 安装 Gin 软件包
	//返回默认路由引擎
	r := gin.Default()

	//指定用户使用GET请求访问/hello,并执行匿名函数,返回JSON格式map[string]的数据
	//1.返回map(一般用于临时返回,不推荐)
	r.GET("/map", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "Hello World",
		})
	})

	/*
		2.返回结构体【推荐】(类似java中的对象,但是首字母必须大写,否则无法进行序列化和反序列化)
		以及灵活使用tag来对结构体进行定制化操作
	*/
	type Person struct {
		//后面写`json:"name"`表示如果以json返回,则变量名使用name
		Name    string `json:"name"`
		Message string `json:"message"`
		Age     int    `json:"age"`
	}

	r.GET("/struct", func(c *gin.Context) {
		data := Person{"Meta39", "Java 学习 Go", 25}
		c.JSON(http.StatusOK, data)
	})

	//3.请求地址携带参数的请求【不推荐】(主要使用c.Query,访问:localhost:8080/query?name=Meta39&age=25,浏览器返回Meta39,控制台输出age: 25)
	r.GET("/query", func(c *gin.Context) {
		name := c.Query("name")
		age := c.Query("age")
		c.JSON(http.StatusOK, gin.H{
			"name": name,
		})
		fmt.Printf("age: %s\n", age)
	})

	//4.获取URL路径参数【推荐】(根据用户ID查询用户信息,访问:localhost:8080/user/1)
	//relativePath也可以是/user/:id/:age,多个组合
	r.GET("/user/:id", func(c *gin.Context) {
		id := c.Param("id")
		c.JSON(http.StatusOK, gin.H{
			"id":   id,
			"name": "Meta39",
			"age":  25,
			"sex":  "Man",
		})
	})

	//5.参数绑定ShouldBind【推荐】(访问:localhost:8080/shouldBind,在body {"username": "mata","password": "123456"})
	r.POST("/shouldBind", func(c *gin.Context) {
		//声明UserInfo类型的变量u
		var u UserInfo
		//& 类似于 Spring @RequestBody 注解
		err := c.ShouldBind(&u)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			return
		}
		fmt.Printf("%+v\n", u)
		c.JSON(http.StatusOK, gin.H{
			"success": "ok",
		})
	})

	//6.文件上传
	r.POST("/upload", func(c *gin.Context) {
		//从请求中读取文件
		f, err := c.FormFile("file")
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			return
		}
		//将读取的文件保存到本地
		dst := path.Join("./", f.Filename)
		_ = c.SaveUploadedFile(f, dst)
		c.JSON(http.StatusOK, gin.H{
			"success": "ok",
		})
	})

	//7.处理404
	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{
			"code":    404,
			"message": "404 Not Found",
			"data":    nil,
		})
	})

	//8.路由组【支持嵌套】(类似SpringBoot里的@RequestMapping)
	userGroup := r.Group("/users")
	{
		//根据用户id查询用户
		userGroup.GET("/:id", func(c *gin.Context) {
			id := c.Param("id")
			c.JSON(http.StatusOK, gin.H{
				"id":   id,
				"name": "Meta39",
			})
		})
		//创建用户
		userGroup.POST("/", func(c *gin.Context) {
			var u UserInfo
			err := c.ShouldBind(&u)
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{
					"error": err.Error(),
				})
			}
			fmt.Printf("创建用户:%+v\n", u)
			c.JSON(http.StatusOK, gin.H{
				"success": "ok",
			})
		})
	}

	//9.定义中间件,一般放到路由组Group(类似Java中的filter过滤器)
	r.GET("/handlerFunc", MyHandlerFunc(true), func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "MyHandlerFunc",
		})
	})

	//10.在控制台输入 go get -u gorm.io/gorm 安装 gorm 软件包
	//11.在控制台输入 go get -u gorm.io/driver/mysql 安装 gorm mysql 数据库驱动软件包
	dsn := "root:123456@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
	db, gormErr := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if gormErr != nil {
		panic("failed to connect database")
	}

	// 迁移 schema
	_ = db.AutoMigrate(&UserInfo{})
	var userInfo UserInfo
	// Create
	db.Create(&UserInfo{Username: "Meta39", Password: "123456"})
	// Read
	db.First(&userInfo, 1)                        // 根据整型主键查找
	db.First(&userInfo, "username = ?", "Meta39") // 查找 username 字段值为 Meta39 的记录

	// Update - 将 userInfo 的 Password 更新为 654321
	db.Model(&userInfo).Update("Password", "654321")
	// Update - 更新多个字段
	db.Model(&userInfo).Updates(UserInfo{Username: "Meta", Password: "123"}) // 仅更新非零值字段
	db.Model(&userInfo).Updates(map[string]interface{}{"Username": "Meta1", "Password": "234"})

	// Delete - 删除 userInfo(默认:软删除,即:打上删除标志,如在deleted_at填充时间,表示这条数据已经被删除了)
	//db.Delete(&userInfo, 1)
	//永久删除
	//db.Unscoped().Delete(&userInfo, 1)

	//启动服务不指定端口号,则默认:8080
	ginErr := r.Run(":8080")

	//启动异常处理并输出异常信息
	if ginErr != nil {
		fmt.Printf("ginErr:%v\n", ginErr)
		return
	}

}

控制台执行

shell 复制代码
go run .\main.go

打开浏览器访问localhost:8080/map会输出JSON格式的Hello World

数据库会有一条id = 1的记录

相关推荐
互联网中的一颗神经元8 小时前
10. Large 对象分配:直接路径
开发语言·golang
microrain10 小时前
从关系库硬扛到专业时序引擎:SagooIoT时序数据存储的架构取舍
物联网·golang·开源·sagooiot
Vect__12 小时前
channel 底层剖析
golang
李燚15 小时前
数据库迁移不翻车:golang-migrate 实战,143 个 DDL 有序执行(第97篇-E83)
golang·agent·multiagent·migrate·eino·subagent·deepflux
念何架构之路16 小时前
Gin内置中间件详解
中间件·gin
运维开发笔记18 小时前
7.1 Go Map 基础
golang
运维开发笔记18 小时前
7.2 Go Map 进阶
golang
西瓜很甜哟1 天前
golang每日十题第2期
golang
程序员小八7771 天前
Go 语言特性
开发语言·后端·golang
X1A0RAN2 天前
pytest 动态报告:数据可视化篇 —— 用 Golang + Echo 打造自动化测试任务可视化平台
信息可视化·golang·pytest