goweb开发实战笔记(一)

目录

🧡Gin简介

🧡Gin特性

🧡Gin环境搭建

🧡HTTP请求和参数解析

创建Engine

Handle方法处理

Engine分类处理

表单实体绑定

ShouldBindQuery

ShouldBind

JSON

多数据格式返回请求结果

[]byte切片

string

JSON

HTML

路由分组

🧡中间件的使用


💟这里是CS大白话专场,让枯燥的学习变得有趣!

💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话!

💟好记性不如烂键盘,自己总结不如收藏别人!

🧡Gin简介

💌Gin 是一个 golang 的微框架,封装比较优雅,API 友好,源码注释比较明确,已经发布了1.0版本。具有快速灵活,容错方便等特点。其实对于 golang 而言,web 框架的依赖要远比 Python,Java 之类的要小。自身的 net/http 足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

🍠Gin 框架是开源的,可以在 github 上下载其源码库,查看相应的说明:Gin源码库地址

🍠Gin 框架有一个官方网站,有对 Gin 相关的介绍和学习资料:Gin官网

🧡Gin特性

🍠速度:Gin 之所以被很多企业和团队所采用,第一个原因是因为其速度快,性能表现出众。

🍠中间件:和 iris 类似,gin 在处理请求时,支持中间件操作,方便编码处理。

🍠路由:在 gin 中可以非常简单地实现路由,路由组解析功能。

🍠内置渲染:Gin 支持 JSON、XML 和 HTML 等多种数据格式的渲染,并提供方便的操作 API。

🧡Gin环境搭建

💌gin 框架需要 go 语言版本在1.6及以上。可以通过 go version 查看 go 语言版本是否符合要求。

 

通过go get命令安装gin框架:

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

💌安装完毕后,可以在当前系统的 $GOPATH 目录下的 src/github.com 目录中找到 gin-gonic 目录,该目录下存放的就是 gin 框架的源码。

🧡HTTP请求和参数解析

创建Engine

💌在 gin 框架中,Engine 被定义成为一个结构体,其中包含了路由组、中间件、页面渲染接口、框架配置设置等相关内容。两种创建方式如下所示:

engine1 = gin.Default()
engine2 = gin.New()

💌gin.Default() 内也调用 gin.New() 创建Engine实例,但会默认使用Logger和Recovery中间件。

🍠Logger 是负责进行打印并输出日志的中间件,方便开发者进行程序调试。

🍠Recovery 中间件的作用是如果程序执行过程中遇到 panic 中断了服务,Recovery 会恢复程序执行,并返回服务器500内部错误。

💌通常情况下,使用默认的 gin.Default() 创建 Engine 实例

Handle方法处理

💌在 Engine 中可以使用 Handle 方法处理 HTTP 请求。Handle 方法包含三个参数,具体如下:

func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc)

🍠httpMethod:表示要处理的 HTTP 的请求类型,是 GET、POST、DELETE、OPTIONS、HEAD、PUT、TRACE、CONNECT 请求类型中的一种。

🍠relativePath:表示要解析的接口,由开发者进行定义。

🍠handlers:是处理对应的请求的代码的定义。

package main

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

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

	//GET
	//http://localhost:8080/hello?name=Jodie
	engine.Handle("GET", "/hello", func(context *gin.Context) {
		path := context.FullPath()
		fmt.Println(path)
		//获取name值,若没有则返回stranger
		name := context.DefaultQuery("name", "stranger")
		fmt.Println(name)
		//页面显示内容
		context.Writer.Write([]byte("Hello, " + name))
	})

	//POST
	//http://localhost:8080/login
	engine.Handle("POST", "/login", func(context *gin.Context) {
		fmt.Println(context.FullPath())
		username := context.PostForm("username")
		password := context.PostForm("password")
		fmt.Println(username)
		fmt.Println(password)
		context.Writer.Write([]byte("Hello, " + username))
	})

	engine.Run()
}

Engine分类处理

💌除了 Engine 中包含的通用的处理方法以外,Engine 还可以按类型直接解析。Engine 中包含有get方法、post方法、delet方法等与 HTTP 请求类型对应的方法。

package main

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

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

	//GET
	engine.GET("/hello", func(context *gin.Context) {
		path := context.FullPath()
		fmt.Println(path)
		name := context.Query("name")
		fmt.Println(name)
		context.Writer.Write([]byte("Hello, " + name))
	})

	//POST
	engine.POST("/login", func(context *gin.Context) {
		fmt.Println(context.FullPath())
		username, existName := context.GetPostForm("username")
		if existName {
			fmt.Println(username)
		}
		password, existWord := context.GetPostForm("password")
		if existWord {
			fmt.Println(password)
		}
		context.Writer.Write([]byte("Hello, " + username))
	})

	//DELETE
	engine.DELETE("/user/:id", func(context *gin.Context) {
		userID := context.Param("id")
		fmt.Println(userID)
		context.Writer.Write([]byte("DELETE " + userID))
	})

	engine.Run()
}

表单实体绑定

💌使用 PostForm 这种单个获取属性和字段的方式,代码量较多,需要一个一个属性进行获取。而表单数据的提交,往往对应着完整的数据结构体定义,其中对应着表单的输入项。gin 框架提供了数据结构体和表单提交数据绑定的功能,提高表单数据获取的效率。如下所示:

以用户注册功能为例,假设用户注册提交表单数据包含三项:username、phone 和 password。 

type UserRegister struct {
	Username string `form:"username" binding:"required"`
	Phone    string `form:"phone"    binding:"required"`
	Password string `form:"password" binding:"required"`
}

创建了 UserRegister 结构体用于接收表单数据,通过 tag 标签的方式设置每个字段对应的 form 表单中的属性名,通过 binding 设置属性是否必须。

ShouldBindQuery

package main

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

func main() {
	engine := gin.Default()
	//GET
	//http://localhost:8080/hello?username=Jodie&password=1234
	engine.GET("/hello", func(context *gin.Context) {
		fmt.Println(context.FullPath())
		var user User
		err := context.ShouldBindQuery(&user)
		if err != nil {
			log.Fatal(err.Error())
			return
		}
		fmt.Println(user.Username)
		fmt.Println(user.Password)
		context.Writer.Write([]byte("Hello, " + user.Username))
	})

	engine.Run()
}

type User struct {
	Username string `form:"username" binding:"required"`
	Password string `form:"password" binding:"required"`
}

ShouldBind

package main

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

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

	//POST
	engine.POST("/regist", func(context *gin.Context) {
		fmt.Println(context.FullPath())
		var register UserRegister
		err := context.ShouldBind(&register)
		if err != nil {
			log.Fatal(err.Error())
			return
		}
		fmt.Println(register.Username)
		fmt.Println(register.Phone)
		context.Writer.Write([]byte("Hello, " + register.Username))
	})

	engine.Run()
}

type UserRegister struct {
	Username string `form:"username" binding:"required"`
	Phone    string `form:"phone"    binding:"required"`
	Password string `form:"password" binding:"required"`
}

JSON

package main

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

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

	//POST
	engine.POST("/addUser", func(context *gin.Context) {
		fmt.Println(context.FullPath())
		var person Person
		context.BindJSON(&person)
		err := context.BindJSON(&person)
		if err != nil {
			log.Fatal(err.Error())
			return
		}
		fmt.Println(person.Username)
		context.Writer.Write([]byte("Add " + person.Username))
	})

	engine.Run()
}

type Person struct {
	Username string `form:"username" binding:"required"`
	Phone    string `form:"phone"    binding:"required"`
	Password string `form:"password" binding:"required"`
}

💌JSON格式提交请求:

{
    "username":"Nike"
    "phone":"13265496230"
    "password":"1234"
}

多数据格式返回请求结果

[]byte切片

💌通过 context.Writer.Write([]byte(返回结果)) 实现,前文内容已经使用,Writer 是 gin 框架中封装的一个 ResponseWriter 接口类型

string

💌ResponseWriter 还封装了 WriteString 方法返回数据,通过 context.Writer.WriteString(返回结果) 实现。

package main

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

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

	//byte[]
	engine.GET("/hellobyte", func(context *gin.Context) {
		path := "请求路径:" + context.FullPath()
		fmt.Println(path)
		context.Writer.Write([]byte(path))
	})

	//string
	engine.GET("/hellostring", func(context *gin.Context) {
		path := "请求路径:" + context.FullPath()
		fmt.Println(path)
		context.Writer.WriteString(path)
	})
	engine.Run()
}

JSON

💌JSON 格式规范使用的更为普遍,context 包含的 JSON 方法可以将结构体类型的数据转换成 JSON 格式的结构化数据,然后返回给客户端。 

package main

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

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

	engine.GET("/hellojson", func(context *gin.Context) {
		path := "请求路径:" + context.FullPath()
		fmt.Println(path)
		//200:正常 404:NOT FOUND 500:内部错误
		//map类型
		context.JSON(200, map[string]interface{}{
			"code":    1,
			"message": "OK",
			"data":    path,
		})
	})
	
	//struct类型
	engine.GET("/hellostruct", func(context *gin.Context) {
		path := "请求路径:" + context.FullPath()
		fmt.Println(path)
		resp := Response{Code: 1, Message: "OK", Data: path}
		context.JSON(200, &resp)
	})

	engine.Run()
}

type Response struct {
	Code    int
	Message string
	Data    interface{}
}

HTML

package main

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

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

	//设置html目录
	engine.LoadHTMLGlob("./html/*")
	//静态文件目录
	engine.Static("/img", "./img")
	engine.GET("/hellohtml", func(context *gin.Context) {
		path := "请求路径:" + context.FullPath()
		fmt.Println(path)
		context.HTML(http.StatusOK, "index.html", gin.H{
			"path":  path,
			"title": "Hello!",
		})
	})

	engine.Run()
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{.title}}</title>
</head>
<body>
{{.path}}
<div><img src="../img/Miku.jpeg"></div>
</body>
</html>

路由分组

💌路由组是 router.Group 中的一个方法,用于对请求进行分组,相同模块的功能接口,可以使用路由组进行分类处理。

package main

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

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

	routerGroup := engine.Group("/user")
	routerGroup.POST("/register", registerHandle)
	routerGroup.DELETE("/:id", deleteHandle) 

	engine.Run()
}

func registerHandle(context *gin.Context) {
	path := "用户注册:" + context.FullPath()
	fmt.Println(path)
	context.Writer.WriteString(path)
}

func deleteHandle(context *gin.Context) {
	path := "用户删除:" + context.FullPath()
	userID := context.Param("id")
	fmt.Println(path + " " + userID)
	context.Writer.WriteString(path + " " + userID)
}

🧡中间件的使用

💌在实际的业务开发和处理中,会有更复杂的业务和需求场景。一个完整的系统可能要包含鉴权认证、权限管理、安全检查、日志记录等多维度的系统支持,对于系统中的所有业务都适用,可以将一些通用业务抽离出来单独进行开发,然后以插件化的形式进行对接。这种方式既保证了系统功能的完整,同时又有效地将具体业务和系统功能进行解耦,还可以达到灵活配置的目的。 

💌自定义中间件有两条标准:

🍠类型为 func 函数

🍠返回值类型为 HandlerFunc

package main

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

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

	//engine.Use(RequestInfos()) //所有接口均可使用中间件
	engine.GET("/middle", func(context *gin.Context) {
		context.JSON(200, map[string]interface{}{
			"code": 1,
			"msg":  context.FullPath(),
		})
	})

	//只有指定接口可以使用
	engine.GET("/only", RequestInfos(), func(context *gin.Context) {
		fmt.Println("中断操作")
		context.JSON(200, map[string]interface{}{
			"code": 2,
			"msg":  context.FullPath(),
		})
	})

	engine.Run()
}

// 打印请求信息的中间件
func RequestInfos() gin.HandlerFunc {
	return func(context *gin.Context) {
		path := context.FullPath()
		method := context.Request.Method
		fmt.Println("请求路径:", path)
		fmt.Println("请求method:", method)
		context.Next() //中断操作,先执行主函数内容
		fmt.Println("状态码:", context.Writer.Status())
	}
}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值