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的记录

相关推荐
007php0071 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
桃园码工5 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
桃园码工5 小时前
1-Gin介绍与环境搭建 --[Gin 框架入门精讲与实战案例]
go·gin·环境搭建
MClink8 小时前
Go怎么做性能优化工具篇之pprof
开发语言·性能优化·golang
m0_7482546611 小时前
go官方日志库带色彩格式化
android·开发语言·golang
Algorithm157614 小时前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
Narutolxy15 小时前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
Hello.Reader15 小时前
全面解析 Golang Gin 框架
开发语言·golang·gin
hkNaruto1 天前
【P2P】【Go】采用go语言实现udp hole punching 打洞 传输速度测试 ping测试
golang·udp·p2p
入 梦皆星河1 天前
go中常用的处理json的库
golang