Goland使用及gin框架下载引入
第一次使用Goland时需要配置GOROOT、GOPATH、Go Modules
配置完成后进入面板,右键选择Go Modules文件,或者在go工作区通过命令go mod init [name]
创建go mod项目。
创建完的项目一般都有go.mod文件和go.sum,前者是go包的依赖管理文件,后者是体现依赖管理的关系。
go get -u github.com/gin-gonic/gin
go get
命令更新主模块的 go.mod 文件中的模块依赖关系,模块的go.mod文件记录了它需要哪些版本的依赖项。这些依赖项的源代码存储在本地缓存中。go get更新go.mod文件中列出的要求。它还确保这些需求是自洽的,并根据需要添加新需求,以便您在命令行中命名的包导入的每个包都由您的需求中的某个模块提供。
作为更新和添加需求的副作用,go get还将包含命名包(及其依赖项)的模块下载到本地模块缓存。
go mod download
不添加新需求或更新现有需求。它只下载您请求的特定模块版本,也就是说模块存在于本地缓存,不需要go get再次远程下载,在go.mod引入后go mod download从缓存中加载。
gin框架下载后会在GOPATH的pkg/mod下面
创建一个包,编写web引擎:
package main
import "github.com/gin-gonic/gin"
func main() {
//创建一个服务器引擎
engine := gin.Default()
//配置web容器地址
engine.GET("/", func(context *gin.Context) {
context.JSON(200, gin.H{"msg": "Hello World"})
})
//配置服务器端口
engine.Run(":8080")
}
Gin路由
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello word")
})
r.POST("/xxxpost",HandlerFunc)
//监听端口默认为8080
r.Run(":8000")
}
在上面函数中,创建了一个gin引擎,利用引擎设置路由规则,不同地址对应不同的方法,这个方法只能是HandlerFunc
类型的方法即参数为gin.context
。
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes
type HandlerFunc func(*Context)
因此方法直接使用匿名方法即可。最后通过引擎的Run方法绑定端口即可。
Restful风格
gin引擎支持Restfu风格,gin框架封装了http库,提供了 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS 这些http请求方式。
router := gin.Default()
router.GET("/get", func(c *gin.Context) { c.JSON(200, gin.H{"message": "get方法"}) })
router.POST("/post", func(c *gin.Context) { c.JSON(200, gin.H{"message": "post方法"}) })
router.PUT("/put", func(c *gin.Context) { c.JSON(200, gin.H{"message": "put方法"}) })
router.DELETE("/delete", func(c *gin.Context) { c.JSON(200, gin.H{"message": "delete"}) })
router.PATCH("/patch", func(c *gin.Context) { c.JSON(200, gin.H{"message": "patch"}) })
router.HEAD("/head", func(c *gin.Context) { c.JSON(200, gin.H{"message": "head"}) })
router.OPTIONS("/options", func(c *gin.Context) { c.JSON(200, gin.H{"message": "options"}) })
router.Run(":80")//指定端口 localhost:9999
engine.PATCH("/url", func(context *gin.Context) {
})
重定向
context.Redirect(code,rrl)
方法实现重定向。
engine.GET("/redirect", func(context *gin.Context) {
context.Redirect(301, "https://baidu.com")
})
错误页面
出现404页面的错误是没有找到对应的路由,一般情况服务器都有默认的404页面,但是有时需要定制的页面。就需要使用engine.NoRoute(func(context *gin.Context)
方法。
/**
gin默认又模板引擎
*/
//加载静态页面
engine.LoadHTMLGlob("./templates/*")
//404页面没有路由
engine.NoRoute(func(context *gin.Context) {
context.HTML(404, "404.html", nil)
})
路由组
处理方法除了使用匿名函数之外还可以直接定义方法,定义方法一般在路由组中,如下
v1 := r.Group("/v1")
{
v1.GET("/login", login)
v1.GET("/register", register)
}
v2 := r.Group("/v2")
{
v2.GET("/index", page)
v2.GET("/main", index)
}
r.Run()
func login(c *gin.Context) {
c.String(200, "login method")
}
func register(c *gin.Context) {
c.String(200, "register method")
}
func page(c *gin.Context) {
c.String(200, "page main")
}
func index(c *gin.Context) {
c.String(200, "index main")
}
每个r.Group("/v2")
管理若干路由地址。
返回数据或页面
import (
"github.com/gin-gonic/gin"
)
func main() {
//创建一个服务器引擎
engine := gin.Default()
//加载静态页面
engine.LoadHTMLGlob("./templates/*")
//配置web容器地址
engine.GET("/", func(context *gin.Context) {
//返回json数据
context.JSON(200, gin.H{"msg": "Hello World"})
})
engine.GET("/index", func(context *gin.Context) {
//返回html页面
context.HTML(200, "index.html", gin.H{
"msg": "gin后台转递的数据",
})
})
//配置服务器端口
engine.Run(":8080")
}
gin.Context
参数的JSON方法用于返回json数据,HTML方法返回页面,且是模板引擎的页面,需要使用引擎加载html文件engine.LoadHTMLGlob("./templates/*")
html文件中通过{{}}
获取传递的数据,.数据
接收。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello World</h1>
{{.msg}}
</body>
</html>
参数处理
在web容器中,第一步有web容器处理统一资源定位符,分发到不同的路由地址,到达地址的数据均有两个参数接收与处理。在Gin中gin.Context
参数,封装了request
(请求参数)和response
(响应参数),因此基于参数的处理都需要使用gin.Context参数。(Java是没有封装的)参数处理又分为请求行参数、请求头和请求体参数。
url?name=xxx&password=xxx
//url?name=xxx&password=xxx
engine.GET("/add", func(context *gin.Context) {
name := context.Query("name")
pass := context.Query("pass")
context.JSON(200, gin.H{
"user": name,
"pass": pass,
})
})
通过context.Query()
查询参数的值。也可以使用DefaultQuery()
,区别在于Query()没对应,返回空字符串,DefaultQuery()返回默认值,其有两个参数,第一个为绑定的查询变量,第二个为默认值。
r := gin.Default()
r.GET("/user", func(c *gin.Context) {
//指定默认值
//http://localhost:8080/user 才会打印出来默认的值
name := c.DefaultQuery("name", "枯藤")
c.String(http.StatusOK, fmt.Sprintf("hello %s", name))
})
r.Run()
url/value1/value2
//url/value1/value2
engine.GET("/delete/:name/:pass", func(context *gin.Context) {
name := context.Param("name")
pass := context.Param("pass")
context.JSON(200, gin.H{
"name": name,
"pass": pass,
})
})
通过context.Param()
获取获取参数的值。这是Restful
风格的传参。url地址上的标识符需要前面加上:
即/delete/:name/:pass
。
接收json数据
//接收json数据
engine.POST("/json", func(context *gin.Context) {
data, err := context.GetRawData()
if err != nil {
panic(err)
}
context.JSON(200, data)
})
context.GetRawData()
用于接收请求体数据,(这个很好记)
在主流的API测试工具中JSON数据均被定义为raw
数据。
context.GetRawData()
返回的是字节数组,需要字节数组转化为Go的内置对象如结构体。
在Go序列化章节中说到,序列化结构体的返回值为字节数组,转为json字符串需要使用string()
方法Go语言流处理,工厂模式,命令参数,序列化,单元测试。因此将其转化为字符串类型。
context.JSON(200, string(data))
但是这样转也没有意义,这个字符串字Go无法运用,在实际中,一般通过反序列化直接将字节数组转化为Go语言的内置对象。
type Person struct{
Name string
Age int
Phone int8
Address string
}
//接收json数据
engine.POST("/json", func(context *gin.Context) {
data, _ := context.GetRawData()
//context.JSON(200, string(data))
var per Person
_ = json.Unmarshal(data, &per)
context.JSON(200, per)
})
定义一个结构体用于接收数据,但是又出现了新的问题,在反序列化时字符串名称要和结构体成员名称一致,于是有需要序列化的tag规则。修改后的结构体如下:
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Phone string `json:"phone"`
Address string `json:"address"`
}
改造后只要传入的数据和json:[name]
的name对应即可。
表单数据
表单数据通过context.PostForm
方法接收,其参数对应html的input
标签的name
属性即可。
//表单数据
engine.POST("/form", func(context *gin.Context) {
user := context.PostForm("user")
pass := context.PostForm("pass")
context.JSON(200, gin.H{
"username": user,
"password": pass,
})
})
表单传输为post请求,http常见的传输格式为四种:
application/json
application/x-www-form-urlencoded
application/xml
multipart/form-data
表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数
文件上传
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<meta lang="en" charset="utf-8">
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
upload file<input type="file" name="file">
<input type="submit" value="submit">
</form>
</body>
</html>
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("./templates/*")
r.GET("/", func(ctx *gin.Context) {
ctx.HTML(200, "index.html", nil)
})
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.String(500, "上传图片出错")
}
c.SaveUploadedFile(file, file.Filename)
c.String(http.StatusOK, file.Filename)
})
r.Run()
}
文件会上传到根目录下,如下:
中间件(拦截器)
中间件是在路由请求前的预处理,相当远Java的拦截器。中间件也是封装在gin.context
中,定义在单个路由就对某个接口生效,定义在全局就对整体生效。
//中间件(拦截器)
func preHandler() gin.HandlerFunc {
return func(context *gin.Context) {
//设置值
context.Set("isLog",true)
//放行
context.Next()
//阻止
context.Abort()
}
}
加载静态资源
//加载静态页面
engine.LoadHTMLGlob("./templates/*")
//加载静态资源
engine.Static("/static", "./static")
前后端交互结构体绑定数据
json
import (
"encoding/json"
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.Default()
engine.GET("/", func(ctx *gin.Context) {
ctx.String(200, "Hello World")
})
engine.GET("/index", func(ctx *gin.Context) {
data, _ := ctx.GetRawData()
var log Login
_ = json.Unmarshal(data, &log)
ctx.JSON(200, log)
})
engine.Run("127.0.0.1:8080")
}
type Login struct {
User string `json:"username"`
Pass string `json:"password"`
}
除了上述通过ctx.GetRawData()
接收字节数组外,也可以直接gin封装的结构体函数将其绑定到结构体数据上。ctx.ShouldBindJSON()
方法将传递的json数据直接绑定到结构体上,而不需要二次转化,要求是字段对应,或者序列化的tag规则即可。如下:
func main() {
engine := gin.Default()
engine.GET("/index", func(ctx *gin.Context) {
var log Login
_ = ctx.ShouldBindJSON(&log)
ctx.JSON(200, log)
})
engine.Run("127.0.0.1:8080")
}
type Login struct {
User string `json:"username"`
Pass string `json:"password"`
}
form-data
注意这里的form-data
不是x-www-form-urlencoded
。form-data的数据通过序列化tag规则的form
标签,如下:
func main() {
engine := gin.Default()
engine.GET("/per", func(ctx *gin.Context) {
var per Person
ctx.Bind(&per)
ctx.JSON(200, per)
})
engine.Run("127.0.0.1:8080")
}
type Person struct {
Name string `form:"username"`
Age int `form:"age"`
}
x-form-urlencoded
x-form-urlencoded
的转化使用的是ctx.ShouldBind()
方法。如下:
type LoginForm struct {
User string `form:"user" binding:"required"`
Password string `form:"password" binding:"required"`
}
func main() {
router := gin.Default()
router.POST("/login", func(c *gin.Context) {
// 你可以使用显式绑定声明绑定 multipart form:
// c.ShouldBindWith(&form, binding.Form)
// 或者简单地使用 ShouldBind 方法自动绑定:
var form LoginForm
// 在这种情况下,将自动选择合适的绑定
_ = c.ShouldBind(&form)
c.JSON(200, form)
})
router.Run("127.0.0.1:8080")
}
url数据绑定结构体
url绑定结构体只支持url?user=xxx&pass=xxx
的风格
func main() {
engine := gin.Default()
engine.GET("/per/:username/:age", func(ctx *gin.Context) {
var per Person
ctx.ShouldBindUri(&per)
ctx.JSON(200, per)
})
engine.Run("127.0.0.1:8080")
}
type Person struct {
Name string `uri:"username"`
Age int `uri:"age"`
}
结构体序列化tag标签改为uri
,方法使用ctx.ShouldBindUri()
。
将数据直接绑定结构体,会更加快捷,但是需要注意,使用序列化的tag规则定义结构体,另外还有一个
binding:"required“
标签,如果存在,则绑定后赋值不能为空否则回报错。
多个标签也可以一起用form:"username" json:"user" uri:"user" xml:"user" binding:"required"
。
前后端交互响应数据
上一节说明了前端传递的数据可以直接转化为结构体数据,也可以通过序列化转化为其他数据类型。在Gin框架中,封装了这些过程,可以直接通过相关方法将数据转化为对应的数据类型。
//JSON
engine.GET("/per", func(ctx *gin.Context) {
var per Person
ctx.ShouldBindUri(&per)
ctx.JSON(200, per)
})
ctx.JSON()
方法可以直接将Go的一些内置对象直接转化为json字符串。最常见的就是字典,结构体等。
// XML
r.GET("/someXML", func(c *gin.Context) {
c.XML(200, gin.H{"message": "abc"})
})
ctx.XML()
方法可以直接将数据转为XML文件的格式。
Gin模板引擎
如果用gin返回html页面,就会默认使用模板引擎,gin使用LoadHTMLGlob()
方法加载模板文件。
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("tem/*")
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{"title": "我是测试", "ce": "123456"})
})
r.Run()
}
r.LoadHTMLGlob("tem/*")
方法加载文件下所有模板文件,通过gin.Context.HTML()
方法渲染模板引擎,方法又三个参数,第一个状态码,第二个是模板文件,第三个是数据。
在模板引擎中通过.
来获取数据。一般情况下通过gin.H
返回的是一个map类型,通过.key
获取。
gin中html文件也能模块化,通过{{ define ...}}
定义模块{{ template ...}}
引入模块。
<!--header.html-->
{{define "header"}}
<h1>this is header</h1>
{{end}}
<!--footer.html-->
{{ define "footer"}}
<h1>this is footer</h1>
{{end}}
<!--index.html->
<!DOCTYPE html>
<html>
<head>
<title>hello</title>
<meta>
</head>
<body>
{{define "index.html"}}
<!--header-->
{{ template "header" .}}
<!--main-->
<h1>this is main</h1>
<!--footer-->
{{ template "footer" .}}
{{ end }}
</body>
</html>
{{define "header"}}
...
{{ end }}
通过上面的关键字定义html模块,header为一个路径,分别是根路径递归,最后一个是模块名,如果header.html在head目录下,那么其路径对应的是head/header。另外还受engine.LoadHTMLGlob("templates/*")
方法的影响,一般该方法加载到资源的更目录或者html文件的父目录即可。在结合define
关键字定义路径。
在其他模板引入时注意不要忘了.
即{{ template "footer" .}}
,主模块也需要定义一下,将被引入模块包裹起来即{{define "index.html"}}
,这里直接定义为文件的名称即可。
package main
import "github.com/gin-gonic/gin"
func main() {
engine := gin.Default()
engine.LoadHTMLGlob("templates/*")
engine.GET("/", func(ctx *gin.Context) {
ctx.HTML(200, "index.html", nil)
})
engine.Run("127.0.0.1:8080")
}
日志
import (
"io"
"os"
"github.com/gin-gonic/gin"
)
func main() {
// 禁用控制台颜色,将日志写入文件时不需要控制台颜色。
gin.DisableConsoleColor()
// 记录到文件。
f, _ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f)
// 如果需要同时将日志写入文件和控制台,请使用以下代码。
// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
router.Run("127.0.0.1:8080")
}
gin.DisableConsoleColor()
禁用控制台颜色控制台没有日志
os.Create("gin.log")
创建日志文件
gin.DefaultWriter = io.MultiWriter(f)
写入日志文件
开启日志后日志会记录到日志文件中去。
gin在路由时会打印日志,这个日志的格式也是可以自定义的,请移步定义路由日志的格式
BasicAuth 中间件
Basic Auth是一种开放平台认证方式,简单的说就是需要你输入用户名和密码才能继续访问。BasicAuth授权认证中间件使用
官方网站:Gin Web Framework
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156150.html