网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
import (
“github.com/gin-gonic/gin”
“net/http”
)
func main() {
r := gin.Default()
r.GET(“/user/:name/:action”, func(c *gin.Context) {
name := c.Param(“name”) // 使用Param可以获取路由URL里面的数据
action := c.Param(“action”)
c.String(http.StatusOK, name+" rush “+action)
})
_ = r.Run(”:8000")
}
* 获取表单参数,一般用于`POST`,`PUT`请求。
Gin提供了`.PostForm`方法获取Form表单的值。
package main
import (
“fmt”
“github.com/gin-gonic/gin”
“net/http”
)
func main() {
r := gin.Default()
r.POST(“/form”, func(c *gin.Context) {
username := c.PostForm(“username”)
password := c.PostForm(“password”)
c.String(http.StatusOK, fmt.Sprintf(“username:%s,password:%s”, username, password))
})
_ = r.Run(“:8000”)
}
### 1.4 文件上传与下载
#### 1.4.1 上传
* 提供了`.FormFile`来获取文件
package main
import (
“github.com/gin-gonic/gin”
)
func main() {
r := gin.Default()
r.POST(“/upload”, func(c *gin.Context) {
file, err := c.FormFile(“file”) // file是参数名称
if err != nil {
c.String(500, “上传图片出错”) //出错就会返回这个
}
c.SaveUploadedFile(file, file.Filename) // 保存文件
c.String(http.StatusOK, file.Filename) // 返回状态码
})
_ = r.Run(“:8000”)
}
#### 1.4.2 下载
### 1.5 路由拆分
我们一般来说,会把这个路由拆分成`URL`和`处理函数`。这样能高效管理我们的框架逻辑。
import (
“github.com/gin-gonic/gin”
“net/http”
)
func helloHandler(c *gin.Context) { // 把处理函数放在这里,可以处理一些复杂的业务
c.JSON(http.StatusOK, gin.H {
“message”: “Hello World!”, // 通过这个 gin.H{} 进行json格式的返回
})
}
// Router 配置路由信息
func Router() *gin.Engine {
r := gin.Default()
r.GET(“/hello”, helloHandler) // 这样这个路由就比较简洁了。
return r
}
## 2. 数据绑定
### 2.1 json数据格式
* 定义接收数据的结构体
`binding:"required"`修饰的字段,是必须有的,没有是会报错的。后面可以跟着限制,`满足限制`才不会报错。
type Product struct {
Name string form:"name" json:"name"
CategoryID int form:"category\_id" json:"category\_id"
Title string form:"title" json:"title" binding:"required,min=2,max=100"
Info string form:"info" json:"info" binding:"max=1000"
ImgPath string form:"img\_path" json:"img\_path"
Price string form:"price" json:"price"
DiscountPrice string form:"discount\_price" json:"discount\_price"
OnSale string form:"on\_sale" json:"on\_sale"
Num string form:"num" json:"num"
}
`gin`框架中提供了一个`ShouldBindJSON`方法,这样就能可以把`json格式`解析到`结构体`中。
func helloHandler(c *gin.Context) { // 把处理函数放在这里,可以处理一些复杂的业务
var data Product
if err := c.ShouldBindJSON(&data); err != nil {
// 进行数据的绑定,这样传过来的数据就会传入这个data当中
// gin.H封装了生成json数据的工具
c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()}) // 返回错误信息
return
}
c.JSON(http.StatusOK, gin.H{“status”: “200”})
}
// Router 配置路由信息
func Router() *gin.Engine {
r := gin.Default()
r.GET(“/hello”, helloHandler) // 这样这个路由就比较简洁了。
return r
}
### 2.2 form表单数据
同样的我们使用`2.1`中的`Product结构体`,注意一定要在结构体中,用`tags`标志`form`格式
上面的那个Product结构体是用tags标志了form格式和json格式的,所以两个都能用。
func helloHandler(c *gin.Context) { // 把处理函数放在这里,可以处理一些复杂的业务
var data Product
if err := c.Bind(&data); err != nil {
// Bind()默认解析并绑定form格式,这样传过来的数据就会传入这个data当中
c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()}) // 返回错误信息
return
}
c.JSON(http.StatusOK, gin.H{“status”: “200”})
}
### 2.3 URI
type Product struct {
Name string form:"name" json:"name" uri:"name”
CategoryID int form:"category\_id" json:"category\_id" uri:"category\_id"
Title string form:"title" json:"title" uri:“title binding:"required,min=2,max=100"
Info string form:"info" json:"info" uri:“info binding:"max=1000"
ImgPath string form:"img\_path" json:"img\_path" uri:"img\_path"
Price string form:"price" json:"price" uri:“price
DiscountPrice string form:"discount\_price" json:"discount\_price" uri:"discount\_price"
OnSale string form:"on\_sale" json:"on\_sale" uri:"on\_sale"
Num string form:"num" json:"num" uri:"num"
}
gin中提供了`ShouldBindUri`方法进行绑定
func helloHandler(c *gin.Context) { // 把处理函数放在这里,可以处理一些复杂的业务
var data Product
if err := c.ShouldBindUri(&data); err != nil {
c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()}) // 返回错误信息
return
}
c.JSON(http.StatusOK, gin.H{“status”: “200”})
}
>
> 无论是`ShouldBindJSON`还是`Bind`还是`ShouldBindUri`
> 不过我个人比较喜欢用`c.ShouldBind()`这种,看个人喜欢吧~
>
>
>
## 3. 参数验证
### 3.1 普通情况
type User struct {
Phone string form:"phone" binding:"required,gt=10"
//不能为空并且大于10
Name string form:"name" binding:"required"
Birthday time.Time form:"birthday" time\_format:"2006-01-02"
// 满足格式才能接收,减少了if-else的判断
}
### 3.2 自定义情况
使用 `gopkg.in/go-playground/validator.v8` 包
* 在结构体上,绑定这个`NotNullAndAdmin`。
type User struct {
Phone string form:"phone" binding:"required,gt=10"
//不能为空并且大于10
Name string form:"name" binding:"NotNullAndAdmin"
// 自定义一个验证
Birthday time.Time form:"birthday" time\_format:"2006-01-02"
// 满足格式才能接收,减少了if-else的判断
}
* 编写自定义方法
func nameNotNullAndAdmin(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
if value, ok := field.Interface().(string); ok {
return value != “” && !(“admin” == value)// 字段不能为空,并且不等于 admin
}
return true
}
* 把我们的自定义注册到`validator`中就好了
if v, ok := binding.Validator.Engine().(\*validator.Validate); ok {
\_ = v.RegisterValidation("NotNullAndAdmin", nameNotNullAndAdmin) //注册定义的验证方法
}
## 4. 渲染
### 4.1 数据的响应
* Json 前后端主流的交互数据格式,我自己也是经常用这个。
func main() {
r := gin.Default()
r.GET(“/json”,JsonHandler)
_ = r.Run(“:8000”)
}
func JsonHandler(c *gin.Context) {
c.JSON(200, gin.H{“message”: “HelloJson”, “status”: 200})
}
* Struct
func main() {
r := gin.Default()
r.GET(“/struct”, StructHandler)
_ = r.Run(“:8000”)
}
func StructHandler(c *gin.Context) {
var msg struct {
Name string
Message string
Number int
}
msg.Name = “FanOne”
msg.Message = “Golang”
msg.Number = 10001
c.JSON(200, msg)
}
* XML
func main() {
r := gin.Default()
r.GET(“/xml”, XMLHandler)
_ = r.Run(“:8000”)
}
func XMLHandler(c *gin.Context) {
c.XML(200, gin.H{“message”: “HelloXml”})
}
* YAML
func main() {
r := gin.Default()
r.GET(“/yaml”, YAMLHandler)
_ = r.Run(“:8000”)
}
func YAMLHandler(c *gin.Context) {
c.YAML(200, gin.H{“message”: “HelloYaml”})
}
* ProtoBuf 这几年很火的数据格式
func main() {
r := gin.Default()
r.GET(“/protobuf”, ProtoBufHandler)
_ = r.Run(“:8000”)
}
func ProtoBufHandler(c *gin.Context) {
reps := []int64{int64(1), int64(2)}
// 定义数据
label := “label”
// 传protobuf格式数据
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
c.ProtoBuf(200, data)
}
### 4.2 模板渲染
>
> * gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据,本质上就是字符串替换
> * `LoadHTMLGlob()`方法可以加载模板文件
> * `Static`方法可以加载静态文件
>
>
>
* 加载HTML模板
func main() {
r := gin.Default()
r.LoadHTMLGlob(“tempate/*”) // 加载你的模板文件 就是html文件嗷
r.GET(“/index”, func(c *gin.Context) {
c.HTML(http.StatusOK, “index.html”, gin.H{“msg”: “HelloWorld”, “status”: “200”})
})
r.Run()
}
![img](https://img-blog.csdnimg.cn/img_convert/7ce28783f12c58dd96c36b09533bbf87.png)
![img](https://img-blog.csdnimg.cn/img_convert/e2f21e9dc31903da1f5c0b944e5c4341.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
c.HTML(http.StatusOK, "index.html", gin.H{"msg": "HelloWorld", "status": "200"})
})
r.Run()
}
[外链图片转存中…(img-o6emSw37-1715372745477)]
[外链图片转存中…(img-ouITbN5y-1715372745478)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!