Gin框架日常使用--高频api使用示例

Go web框架目前有很多,Beego,Gin,Iris,Revel等等。目前国内使用量比较多的是前两个,鉴于Beego的源码一直被人吐槽并且Beego使用起来太过于臃肿,框架本身构造的大而全,很多功能不一定会是你想要的这些原因,我们着重关注Gin框架的使用。Gin没有像Beego那样什么都做,它只专注于web请求的封装,如果你想做缓存,想连接数据库等等还需要使用别的框架或者使用原生的API。

Gin的github地址如下: Gin点我

安装Gin:

go get github.com/gin-gonic/gin

1. 构建一个http请求

服务端构建一个http请求:

package main

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

func HelloWordGet (c *gin.Context)  {
	c.String(http.StatusOK, "hello world get")
}
func HelloWordPost (c *gin.Context) {
	c.String(http.StatusOK, "hello world post")
}
func main(){
	// 注册一个默认的路由器
	router := gin.Default()
	// 最基本的用法
	router.GET("/HelloWordGet", HelloWordGet)
	router.POST("/HelloWordPost", HelloWordPost)
	// 绑定端口是8080
	router.Run(":8080")
}

启动main函数,你可以在浏览器中调用链接,当然也可以使用http包去发送请求:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	resp, _ := http.Get("http://localhost:8080/HelloWordGet")
	bytes, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("get request: %s \n",string(bytes))

	response, _ := http.Post("http://localhost:8080/HelloWordPost",
		"application/x-www-form-urlencode", nil)
	bytes1, _ := ioutil.ReadAll(response.Body)
	fmt.Printf("get request: %s \n",string(bytes1))

}

2. 带参数的路由

如果想模仿restful api 的方式在 路由上面带参数应该如何实现呢。Gin提供了两种匹配方式:

一种是在路由上使用:paramName;

一种是在路由上使用:paramName/*action,paramName后面如果跟有任何路由,只要前缀一样都会到该route上。

package main

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

func HelloWordGet (c *gin.Context)  {
	name := c.Param("name")
	c.String(http.StatusOK, "hello world get %s",name)
}

func HelloWordGet1 (c *gin.Context)  {
	name := c.Param("name")
	c.String(http.StatusOK, "hello world get %s",name)
}

func main(){
	router := gin.Default()
	router.GET("/hello/get/:name", HelloWordGet)
	router.GET("/hello/get/:name/*action", HelloWordGet1)

	router.Run(":8080")
}

Param()方法用于接收来自于路由上的参数。

测试:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {
	resp, _ := http.Get("http://localhost:8080/hello/get/xiaoming")
	bytes, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("get request: %s \n",string(bytes))
}

3. Get,Post 请求方式传参 & 使用自定义表单方式接收参数

package main

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

type User struct {
	Name string
	Age int
	sex byte
}

func HelloWordGet1 (c *gin.Context)  {
	var user User
	c.Bind(&user)
	c.String(http.StatusOK, "hello world get %s,%s",user.Name,user.Age)
}

func HelloWordGet (c *gin.Context)  {
   name := c.DefaultQuery("name","NULL")
   age := c.Query("age")
   c.String(http.StatusOK, "hello world get %s,%s",name,age)
}

func HelloWordPost (c *gin.Context) {
   name := c.PostForm("name")
   sex := c.DefaultPostForm("sex", "1")
   c.JSON(http.StatusOK,gin.H{"status":0,"data":name+":"+sex,"message":"success"})
}
func main(){
   router := gin.Default()
   router.GET("/hello/get/", HelloWordGet)
   router.GET("/hello/get1/", HelloWordGe1t)
   router.POST("/hello/post", HelloWordPost)
   router.Run(":8080")
} 

Get,Post请求方式接收参数使用的方法为Query或者DefaultQuery(),区别就是一个可以设置默认值一个不可以。

注意到在Post方法中使用了JSON()方法来返回json格式的对象。

测试:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {
	resp, _ := http.Get("http://localhost:8080/hello/get?name=xiohong&age=1")
	bytes, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("get request: %s \n",string(bytes))

	body := "{\"name\":\"xiaoming\",\"age\":12,\"sex\":1}"
	response, _ := http.Post("http://localhost:8080/hello/post",
		"application/x-www-form-urlencode", strings.NewReader(body))
	bytes1, _ := ioutil.ReadAll(response.Body)
	fmt.Printf("get request: %s \n",string(bytes1))

}

4.单文件上传

使用c.Request.FormFile(param)方法来获取文件。

package main

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

//接收客户端上传的文件然后写入本地
func UploadFile(c *gin.Context) {
	file, header , err := c.Request.FormFile("file")
	filename := header.Filename
	fmt.Println(header.Filename)
	// 创建临时接收文件
	out, err := os.Create("copy_"+filename)
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()
	// Copy数据
	_, err = io.Copy(out, file)
	if err != nil {
		log.Fatal(err)
	}
	c.JSON(http.StatusOK,gin.H{"status":0,"data":nil,"message":"success"})
}

func main(){
	router := gin.Default()
	router.POST("/hello/upload", UploadFile)

	router.Run(":8080")


}

测试:

构造Post请求的时候,文件要使用multipart去承载,可以用它去设置header格式,设置文件名等等。

package main

import (
	bytes3 "bytes"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
)

func main() {
	buf := new(bytes3.Buffer)
	w := multipart.NewWriter(buf)
	fw,_ := w.CreateFormFile("file", "1.png") //这里的uploadFile必须和服务器端的FormFile-name一致
	fd,_ := os.Open("c:/1.png")
	defer fd.Close()
	io.Copy(fw, fd)
	w.Close()
	resp1,_ := http.Post("http://localhost:8080/hello/upload", w.FormDataContentType(), buf)
	bytes2, _ := ioutil.ReadAll(resp1.Body)
	fmt.Printf("get request: %s \n",string(bytes2))

}

5. 多文件上传

package main

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


//多文件上传,接收多文件,然后写入本地
func UploadMultFile(c *gin.Context) {
	form, _ := c.MultipartForm()
	files := form.File["file"]
	for _,file := range files {
		c.SaveUploadedFile(file,"c:/copy_"+file.Filename)
	}
	c.JSON(http.StatusOK,gin.H{"status":0,"data":nil,"message":"success"})
}


func main(){
	router := gin.Default()
	router.POST("/hello/multiUpload", UploadMultFile)

	router.Run(":8080")
}

测试:

package main

import (
	bytes3 "bytes"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {

	buf := new(bytes3.Buffer)
	w := multipart.NewWriter(buf)
	fw,_ := w.CreateFormFile("file", "1.png") 
	fd,_ := os.Open("c:/1.png")
	defer fd.Close()
	io.Copy(fw, fd)

	fw1,_ := w.CreateFormFile("file", "2.png") 
	fd1,_ := os.Open("c:/2.png")
	defer fd1.Close()
	io.Copy(fw1, fd1)
	w.Close()


	resp1,_ := http.Post("http://localhost:8080/hello/multiUpload", w.FormDataContentType(), buf)
	bytes2, _ := ioutil.ReadAll(resp1.Body)
	fmt.Printf("get request: %s \n",string(bytes2))
}

6. 路由分组–Java中Controller上的mapping

上面的示例中我们每构建一个Get或者Post请求,都要将完整的路由路径写入方法参数中。Java的同学可能就会抱怨了,为啥不能像SpringMVC中的Controller一样,定义一个统一的Controller mapping 前缀,然后整个Controller中的路由都会带上该前缀呢。别急,Gin也会考虑到这种使用方式,所以提供了路由分组的功能。

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

	helloGroup := router.Group("/hello")
	helloGroup.GET("/get", HelloWordGet)
	helloGroup.POST("/post", HelloWordPost)
	helloGroup.POST("/upload", UploadFile)
	helloGroup.POST("/multiUpload", UploadMultFile)

	userGroup := router.Group("/user")
	userGroup.GET("/get", HelloWordGet)
	userGroup.POST("/post", HelloWordPost)
	userGroup.POST("/upload", UploadFile)

	router.Run(":8080")
}

Group(param)方法可以上我们设置一个组名,使用该组对象发出的请求自动会带上该组名作为前缀。

7. 提供静态文件服务

可以将你本地的某些目录作为静态文件存储的目录对外提供访问。

func main(){
	router := gin.Default()
    //当前项目的根目录
	router.StaticFS("/all",http.Dir("."))
    //指定目录
    router.Static("/files","c:/bin")
    //指定文件
	router.StaticFile("specialFile","./a/1.png")

	router.Run(":8080")
}

第一个参数为url,第二个参数是要展示的路径。

8. 加载html模板

Java中我们可以使用thymeleaf或者freemarker来加载html模板,Gin中提供了这个功能,同时也定义了一套自己的模板解析方法。

使用LoadHTMLGlob() 或者 LoadHTMLFiles()

func main(){
	router := gin.Default()
	router.LoadHTMLGlob("templates/*")
	//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
	router.GET("/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.tmpl", gin.H{
			"title": "我就是个标题",
			"content": "我想说一句话",
		})
	})
	router.Run(":8080")

}

index.tmpl文件内容:




{{ .title }}

{{ .content }}

自定义渲染分隔符:

默认是用两个大括号隔开,你也可是设置成别的:

r := gin.Default()
r.Delims("{", "}")
r.LoadHTMLGlob("/templates")

自定义函数在模板中使用:

func formatAsDate(t time.Time) string {
	year, month, day := t.Date()
	return fmt.Sprintf("%d-%02d-%02d", year, month, day)
}

func main() {
	router := gin.Default()
	router.Delims("{", "}")
	router.SetFuncMap(template.FuncMap{
		"formatAsDate": formatAsDate,
	})
	router.LoadHTMLGlob("templates/*")
	router.GET("/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.tmpl", map[string]interface{}{
			"time": time.Date(2019, 06, 16, 10, 0, 0, 0, time.UTC),
		})
	})

	router.Run(":8080")
}

index.tmpl文件内容:




{.time | formatAsDate}

9.重定向

发布HTTP重定向很容易,支持内部和外部链接:

router.GET("/redirect", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "/index")
})

这一篇先介绍一些常用的使用,更多的 api 使用我们后面用到的时候再详细的介绍。

你可能感兴趣的:(Go语言学习,Go学习)