GoLang Web框架Gin

本文最后更新于:2 小时前

网络请求Method

package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()

	r.GET("/ping/:id", func(c *gin.Context) {
		id := c.Param("id")
		user := c.DefaultQuery("user", "qiuqian")
		password := c.Query("password")
		c.JSON(200, gin.H{
			"success":  "true",
			"id":       id,
			"user":     user,
			"password": password,
		})
	})

	r.POST("/ping", func(c *gin.Context) {
		user := c.DefaultPostForm("user", "aowu")
		password := c.PostForm("password")
		c.JSON(200, gin.H{
			"success":  "true",
			"user":     user,
			"password": password,
		})
	})

	r.DELETE("/ping/:id", func(c *gin.Context) {
		id := c.Param("id")
		c.JSON(200, gin.H{
			"success": "true",
			"id":      id,
		})
	})

	r.PUT("/ping", func(c *gin.Context) {
		user := c.DefaultPostForm("user", "aowu")
		password := c.PostForm("password")
		c.JSON(200, gin.H{
			"success":  "true",
			"user":     user,
			"password": password,
		})
	})
	r.Run(":8088")
}

Bind

package main

import "github.com/gin-gonic/gin"

type PostParams struct {
	Name   string `json:"name" uri:"name" form:"name"`
	Gender bool   `json:"gender" uri:"gender" form:"gender"`
	Age    int    `json:"age" uri:"age" form:"age"`
}

func main() {
	r := gin.Default()

	r.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		// 这里修改传参方式
		err := c.ShouldBindQuery(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg":  "报错了",
				"data": gin.H{},
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "success",
				"data": p,
			})
		}
	})
	r.Run(":8088")
}

binding

必须有参数,否则报错

package main

import "github.com/gin-gonic/gin"

type PostParams struct {
	Name   string `json:"name" binding:"required"`
	Gender bool   `json:"gender" binding:"required"`
	Age    int    `json:"age" binding:"required"`
}

func main() {
	r := gin.Default()

	r.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		// 这里修改传参方式
		err := c.ShouldBindJSON(&p)
		if err != nil {
			c.JSON(200, gin.H{
				"msg":  "报错了",
				"data": gin.H{},
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "success",
				"data": p,
			})
		}
	})
	r.Run(":8088")
}

自定义校验: age must > 18

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

type PostParams struct {
	Name   string `json:"name"`
	Gender bool   `json:"gender"`
	// binging里面的用逗号分割,不可以加空格!!
	Age    int    `json:"age" binding:"required,mustBig"`
}

// 自定义校验
func mustBig(fl validator.FieldLevel) bool {
	fmt.Println(fl.Field().Interface().(int))
	if fl.Field().Interface().(int) <= 18 {
		return false
	}
	return true
}

func main() {
	r := gin.Default()

	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterValidation("mustBig", mustBig)
	}

	r.POST("/testBind", func(c *gin.Context) {
		var p PostParams
		// 这里修改传参方式
		err := c.ShouldBindJSON(&p)
		if err != nil {
			fmt.Println(err.Error())
			c.JSON(200, gin.H{
				"msg":  "报错了",
				"data": gin.H{},
			})
		} else {
			c.JSON(200, gin.H{
				"msg":  "success",
				"data": p,
			})
		}
	})
	r.Run(":8088")
}

中间件和路由分组

洋葱模型 鉴权 日志等

中间件: 请求达到路由放大前,后的一系列操作,有点类似 Spring 的面向切面编程

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func middle() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("我在方法前1...")
		c.Next()
		fmt.Println("我在方法后1...")
	}
}

func middle2() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("我在方法前2...")
		c.Next()
		fmt.Println("我在方法后2...")
	}
}


func main() {
	r := gin.Default()
	// 路由分组 中间件
	v1 := r.Group("v1").Use(middle(), middle2())
	v1.GET("group", func(c *gin.Context) {
		fmt.Println("我在方法内部...")
		c.JSON(200, gin.H{
			"success": true,
		})
	})
	r.Run(":8088")
}



/** 请求结果
	我在方法前1...
  我在方法前2...
  我在方法内部...
  我在方法后2...
  我在方法后1...
**/

GORM

创建链接

package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
  dsn := "username:pwd@tcp(ip:port)/dbName?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}
  // 关闭db	
	defer db.Close()
}

自动迁移

package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type HelloWorld struct {
	/** 自动创建基础结构
	type Model struct {
		ID        uint `gorm:"primary_key"`
		CreatedAt time.Time
		UpdatedAt time.Time
		DeletedAt *time.Time `sql:"index"`
	}
	*/
	gorm.Model
	Name string
	Gender bool
	Age int
}

func main() {
	dsn := "username:pwd@tcp(ip:port)/dbName?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}

	// 自动迁移,查看是否有表,没有会自动创建
	db.AutoMigrate(&HelloWorld{})

	defer db.Close()
}

CRUD

package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type HelloWorld struct {
	/** 自动创建基础结构
	type Model struct {
		ID        uint `gorm:"primary_key"`
		CreatedAt time.Time
		UpdatedAt time.Time
		DeletedAt *time.Time `sql:"index"`
	}
	*/
	gorm.Model
	Name   string
	Gender bool
	Age    int
}

func main() {
	dsn := "username:pwd@tcp(ip:port)/dbName?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}

	// 自动迁移,查看是否有表,没有会自动创建
	db.AutoMigrate(&HelloWorld{})

	// 创建数据
	//db.Create(&HelloWorld{
	//	Name:   "ysml",
	//	Gender: true,
	//	Age:    25,
	//})

	// 查
	// hello 用于接收
	//var hello HelloWorld
	//db.First(&hello, "name = ?", "aowu")
	//db.Find(&hello, "age >= ?", "20")
	// 条件写前面最常用
	// Or 可以写进SQL语句也可以在后面显示编写
	//db.Where("age > ?", "20").Or("name = ?", "qiuqian").Find(&hello)
	//fmt.Println(hello)

	// 改
	//db.Where("name = ?", "qiuqian").First(&HelloWorld{}).Update("name", "qiuqian123")
	//fmt.Println(hello)
	// map批量修改
	//db.Where("id in (?)", []int{2, 3}).Find(&[]HelloWorld{}).Updates(map[string]interface{}{
	//	"Name":   "updated",
	//	"Gender": true,
	//	"Age":    22,
	//})

	// 删
	// 软删除
	db.Where("id in (?)", []int{1, 2}).Delete(&HelloWorld{})
	// 物理删除
	//db.Where("id in (?)", []int{1, 2}).Unscoped().Delete(&HelloWorld{})
	defer db.Close()
}

创建

func CreatUsers() int {
   // 批量创建
   res := global.DBEngine.Create(&[]model.User{
      {Name: "yz1", Age: 17},
      {Name: "yz2", Age: 18},
      {Name: "yz3", Age: 19},
      {Name: "yzz", Age: 20},
   })
   if res.Error != nil {
      fmt.Println("创建失败")
      return utils.ERROR
   } else {
      fmt.Println("创建成功")
      return utils.SUCCESS
   }
}

查询

模型

携带了 gorm 规定的标签或实现了接口的一种结构体,书写良好的模型可以增加gorm的操作效率

嵌入结构体,会自动创建 id created_at updated_at deleted_at 列名

package model

import "gorm.io/gorm"

type User struct {
  // 嵌入结构体,会自动创建 id created_at updated_at deleted_at 列名
	gorm.Model
	Username string `json:"username"`
	Password string `json:"password"`
}

也可以自定义

以 Model 匿名结构放进 User 结构体后,整个字段都会被继承

package model

import (
	"time"
)

type Model struct {
	UUID uint `gorm:"primaryKey"`
	// 重命名列名
	Time time.Time `gorm:"column:my_time"`
}

type User struct {
	Model Model `gorm:"embedded;embeddedPrefix:prefix_"` // 前缀
	Username string `gorm:"not null;default:qiuqian;comment:密码"`
	Password string
}

image-20211107170030101

更多看文档

JWT

package main

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"time"
)

type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

func main() {
	// 下面是签发
	mySignedStringKey := []byte("qiuqianaowu")
	// 结构体的方式
	c := MyClaims{
		Username: "qiuqian",
		StandardClaims: jwt.StandardClaims{
			// 生效时间
			NotBefore: time.Now().Unix() - 60,
			// 失效时间 2h
			ExpiresAt: time.Now().Unix() + 60*60*2,
			// 签发者
			Issuer:    "qiuqian",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	// 对 token 加密
	sign, err := token.SignedString(mySignedStringKey)
	if err != nil {
		fmt.Println("%s", err)
	}
	fmt.Println(sign)

	// 下面是解密
	t, e := jwt.ParseWithClaims(sign, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return mySignedStringKey, nil
	})
	if e != nil {
		fmt.Println("%s", e)
	}
	// 在这里取出
	fmt.Println(t.Claims.(*MyClaims).Username)
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!