-
package main import ( "github.com/gin-gonic/gin" "gopkg.in/go-playground/validator.v9" "net/http" "time" ) type Booking struct { CheckIn time.Time `form:"check_in" validate:"required,bookableDate" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" validate:"required,gtfield=CheckIn" time_format:"2006-01-02"` } func main(){ r := gin.Default() validate := validator.New() validate.RegisterValidation("bookableDate", bookableDate) r.GET("/bookable", func(c *gin.Context) { var book Booking if err := c.ShouldBind(&book); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) c.Abort() return } if err := validate.Struct(book); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) c.Abort() return } c.JSON(http.StatusOK, gin.H{ "message": "OK", "booking": book, }) }) r.Run() } func bookableDate(fl validator.FieldLevel) bool { if date, ok := fl.Field().Interface().(time.Time); ok { today := time.Now() if date.Unix() > today.Unix() { return true } } return false }
查看全部 -
package main import ( "github.com/gin-gonic/gin" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" "github.com/go-playground/universal-translator" "gopkg.in/go-playground/validator.v9" en2 "gopkg.in/go-playground/validator.v9/translations/en" zh2 "gopkg.in/go-playground/validator.v9/translations/zh" "net/http" "time" ) type Booking struct { CheckIn time.Time `form:"check_in" validate:"required,bookableDate" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" validate:"required,gtfield=CheckIn" time_format:"2006-01-02"` } func main(){ r := gin.Default() zhTranslate := zh.New() enTranslate := en.New() Uni := ut.New(zhTranslate, enTranslate) validate := validator.New() _ = validate.RegisterValidation("bookableDate", bookableDate) r.GET("/bookable", func(c *gin.Context) { locale := c.DefaultQuery("locale", "zh") trans, _ := Uni.GetTranslator(locale) switch locale { case "zh": _ = validate.RegisterTranslation("bookableDate", trans, registerBookableDateTranslation, bookableDateTranslation) _ = zh2.RegisterDefaultTranslations(validate, trans) break case "en": _ = en2.RegisterDefaultTranslations(validate, trans) break default: _ = validate.RegisterTranslation("bookableDate", trans, registerBookableDateTranslation, bookableDateTranslation) _ = zh2.RegisterDefaultTranslations(validate, trans) } var book Booking if err := c.ShouldBind(&book); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) c.Abort() return } if err := validate.Struct(book); err != nil { errs := err.(validator.ValidationErrors) var sliceErrs []string for _, v := range errs { sliceErrs = append(sliceErrs, v.Translate(trans)) } c.JSON(http.StatusInternalServerError, gin.H{ "error": sliceErrs, }) c.Abort() return } c.JSON(http.StatusOK, gin.H{ "message": "OK", "booking": book, }) }) _ = r.Run() } func bookableDate(fl validator.FieldLevel) bool { if date, ok := fl.Field().Interface().(time.Time); ok { today := time.Now() if date.Unix() > today.Unix() { return true } } return false } func registerBookableDateTranslation(ut ut.Translator) error { return ut.Add("bookableDate", "{0} 日期必须大于当天日期!", true) } func bookableDateTranslation(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("bookableDate", fe.Field()) return t }
查看全部 -
老师棒棒哒查看全部
-
Gin脚手架文件结构说明:
conf/ #配置文件目录-下一层#环境文件夹
/dev #开发环境
base.toml* #基本配置存储
mysql_map.toml* #mysql配置存储
redis_map.toml* #redis配置存储
controller/ #控制器类-按照文件名区分不同的请求,同一请求汇聚到同一文件
dao/ #数据访问的对象层-一般存储的是RM
dto/ #数据传输对象层-输入的参数转化为实际的对象
middleware/ #中间件层-日志的打印和请求的拦截,以及session和多语言的处理也可以放在这里
public/ #公共层-放置一些公共的函数
router/ #路由层-路由的配置请求的配置
tmpl/ #模版文件存储位置
查看全部 -
传统关停服务器的方式,开始有一个gin实例,gin.run通过阻塞监听端口,请求过来之后会请求回调函数提供服务,结束之后就直接终止了
优雅关停的方式,可以使用一个server.ListenAndServer构建一个server来代替gin.Run,它是不阻塞的
另外使用os.Signal来阻塞进程,监听关闭信号,如果获取到信号就将超时的上下文传递到server的shutdwon方法里才正式退出
从监听到信号到真正的结束之前,会关闭这个时间段内的连接请求,并且要在超时时间内把已经接收到请求执行完毕
查看全部 -
学完了,内容比较简单,脚手架那章没什么实际内容查看全部
-
curl -X GET http://127.0.0.1:8080/api/hello
查看全部 -
#出事换环境
https://beego.gocn.vip/beego/zh/developing/bee/env.html
#go语言安装主根目录
export GOROOT=/usr/local/go
#替换你的目录#GOPATH 是自己的go项目路径,自定义设置export GOPATH=/Users/ding/go_workspace #替换你的目录#GOBIN 当我们使用go install命令编译后并且安装的二进制程序目录export GOBIN=$GOPATH/bin# 启用 Go Modules 功能export GO111MODULE=on# 配置 GOPROXY 环境变量。你可以换成你喜欢的 proxyexport GOPROXY=https://goproxy.cn,direct# 加入环境变量中export PATH=$PATH:$GOROOT/bin:$GOBIN
# 创建文件夹
mkdir -p $GOPAH/src/github.com/rupid/learn-gin
# 进入learn-gin文件夹
cd $_
# 初始化mod
go mod init
# 拉去gin的模块
go get -v github.com/gin-gonic/gin@v1.7
查看全部 -
待了解的前置知识:
- go基本语法
- go写成基本知识
开发工具
- goland
查看全部 -
老师是在liunx下教学的,windows的命令行更改如下
mkdir -p $GOPATH/src/github.com/e421083458/gin_test_project 换成 mkdir -p $env:GOPATH/src/github.com/e421083458/gin_test_project
export GO111MODULE=on 换成 go env -w GO111MODULE=on
这个on不能是大写,而且只有on,off,auto
如果设置错了值,可以看这篇文章
windows错误设置GO111MODULE报错解决
设置好GO111MODULE之后,可以设置代理,下载速度会快一点go env -w GOPROXY=https://goproxy.cn,direct
查看全部 -
自动申请证书
autotls.Run(r, "域名")
流程:
1、生成本地密钥
2、发送密钥到证书颁发机构 => 获取私钥
3、私钥验证,验证后保存,下次请求用私钥加密 => 自动下载证书
查看全部 -
1、加载模板文件
r.LoadHTMLGlob("template/*")
2、处理模板数据
c.HTML(200, "index.html", gin.H{ "title": "test_gin_template" })
查看全部 -
package mainimport ( "context" "github.com/gin-gonic/gin" "log" "net/http" "os" "os/signal" "syscall" "time")func main() { r := gin.Default() r.GET("/other_shutdown", func(c *gin.Context) { time.Sleep(10*time.Second) c.String(200, "test other shutdown") }) srv := &http.Server{ Addr: ":8085", Handler: r, } go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen:%s\n", err) } }() quit := make(chan os.Signal) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("shutdown server...") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("server shutdown:", err) } log.Println("server exiting") }
1、时间库使用
time.Sleep(10*time.Second) // 表示等待10秒
2、使用http.Server 构建server
srv := &http.Server{ // 地址 Addr: ":8085", Handler: r, }
3、goroutine创建协程并使用
go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { } }()
4、信号 os.Signal - 请求拦截
quit := make(chan os.Signal) // 捕获 ctrl+c 和 kill -15 终止两类, kill -9捕获不到 signal.Notify(quit, syscall.S IGINT, syscall.SIGTERM) // 阻塞channel <-quit
5、设置超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
6、defer
7、执行关闭服务器
srv.Shutdown(ctx)
查看全部 -
package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func IPAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { ipList := []string{ "127.0.0.2", } flag := false clientIP := c.ClientIP() for _, ip := range ipList { if ip == clientIP { flag = true break } } if !flag { c.String(http.StatusUnauthorized, "%s not in ip list", clientIP) c.Abort() } } } func main() { r := gin.Default() r.Use(IPAuthMiddleware()) r.GET("whitelist_middleware_gin", func(c *gin.Context) { c.String(200, c.ClientIP()) }) err := r.Run() if err != nil { fmt.Println(err) } }
1、ip数组初始化:
ipList := []string{ "127.0.0.2", }
2、获取客户端ip
c.ClientIP()
3、自定义中间件:
3.1 定义中间件方法 func IPAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { } } 3.2 使用中间件 r.Use(IPAuthMiddleware())
4、中间件校验不通过直接退出
c.Abort() // 不终止退出的话,会继续调用接口,输出接口内容,与中间件检验拦截目的不符
查看全部 -
package main import ( "bytes" "fmt" "github.com/gin-gonic/gin" "io/ioutil" "net/http" ) func main() { r := gin.Default() r.POST("/test", func(c *gin.Context) { bodyBytes, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.String(http.StatusBadRequest, err.Error()) c.Abort() } c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) name := c.PostForm("name") c.String(http.StatusOK, "%s, %s", name, string(bodyBytes)) }) err := r.Run() if err != nil { fmt.Println(err) } }
curl -X POST "http://127.0.0.1:8080/test" -d "name=zqunor"
虽然能实现,但是感觉回传不是个好方案。
查看全部
举报