当前位置: 首页 > news >正文

gin 快速入门手册

文章目录

  • 安装
  • URL和路由分组
    • 2. 带参数的url
    • 3. 获取路由分组的参数
  • 获取参数
    • 1. 获取get参数
    • 2. 获取post参数
    • 3. get、post混合
  • JSON 、 ProtoBuf渲染
    • 1. 输出json和protobuf
    • 2. PureJSON
  • 表单验证
    • 1. 表单的基本验证
  • 中间件和next函数
    • 1. 无中间件启动
    • 2. 使用中间件
    • 3. 自定义组件
  • 设置静态文件路径和HTML文件
    • 1. 设置静态文件路径
    • 2. index.html内容
    • 3. templates/posts/index.tmpl
    • 4. templates/users/index.tmpl
  • 优雅重启或停止
  • gorm
    • 1. 什么是orm
    • 2. 常用orm
    • 3. orm的优缺点
    • 4. 如何正确看待orm和sql之间的关系

官方手册

安装

go get -u github.com/gin-gonic/gin 
  1. 代码
package mainimport "github.com/gin-gonic/gin"
# func main() {r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.Run() // listen and serve on 0.0.0.0:8080
}
  1. 使用get、post、put等http方法
func main() {// 使⽤默认中间件创建⼀个gin路由器// logger and recovery (crash-free) 中间件router := gin.Default()router.GET("/someGet", getting)router.POST("/somePost", posting)router.PUT("/somePut", putting)router.DELETE("/someDelete", deleting)router.PATCH("/somePatch", patching)router.HEAD("/someHead", head)router.OPTIONS("/someOptions", options)// 默认启动的是 8080端⼝,也可以⾃⼰定义启动端⼝router.Run()// router.Run(":3000") for a hard coded port
}

URL和路由分组

  1. 路由分组
func main() {router := gin.Default()// Simple group: v1v1 := router.Group("/v1"){v1.POST("/login", loginEndpoint)v1.POST("/submit", submitEndpoint)v1.POST("/read", readEndpoint)}// Simple group: v2v2 := router.Group("/v2"){v2.POST("/login", loginEndpoint)v2.POST("/submit", submitEndpoint)v2.POST("/read", readEndpoint)}router.Run(":8082")
}

2. 带参数的url

package mainimport ("github.com/gin-gonic/gin""net/http")func main() {r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.GET("/user/:name/:action/", func(c *gin.Context) {name := c.Param("name")action := c.Param("action")c.String(http.StatusOK, "%s is %s", name, action)})r.GET("/user/:name/*action", func(c *gin.Context) {name := c.Param("name")action := c.Param("action")c.String(http.StatusOK, "%s is %s", name, action)})r.Run(":8082")
}

3. 获取路由分组的参数

package mainimport "github.com/gin-gonic/gin"type Person struct {ID string `uri:"id" binding:"required,uuid"`Name string `uri:"name" binding:"required"`}func main() {route := gin.Default()route.GET("/:name/:id", func(c *gin.Context) {var person Personif err := c.ShouldBindUri(&person); err != nil {c.JSON(400, gin.H{"msg": err})return}c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})})route.Run(":8088")
}

获取参数

1. 获取get参数

func main() {router := gin.Default()// 匹配的url格式: /welcome?firstname=Jane&lastname=Doerouter.GET("/welcome", func(c *gin.Context) {firstname := c.DefaultQuery("firstname", "Guest")lastname := c.Query("lastname") // 是 c.Request.URL.Query().Get("lastnamec.String(http.StatusOK, "Hello %s %s", firstname, lastname)})router.Run(":8080")
}

2. 获取post参数

func main() {router := gin.Default()router.POST("/form_post", func(c *gin.Context) {message := c.PostForm("message")nick := c.DefaultPostForm("nick", "anonymous") // 此⽅法可以设置默认值c.JSON(200, gin.H{"status": "posted","message": message,"nick": nick,})})router.Run(":8080")
}

3. get、post混合

POST /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=manu&message=this_is_greatfunc main() {router := gin.Default()router.POST("/post", func(c *gin.Context) {id := c.Query("id")page := c.DefaultQuery("page", "0")name := c.PostForm("name")message := c.PostForm("message")fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, mes})router.Run(":8080")
}

JSON 、 ProtoBuf渲染

1. 输出json和protobuf

新建user.proto文件

syntax = "proto3";
option go_package = ".;proto";
message Teacher {string name = 1;repeated string course = 2;
}
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"start/gin_t/proto"
)
func main() {r := gin.Default()// gin.H is a shortcut for map[string]interface{}r.GET("/someJSON", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})})r.GET("/moreJSON", func(c *gin.Context) {// You also can use a structvar msg struct {Name string `json:"user"`Message stringNumber int}msg.Name = "Lena"msg.Message = "hey"msg.Number = 123// Note that msg.Name becomes "user" in the JSON// Will output : {"user": "Lena", "Message": "hey", "Number": 123}c.JSON(http.StatusOK, msg)})r.GET("/someProtoBuf", func(c *gin.Context) {courses := []string{"python", "django", "go"}// The specific definition of protobuf is written in the testdata/protoexName: "bobby",Course: courses,}// Note that data becomes binary data in the response// Will output protoexample.Test protobuf serialized datac.ProtoBuf(http.StatusOK, data)})// Listen and serve on 0.0.0.0:8080r.Run(":8083")
}

2. PureJSON

通常情况下,JSON会将特殊的HTML字符替换为对应的unicode字符,比如 < 替换为 \u003c ,如果想原样输出html,则使用PureJSON

func main() {r := gin.Default()// Serves unicode entitiesr.GET("/json", func(c *gin.Context) {c.JSON(200, gin.H{"html": "<b>Hello, world!</b>",})})// Serves literal charactersr.GET("/purejson", func(c *gin.Context) {c.PureJSON(200, gin.H{"html": "<b>Hello, world!</b>",})})// listen and serve on 0.0.0.0:8080r.Run(":8080")
}

表单验证

1. 表单的基本验证

若要将请求主体绑定到结构体中,请使用模型绑定,目前支持JSON、XML、YAML和标准表单值(foo=bar&boo=baz)的绑定。 Gin使用 go-playground/validator 验证参数

需要在绑定的字段上设置tag,比如,绑定格式为json,需要这样设置 json:“fieldname” 。
此外,Gin还提供了两套绑定方法:

  • Must bind
    Methods - Bind , BindJSON , BindXML , BindQuery , BindYAML Behavior - 这些方法底层使用 MustBindWith ,如果存在绑定错误,请求将被以下指令中止 c. AbortWithError(400,err).SetType(ErrorTypeBind) ,响应状态代码会被设置为400,请求头 Content-Type 被设置为 text/plain; charset=utf-8 。注意,如果你试图在此之后设置响应代码,将会发出一个警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422 ,如果你希望更好地控制行为,请使用 ShouldBind 相关的方法
  • Should bind
    Methods - ShouldBind , ShouldBindJSON , ShouldBindXML , ShouldBindQuery , ShouldBindYAML
    Behavior - 这些方法底层使用 ShouldBindWith ,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。

当我们使用绑定方法时,Gin会根据Content-Type推断出使用哪种绑定器,如果你确定你绑定的是什么,你可以使用 MustBindWith 或者 BindingWith 。你还可以给字段指定特定规则的修饰符,如果一个字段用 binding:“required” 修饰,并且在绑定时该字段的值为空,那么将返回一个错误。

// 绑定为json
type Login struct {User string `form:"user" json:"user" xml:"user" binding:"required"`Password string `form:"password" json:"password" xml:"password" binding:"requ`
}type SignUpParam struct {Age uint8 `json:"age" binding:"gte=1,lte=130"`Name string `json:"name" binding:"required"`Email string `json:"email" binding:"required,email"`Password string `json:"password" binding:"required"`RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
func main() {router := gin.Default()// Example for binding JSON ({"user": "manu", "password": "123"})router.POST("/loginJSON", func(c *gin.Context) {var json Loginif err := c.ShouldBindJSON(&json); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}if json.User != "manu" || json.Password != "123" {c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})return}c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})})// Example for binding a HTML form (user=manu&password=123)router.POST("/loginForm", func(c *gin.Context) {var form Login// This will infer what binder to use depending on the content-type headeif err := c.ShouldBind(&form); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}if form.User != "manu" || form.Password != "123" {c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})return}c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})})r.POST("/signup", func(c *gin.Context) {var u SignUpParamif err := c.ShouldBind(&u); err != nil {c.JSON(http.StatusOK, gin.H{"msg": err.Error(),})return}// 保存⼊库等业务逻辑代码...c.JSON(http.StatusOK, "success")})// Listen and serve on 0.0.0.0:8080router.Run(":8080")
}

中间件和next函数

1. 无中间件启动

#使⽤
r := gin.New()
#替代
// 默认启动⽅式,包含 Logger、Recovery 中间件
r := gin.Default()

2. 使用中间件

func main() {
// 创建⼀个不包含中间件的路由器r := gin.New()// 全局中间件// 使⽤ Logger 中间件r.Use(gin.Logger())// 使⽤ Recovery 中间件r.Use(gin.Recovery())// 路由添加中间件,可以添加任意多个r.GET("/benchmark", MyBenchLogger(), benchEndpoint)// 路由组中添加中间件// authorized := r.Group("/", AuthRequired())// exactly the same as:authorized := r.Group("/")// per group middleware! in this case we use the custom created// AuthRequired() middleware just in the "authorized" group.authorized.Use(AuthRequired()){authorized.POST("/login", loginEndpoint)authorized.POST("/submit", submitEndpoint)authorized.POST("/read", readEndpoint)// nested grouptesting := authorized.Group("testing")testing.GET("/analytics", analyticsEndpoint)}// Listen and serve on 0.0.0.0:8080r.Run(":8080")
}

3. 自定义组件

func Logger() gin.HandlerFunc {return func(c *gin.Context) {t := time.Now()// Set example variablec.Set("example", "12345")// before requestc.Next()// after requestlatency := time.Since(t)log.Print(latency)// access the status we are sendingstatus := c.Writer.Status()log.Println(status)}}func main() {r := gin.New()r.Use(Logger())r.GET("/test", func(c *gin.Context) {example := c.MustGet("example").(string)// it would print: "12345"log.Println(example)})// Listen and serve on 0.0.0.0:8080r.Run(":8080")
}

设置静态文件路径和HTML文件

1. 设置静态文件路径

package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {// 创建⼀个默认的路由引擎r := gin.Default()// 配置模板r.LoadHTMLGlob("templates/**/*")//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html// 配置静态⽂件夹路径 第⼀个参数是api,第⼆个是⽂件夹路径r.StaticFS("/static", http.Dir("./static"))// GET:请求⽅式;/hello:请求的路径// 当客户端以GET⽅法请求/hello路径时,会执⾏后⾯的匿名函数r.GET("/posts/index", func(c *gin.Context) {// c.JSON:返回JSON格式的数据c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{"title": "posts/index",})})r.GET("gets/login", func(c *gin.Context) {c.HTML(http.StatusOK, "posts/login.tmpl", gin.H{"title": "gets/login",})})// 启动HTTP服务,默认在0.0.0.0:8080启动服务r.Run()
}

2. index.html内容

<html><h1>{{ .title }}</h1>
</html>

3. templates/posts/index.tmpl

{{ define "posts/index.tmpl" }}<html><h1>{{ .title }}</h1><p>Using posts/index.tmpl</p></html>
{{ end }}

4. templates/users/index.tmpl

{{ define "users/index.tmpl" }}
<html><h1>{{ .title }}
</h1><p>Using users/index.tmpl</p>
</html>
{{ end }}

优雅重启或停止

package main
import ("context""log""net/http""os""os/signal""syscall""time""github.com/gin-gonic/gin"
)
func main() {router := gin.Default()router.GET("/", func(c *gin.Context) {time.Sleep(5 * time.Second)c.String(http.StatusOK, "Welcome Gin Server")})
srv := &http.Server{Addr: ":8080",Handler: router,
}
go func() {// service connectionsif err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosedlog.Fatalf("listen: %s\n", err)}
}()// Wait for interrupt signal to gracefully shutdown the server with// a timeout of 5 seconds.quit := make(chan os.Signal)// kill (no param) default send syscanll.SIGTERM// kill -2 is syscall.SIGINT// kill -9 is syscall. SIGKILL but can"t be catch, so don't need add itsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<-quitlog.Println("Shutdown Server ...")ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()if err := srv.Shutdown(ctx); err != nil {log.Fatal("Server Shutdown:", err)
select {case <-ctx.Done():log.Println("timeout of 5 seconds.")}log.Println("Server exiting")
}

gorm

1. 什么是orm

ORM全称是:Object Relational Mapping(对象关系映射),其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。举例来说就是,我定义一个对象,那就对应着一张表,这个对象的实例,就对应着表中的一条记录。

对于数据来说,最重要最常用的是表:表中有列, orm就是将一张表映射成一个类,表中的列映射成类中的一个类。java 、python,但是针对go语言而言,struct,就是列如何映射,是因为列可以映射成struct中的类型,int->int,但是有另一个问题? 就是数据库中的列具备很好的描述性,但是struct有tag。执行sql, 需要我们有足够的sql语句基础、需要我们懂得不同的数据的sql

2. 常用orm

个人而言,不用太去纠结应该选择哪一个orm框架,但是实际上你用熟悉了一个,其他的orm迁移成本很低,我们选个一个star数量最高的一定不会有错,这些差异也不会很大
sql语言远比orm重要的多
https://github.com/go-gorm/gorm
https://github.com/facebook/ent
https://github.com/jmoiron/sqlx
https://gitea.com/xorm/xorm/src/branch/master/README_CN.md
https://github.com/didi/gendry/blob/master/translation/zhcn/README.md

3. orm的优缺点

优点:

  1. 提高了开发效率。
  2. 屏蔽sql细节。可以自动对实体Entity对象与数据库中的Table进行字段与属性的映射;不用直接SQL编码
  3. 屏蔽各种数据库之间的差异
    缺点:
  4. orm会牺牲程序的执行效率和会固定思维模式
  5. 太过依赖orm会导致sql理解不够
  6. 对于固定的orm依赖过重,导致切换到其他的orm代价高

4. 如何正确看待orm和sql之间的关系

  1. sql为主,orm为辅
  2. orm主要目的是为了增加代码可维护性和开发效率

一定要学好:

  1. group by
  2. 子查询
  3. having子句
http://www.lryc.cn/news/222274.html

相关文章:

  • Window下安装 Mongodb,并实现单点事务
  • 【通信原理】第三章 随机过程——例题
  • 线性【SVM】数学原理和算法实现
  • R语言中的函数26:polyroot多项式求根函数
  • 2023年辽宁省数学建模竞赛A题铁路车站的安全标线
  • 半导体工厂将应用哪些制造创新技术?
  • [unity]深色模式/浅色模式
  • 在react中组件间过渡动画如何实现?
  • 解析找不到msvcr100.dll文件的解决方法,4个方法修复msvcr100.dll
  • 达梦主备部署
  • 后期混音效果全套插件Waves 14 Complete mac中文版新增功能
  • HTML5笔记
  • 前端架构师需要解决那些问题
  • 使用python快速搭建接口自动化测试脚本实战总结
  • android studio 字节码查看工具jclasslib bytecode viewer
  • Ubuntu上搭建FTP服务
  • unity打AB包,AssetBundle预制体与图集(三)
  • 在Javascript中为什么 0.1+0.2 不等于0.3 ? 源代码详细解析
  • MATLAB|热力日历图
  • 《golang设计模式》第三部分·行为型模式-05-仲裁者/中介模式(Mediator)
  • 7天入门python系列之准备工作
  • Go语言~反射
  • 详解交叉验证中【KFold】【Stratified-KFold】【StratifiedShuffleSplit】的区别
  • 数学建模比赛中常用的建模提示词(数模prompt)
  • Spark 新特性+核心回顾
  • STM32 TIM定时器,配置,详解(1)
  • Helix Toolkit:为.NET开发者带来的3D视觉盛宴
  • PHP分类信息网站源码系统 电脑+手机+微信端三合一 带完整前后端部署教程
  • 2023年辽宁省数学建模竞赛B题数据驱动的水下导航适配区分类预测
  • 完蛋!百融云被大阳线包围了!