golang入门笔记——Gin

文章目录

    • Gin简介:
    • 简单的gin实例
    • 参数获取
    • Form表单的处理
    • 绑定Form表单
    • 表单验证
    • boostrap集成
    • 中间件的使用
    • BasicAuth中间件
    • 日志
    • cookie和session
    • 简单实例:用户授权访问
    • Cookie的使用
    • 使用Session
    • Gin实现restful风格的CRUD
    • Gin路由组
    • 输出渲染
    • 文件上传
    • 请求重定向
    • 自定义HTTP配置

Gin简介:

Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的 API框架, 由于使用了httprouter,速度提高了近40倍。具有封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点.

Gin特征:
1.速度快:基于基数树的路由,内存占用少。没有反射。可预测的API性能。
中间件支持:传入的HTTP请求可以由中间件链和最终操作处理。
2。Crash—free
Gin可以捕获HTTP请求期间发生的panic并恢复它。这样,你的服务器将始终可用。
3.JSON验证
Gin可以解析和验证请求的JSON-例如,检查所需值的存在
4.路由分组
更好地组织您的路线。需要授权与不需要授权,不同的API版本…此外,组可以无限嵌套,而不会奖低性能。
错误管理
5.Gin提供了一种方便的方法来收集HTTP请求期间发生的所有错误。最终,中间件可以将它们写入日志文件、数据库并通过网络发送它们。
6.内置渲染
Gin为JSON、XML和HTML渲染提供了一个易于使用的API
7.可扩展
创建一个新的中间件非常简单,只需查看示例代码即可

gin的安装

go get -u github.com/gin-gonic/gin

简单的gin实例

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func Hello(c *gin.Context) {
	c.String(200, "hello %s", "world")
	c.JSON(http.StatusOK, gin.H{ //以json格式输出
		"name": "tom",
		"age":  "20",
	}) //200代表请求成功,http.StatusOK代表请求成功,gin.H是map的一个快捷方式
}

func main() {
	e := gin.Default() //创建一个默认的路由引擎
	e.GET("/hello", Hello)
	e.Run()
}


简单的用户登录实现:

package main

//gin实现简单的登录程序
import "github.com/gin-gonic/gin"

func Login(c *gin.Context) {
	c.HTML(200, "login.html", nil)
}

func DoLogin(c *gin.Context) {
	username := c.PostForm("username")
	password := c.PostForm("password")
	c.HTML(200, "welcome.html", gin.H{
		"Username": username,
		"Password": password,
	})
}

func main() {
	e := gin.Default()
	e.LoadHTMLGlob("views/*") //获取当前路径下的views文件夹下的所以html文件
	e.GET("/login", Login)
	e.POST("/login", DoLogin) //post请求交给DoLogin处理
	e.Run()
}

welcome.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
head>
<body>
    欢迎,{{.Username}}
    {{.Password}}
body>
html>

login.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>Logintitle>
head>
<body>

<form action="/login" method="post">
    用户名称:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="Login">
form>

body>
html>

参数获取

//获取param参数
//router.Get("/:id",Param1)
func Param1(ctx *gin.Context){
	id:=ctx.Param("id")
}

//router.Get("/*id",Param2)
func Param2(ctx *gin.Context){
	id:=ctx.Param("id")
}
//这种情况下,连id前面的/也会获取到,而且id也可以为空



//获取query参数
//router.Get("/",Query1)
func Query1(ctx *gin.Context){
	id:=ctx.Query("id")
	id2:=ctx.DefaultQuery("id","0")//获取不到id时默认为0
	ids:=ctx.QueryArray("ids")//获取ids的多个参数
	idm:=ctx.QueryMap("idm")//获取map类型的参数idm
}


//获取post参数
//router.Post("/",Post1)
func Post1(ctx *gin.context){
	id:=ctx.PostForm("id")
	id2:=ctx.DefaultPostForm("id","10")//id获取不到的话默认为10
	ids:=ctx.PostFormArray("ids")
	idm:=ctx.PostFormMap("idm")
}

//获取提交的单文件
func GetFile(ctx *gin.context){
	file,_:=ctx.FormFile("file")
	fmt.Println(file.Filename)
	dst:=path+file.Filename
	ctx.SaveUploadedFile(file,dst)//文件保存 
}

//获取提交的多文件
func GetMulFile(ctx *gin.context){
	file,_:=ctx.MultipartForm()
	files:=form.File["file"] 

	for _,file:=range files{
	dst:=path+file.Filename
	ctx.SavaUploadFile(file,dst)
	}
}


Form表单的处理

package main

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

func TestGet(c *gin.Context) {
	s := c.Query("username")
	pwd := c.DefaultQuery("password", "123") //如果没有输入密码给它一个默认值“123”
	c.String(200, "username:%s password:%s", s, pwd)
	//http://localhost:8888/testget?username=zyj&password=1234
}

func TestGetParam(c *gin.Context) {
	s := c.Param("username")
	s2 := c.Param("age")
	c.String(200, "Username:%s", s)
	c.String(200, "Age:%s", s2)
	//http://localhost:8888/hello/zyj/22
}

func GoSearch(c *gin.Context) {
	c.HTML(200, "query.html", nil)
}

func Search(c *gin.Context) {
	page := c.DefaultQuery("page", "0")
	key := c.PostForm("key")
	c.String(200, "page:%s,key:%s", page, key)
}

func main() {
	e := gin.Default()
	e.LoadHTMLGlob("views/*")
	e.GET("/testget", TestGet)
	e.GET("/hello/:username/:age", TestGetParam)
	e.GET("/goSearch", GoSearch)
	e.POST("/search", Search)

	e.Run(":8888")
}

//post的运用

query.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
head>
<body>

<form action="/search?page=1" method="post">
    请输入查询关键字:<input type="text" name="key"><br>

    <input type="submit" value="查询">
form>
body>
html>

绑定Form表单

golang入门笔记——Gin_第1张图片

1.ShouldBind()  根据标记进行数据绑定
2.ShouldBindWith() 接受两个参数,第二个参数来指名绑定参数类型,例:表单类型binding.Form
3.ShouldBindQuery()对query参数的绑定
4.ShouldBindUri()对param参数进行绑定
package main

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

type User struct {
	Username string   `form:"username"`
	Password string   `form:"password"`
	Hobby    []string `form:"hobby"`
	Gender   string   `form:"gender"`
	City     string   `form:"city"`
}

type User2 struct {
	Username string `uri:"username"`
	Password string `uri:"password""`
}

func Register(c *gin.Context) {
	var user User
	err := c.ShouldBind(&user) //form绑定数据
	if err != nil {
		fmt.Println("绑定失败")
	}
	c.String(200, "User:%s", user)
	//http://localhost:8080/testGetBind?username=zyj&password=123
	//这种连接也会将其进行绑定
}

func GoRegister(c *gin.Context) {
	c.HTML(200, "login.html", nil)
}

func TestGetBind(c *gin.Context) {
	var user User2
	err := c.ShouldBind(&user) //form绑定数据
	if err != nil {
		fmt.Println("绑定失败")
	}
	c.String(200, "User:%s", user)
	//http://localhost:8080/testGetBind?username=zyj&password=123
	//通过uri绑定
}

func main() {
	e := gin.Default()
	e.LoadHTMLGlob("views/*")
	e.GET("/testFrom", GoRegister)
	e.POST("/register", Register)
	e.GET("/testGetBind", TestGetBind)
	e.Run()
}

login.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>Logintitle>
head>
<body>

<form action="/register" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    爱好:
    <input type="checkbox" name="hobby" value="swimming">游泳
    <input type="checkbox" name="hobby" value="basketball">篮球
    <br>
    性别:<input type="radio" name="gender" id="1" value="m"><input type="radio" name="gender" id="2" value="f"><br>
    城市:<select name="city">
    <option value="beijing">北京option>
    <option value="shanghai">上海option>
    <br>
select>
    <input type="submit" value="注册">
form>

body>
html>

表单验证

golang入门笔记——Gin_第2张图片
golang入门笔记——Gin_第3张图片
golang入门笔记——Gin_第4张图片
golang入门笔记——Gin_第5张图片
golang入门笔记——Gin_第6张图片
golang入门笔记——Gin_第7张图片
golang入门笔记——Gin_第8张图片

使用go-playground/validator.v8进行验证

type Article struct{
	Id int `form:"id"`
	Title string `form:"title" binding:"required"`
}

自定义验证器:

安装包:

go get github.com/go-playgroud/validator
func Len6Valid validator.Func=func(f1 validator.FieldLevel) bool{
	data:=f1.Field().Interface().(string)
	if len(data)>6{
	return false
	}else{
	return true
	}
}

func main(){
	v,ok:=binding.Validator.Engine().(*validator.Validate)

	if ok{
	v.RegisterValidation("len_valid",Len6Valid) //第一个参数是绑定的tag标记,第二个是绑定的函数
	validation.SetDefaultMessage(map[string]string{}) //设置验证不通过返回的信息
	}
}

boostrap集成

boostrap下载网站
下载完成后将其中的js和css放入到assets中

简单的集成实例

package main

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

func GoStatic(e *gin.Context) {
	e.HTML(200, "test_static.html", nil)

}

func main() {
	e := gin.Default()
	e.Static("/assets", "./assets") //第一个是访问的路径,第二个路径是css、js存放的路径
	e.LoadHTMLGlob("views/*")

	e.GET("/gostatic", GoStatic)
	e.Run()
}

test_static.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>

    <link rel="stylesheet" href="/gin/asset/css/bootstrap.min.css">
    <script src="/gin/asset/js/bootstrap.min.js">script>

head>
<body>

    <div class="container">
        <div class="btn-group" role="group" aria-label="Basic example">
            <button type="button" class="btn btn-primary">Leftbutton>
            <button type="button" class="btn btn-primary">Middlebutton>
            <button type="button" class="btn btn-primary">Rightbutton>
        div>
    div>

body>
html>

中间件的使用

golang入门笔记——Gin_第9张图片
golang入门笔记——Gin_第10张图片

golang入门笔记——Gin_第11张图片

gin的内置中间件

golang入门笔记——Gin_第12张图片

package main

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

func Testmw(c *gin.Context) {
	c.String(200, "hello %s", "world!")
}

func MyMiddeleware1(c *gin.Context){
	fmt.Println("我的第一个中间件")
}

func MyMiddeleware2(c *gin.Context){
	fmt.Println("我的第二个中间件")
}

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

	e.Use(MyMiddeleware1, MyMiddeleware2)

	e.GET("/testmw", Testmw)

	e.Run()
}

BasicAuth中间件

// 局部使用中间价
chap05.GET("/basic",gin.BasicAuth(gin.Accounts{
        "zs":"123456",
        "ls":"123",
        "ww":"1234",
    }),BasicAuthTest)


// 私有数据
var map_data map[string]interface{} = map[string]interface{}{
    "zs":gin.H{"age":18,"addr":"zs-xx"},
    "ls":gin.H{"age":19,"addr":"ls-xx"},
    "ww":gin.H{"age":20,"addr":"ww-xx"},
}


// 获取私有数据。如果没有权限则获取不到
func BasicAuthTest(ctx *gin.Context)  {

    user_name := ctx.Query("user_name")

    data ,ok := map_data[user_name]

    if ok{
        ctx.JSON(http.StatusOK,gin.H{"user_name":user_name,"data":data})
    }else {
        ctx.JSON(http.StatusOK,gin.H{"user_name":user_name,"data":"没有权限"})
    }
}

一文读懂HTTP Basic身份认证:链接

日志

golang入门笔记——Gin_第13张图片

使用日志文件:

// 1.创建日志文件
f, _ := os.Create("gin.log")

// 2.重新赋值DefaultWriter
gin.DefaultWriter = io.MultiWriter(f)

// 同时在控制台打印信息
gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

logrus中间件

func LoggerFile(c *gin.Context) {
	file_dir := "./gin.log"
	src, err := os.OpenFile(file_dir, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend)

	if err != nil {
		panic(err)
	}

	logger := logrus.New()

	logger.Out = src

	logger.SetLevel(logrus.DebugLevel)

	logger.SetFormatter(&logrus.TextFormatter{TimestampFormat: "2006-01-02 15:04:05"})

	startTime := time.Now()

	c.Next()

	long := time.Since(startTime)
	reqMothod := c.Request.Method
	reqUri := c.Request.RequestURI
	statusCode := c.Writer.Status()
	clientIp := c.ClientIP()

	logger.Infof("|%3s|%13v|%15s|%s|%s|",
		statusCode,
		long,
		clientIp,
		reqMothod,
		reqUri,
	)
}

cookie和session

golang入门笔记——Gin_第14张图片
golang入门笔记——Gin_第15张图片

Session的使用:

func SessionTest(ctx *gin.Context)  {


    // 初始化session对象
    session := sessions.Default(ctx)

    // 设置session
    session.Set("name","hallen")
    session.Set("age",18)
    session.Set("addr","xxx")

    // 获取session
    name := session.Get("name")
    fmt.Println("================++++++++++")
    fmt.Println(name)

    // 删除指定key的session
    session.Delete("name")

    name2 := session.Get("name")
    fmt.Println("================++++++++++")
    fmt.Println(name2)

    fmt.Println(session.Get("age"))
    // 删除所有的session
    session.Clear()
    fmt.Println(session.Get("age"))
    fmt.Println(session.Get("addr"))

    // 保存session
    session.Save()




}

基于redis的存储引擎

安装:

go get github.com/gin-contrib/sessions/redis

使用:

store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("hallen"))

router.Use(sessions.Sessions("session_test",store))



参数说明:
    第1个参数 - redis最大的空闲连接数
    第2个参数 - 数通信协议tcp或者udp
    第3个参数 - redis地址, 格式,host:port
    第4个参数 - redis密码,如果没有密码则为空字符串
    第5个参数 - session加密密钥

简单实例:用户授权访问

package main

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

//模拟一些私人数据
var secrets = gin.H{
	"foo":    gin.H{"email": "[email protected]", "phone": "123433"},
	"austin": gin.H{"email": "[email protected]", "phone": "666"},
	"lena":   gin.H{"email": "[email protected]", "phone": "523443"},
}

func Handler(c *gin.Context) {
	//获取用户,它是由BasicAuth中间件设置
	user := c.MustGet(gin.AuthUserKey).(string) //获得当前用户,AuthUserKey就是user快捷键
	fmt.Println(user)
	if secret, ok := secrets[user]; ok {
		c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
	} else {
		c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET:("})
	}
}

func main() {

	e := gin.Default()

	//这些用户数据也可以从数据库查询
	//路由使用gin.BasicAuth()中间件
	//gin.Accounts是map[string]string的一种快捷方式
	e1 := e.Group("/admin", gin.BasicAuth(
		gin.Accounts{
			"foo":    "bar",
			"austin": "1234",
			"lena":   "hello2",
			"manu":   "4321",
		})) //授权登入/admin的用户由以上那些
	//http://localhost:8080/admin/secrets
	e1.GET("/secrets", Handler)

	e.Run()
}

Cookie的使用

package main

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

func Handler(c *gin.Context) {
	s, err := c.Cookie("username") //取username的cookie值
	if err != nil {
		s = "zyj"
		c.SetCookie("username", s, 60*60, "/", "localhost", false, true)
		//参数分别为name,value,时间,路径,域,https是否可以访问,是否是只有http请求能够访问
	}
	c.String(200, "测试cookie")
}

func main() {
	e := gin.Default()
	e.GET("test_cookie", Handler)
	e.Run()
}

使用Session

session库的下载

go get github.com/gin-contrib/sessions

session库的使用

package main

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
)

func Handle(c *gin.Context) {
	session := sessions.Default(c)
	//获得session值 Get
	if session.Get("hello") != "world" {
		//设置
		session.Set("hello", "world")
		//保存
		session.Save()
	}
	c.JSON(200, gin.H{"hello": session.Get("hello")})
}

func main() {
	r := gin.Default()
	store := cookie.NewStore([]byte("secret"))   //创建一个存储cookie的存储器
	r.Use(sessions.Sessions("mysession", store)) //注入中间件,mysession是session名称

	r.GET("/hello", Handle)
	r.Run(":8000")
}

Gin实现restful风格的CRUD

REST与技术无关,代表的是一种软件架构风格。简单来说,REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作:
1.GET用来获取资源
2.POST用来新建资源
3.PUT用来更新资源
4.DELETE用来删除资源。
只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互。

package main

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

type User struct {
	UId  int    `json:"uid"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

var users = make([]User, 3)

func init() {
	u1 := User{1, "tom", 20}
	u2 := User{2, "kite", 30}
	u3 := User{3, "rose", 40}
	users = append(users, u1, u2, u3)
	fmt.Println(users)
}

func find(uid int) (*User, int) {
	for i, u := range users {
		if u.UId == uid {
			return &u, i
		}
	}
	return nil, -1
}

func AddUser(c *gin.Context) {
	u4 := User{4, "Joe", 50}
	users = append(users, u4)
	c.JSON(200, users)
}

func DelUser(c *gin.Context) {
	uid := c.Param("uid")
	id, _ := strconv.Atoi(uid)
	_, i := find(id)
	users = append(users[:i], users[i+1:]...)
	c.JSON(200, users)
}

func UpdateUser(c *gin.Context) {
	uid := c.Param("uid")
	id, _ := strconv.Atoi(uid)
	u, _ := find(id)
	u.Name = "修改的Name"
	c.JSON(200, u)
}

func FindUser(c *gin.Context) {
	uid := c.Param("uid")
	id, _ := strconv.Atoi(uid)
	u, _ := find(id)
	c.JSON(200, u)
}

func main() {
	e := gin.Default()
	e.GET("/user/:uid", FindUser)   //GET获取请求
	e.PUT("/user/:uid", UpdateUser) //PUT修改请求
	e.DELETE("/user/:uid", DelUser) //DELETE删除请求
	e.POST("/user/", AddUser)       //POST添加请求
	e.Run()
}

Gin路由组

package main

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

func F1(c *gin.Context)  {}
func F2(c *gin.Context)  {}
func F3(c *gin.Context)  {}
func F4(c *gin.Context)  {}
func F5(c *gin.Context)  {}
func F6(c *gin.Context)  {}

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

	//http://localhost:8080/blog/list
	v1 := router.Group("/blog")
	{
		v1.POST("/list", F1)
		v1.POST("/post", F2)
		v1.POST("/add", F3)
	}

	//http://localhost:8080/video/list
	v2 := router.Group("/video"){
		v2.POST("/list",F4)
		v2.POST("/post",F5)
		v2.POST("/add",F6)
	}
	router.Run("8080")
}

输出渲染

LoadHTMLGlob:通过通配符来进行模板文件夹指定,例:router.LoadHTMLGlob(“template/"),二级目录时:router.LoadHTMLGlob("template/**/”)

LoadHTMLFiles:指定html文件,例:router.LoadHTMLFiles(“index.html”,“news.html”)

HTML:接受三个参数,第一个是满足条件的状态码,第二个是html文件的名称,第三个是给模板传递的参数

Static:第一个参数指定访问路径的url,第二个参数是静态资源的路径

golang入门笔记——Gin_第16张图片

package main

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

func TestJson(e *gin.Context) {
	e.JSON(200, gin.H{
		"name": "zyj",
		"site": "www.baidu.com",
	})
}

func TestXMl(e *gin.Context) {
	e.XML(200, gin.H{
		"name": "lcc",
		"site": "www.sougou.com",
	})
}

func TestString(e *gin.Context) {
	e.String(200, "zyj")
}

func TestHtml(e *gin.Context) {
	e.HTML(200, "login.html", nil)
}

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

	e.GET("/test_json", TestJson)
	e.GET("/test_xml", TestXMl)
	e.LoadHTMLGlob("views/*")
	e.GET("/test_html", TestHtml)
	e.GET("/test_string", TestString)
	e.Run()
}

其他的一些模板玩法参考博客

文件上传

package main

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

func Upload(c *gin.Context) {
	//单文件
	file, _ := c.FormFile("file")
	log.Println(file.Filename)

	//上传文件到项目根目录,使用原文件名
	c.SaveUploadedFile(file, file.Filename)

	c.String(http.StatusOK, fmt.Sprintf("'%s' upload!", file.Filename))
}

func GoUpload(c *gin.Context) {
	c.HTML(200, "put_file.html", nil)
}

func main() {
	e := gin.Default()
	e.MaxMultipartMemory = 8 << 20 //设置上传文件的最大内存8MB
	e.LoadHTMLGlob("views/*")
	e.GET("/upload", GoUpload)
	e.POST("/upload", Upload)
	e.Run()
}

put_file.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
head>
<body>
    <form action="/upload" method="post" enctype="multipart/form-data">
        请选择上传文件:<input type="file" name="file"><br>
        <input type="submit" value="上传">
    form>

body>
html>

请求重定向

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func Hello(c *gin.Context) {
	c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
}

func main() {
	e := gin.Default() //创建一个默认的路由引擎
	e.GET("/hello", Hello)
	e.GET("/a", func(c *gin.Context) {
		c.Request.URL.Path = "/hello" //设置转交地址的URL
		e.HandleContext(c)            //转交
	})
	e.Run()
}

自定义HTTP配置

s:=&http.Server{
	Addr:":8080",
	Handler:router,
	ReadTimeout:10*time.Second,
	WithTimeout:5*time.Second,
}

s.ListenAndServe()

你可能感兴趣的:(go语言,golang)