2-gin路由
一 基本路由
- gin 框架中采用的路由库是基于httprouter做的
- 地址为:https://github.com/julienschmidt/httprouter
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func funcPost(c *gin.Context) {
c.String(http.StatusOK, "post请求")
}
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello word")
})
r.POST("/",funcPost)
//r.DELETE()
//r.PUT()
//r.OPTIONS()
//监听端口默认为8080
r.Run(":8000")
}
二 API参数
- 可以通过Context的Param方法来获取API参数
- localhost:8000/xxx/zhangsan
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func main() {
r := gin.Default()
r.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
fmt.Println(action)
//把字符串开头/截取掉
action = strings.Trim(action, "/")
fmt.Println(action)
c.String(http.StatusOK, name+" is "+action)
})
//默认为监听8080端口
r.Run(":8000")
}
三 URL参数
- URL参数可以通过DefaultQuery()或Query()方法获取
- DefaultQuery()若参数不存在,返回默认值,Query()若不存在,返回空串
- API http://localhost:8080/user?name=lqz
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/user", func(c *gin.Context) {
//指定默认值
//http://localhost:8080/user 才会打印出来默认的值
//name := c.DefaultQuery("name", "世界")
name := c.Query("name")
c.String(http.StatusOK, fmt.Sprintf("hello %s", name))
})
r.Run()
}
不传递参数输出的结果:
传递参数输出的结果:
四 表单参数
- 表单传输为post请求,http常见的传输格式为四种:
- application/json
- application/x-www-form-urlencoded
- application/xml
- multipart/form-data
- 表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
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,type:%s", username, password, types))
c.String(http.StatusOK, fmt.Sprintf("用户名:%s,密码:%s", username, password))
})
r.Run()
}
五 上传单个文件
- multipart/form-data格式用于文件上传
- gin文件上传与原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
//限制上传最大尺寸
r.MaxMultipartMemory = 8 << 20
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()
}
六 上传多个文件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
// gin的helloWorld
func main() {
// 1.创建路由
// 默认使用了2个中间件Logger(), Recovery()
r := gin.Default()
// 限制表单上传大小 8MB,默认为32MB
r.MaxMultipartMemory = 8 << 20
r.POST("/upload", func(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
}
// 获取所有图片
files := form.File["files"]
// 遍历所有图片
for _, file := range files {
// 逐个存
if err := c.SaveUploadedFile(file, file.Filename); err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
return
}
}
c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
})
//默认端口号是8080
r.Run(":8000")
}
七 routes group
routes group是为了管理一些相同的URL
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
// gin的helloWorld
func main() {
// 1.创建路由
r := gin.Default()
// 路由组1 ,处理GET请求
v1 := r.Group("/v1")
// {} 是书写规范,不写也开业
{
v1.GET("/login", login)
v1.GET("submit", submit) // /不写也可以
}
v2 := r.Group("/v2")
v2.POST("/login", login)
v2.POST("/submit", submit)
r.Run(":8000")
}
func login(c *gin.Context) {
name := c.DefaultQuery("name", "lqz")
c.String(200, fmt.Sprintf("hello %s\n", name))
}
func submit(c *gin.Context) {
name := c.DefaultQuery("name", "egon")
c.String(200, fmt.Sprintf("hello %s\n", name))
}
测试
get请求:127.0.0.1:8000/v1/login
get请求:127.0.0.1:8000/v1/submit
post请求:127.0.0.1:8000/v1/login
post请求:127.0.0.1:8000/v1/submit
八 路由拆分与注册
8.1 基本路由注册
适用于路由比较少的简单项目
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func helloHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Hello world!",
})
}
func main() {
r := gin.Default()
r.GET("/hello", helloHandler)
r.Run()
}
8.2 路由拆分成单独文件或包
当项目的规模增大后就不太适合继续在项目的main.go
文件中去实现路由注册相关逻辑了,我们会倾向于把路由部分的代码都拆分出来,形成一个单独的文件或包
8.2.1 拆分到单独文件中
routers.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func helloHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "www.liuqingzheng.top",
})
}
func testHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status":100,
"msg": "hello world",
})
}
func initRouter() *gin.Engine {
r := gin.Default()
r.GET("/hello", helloHandler)
r.GET("/test", testHandler)
return r
}
main.go
package main
func main() {
r := initRouter()
r.Run()
}
//访问
//http://127.0.0.1:8080/test
http://127.0.0.1:8080/hello
目录结构
8.2.2 拆分到包中
routers/routers.go
需要注意此时initRouter需要改成首字母大写:
package routers
import (
"net/http"
"github.com/gin-gonic/gin"
)
func helloHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "www.liuqingzheng.top",
})
}
func testHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status":100,
"msg": "hello world",
})
}
func InitRouter() *gin.Engine {
r := gin.Default()
r.GET("/hello", helloHandler)
r.GET("/test", testHandler)
return r
}
main.go
package main
import "gin_test/routers"
func main() {
r := routers.InitRouter()
r.Run()
}
目录结构
8.3 路由拆分成多个文件
单独的一个routers
文件或包已经满足不了我们的需求了
目录结构
routers/goods.go
package routers
import (
"github.com/gin-gonic/gin"
"net/http"
)
func LoadGoodsRouters(e *gin.Engine) {
e.GET("/good", goodHandler)
e.GET("/goodlist", goodlistHandler)
e.GET("/updategood", updategoodHandler)
}
func goodHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "www.liuqingzheng.top",
})
}
func goodlistHandler(c *gin.Context) {
c.String(http.StatusOK, "goodlistHandler")
}
func updategoodHandler(c *gin.Context) {
c.String(http.StatusOK, "updategoodHandler")
}
routers/order.go
package routers
import (
"github.com/gin-gonic/gin"
"net/http"
)
func LoadOrderRouters(e *gin.Engine) {
e.GET("/order", orderHandler)
e.GET("/orderlist", orderlistHandler)
e.GET("/updateorder", updateorderHandler)
}
func orderHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "www.liuqingzheng.top",
})
}
func orderlistHandler(c *gin.Context) {
c.String(http.StatusOK, "orderlistHandler")
}
func updateorderHandler(c *gin.Context) {
c.String(http.StatusOK, "updateorderHandler")
}
routers/user.go
package routers
import (
"github.com/gin-gonic/gin"
"net/http"
)
func LoadUserRouters(e *gin.Engine) {
e.GET("/user", userHandler)
e.GET("/userlist", userlistHandler)
e.GET("/updateuser", updateuserHandler)
}
func userHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "www.liuqingzheng.top",
})
}
func userlistHandler(c *gin.Context) {
c.String(http.StatusOK, "userlistHandler")
}
func updateuserHandler(c *gin.Context) {
c.String(http.StatusOK, "updateuserHandler")
}
main.go
package main
import (
"gin_test/routers"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
routers.LoadGoodsRouters(r)
routers.LoadOrderRouters(r)
routers.LoadUserRouters(r)
r.Run()
}
8.4 路由拆分到不同的APP
有时候项目规模实在太大,那么我们就更倾向于把业务拆分的更详细一些,例如把不同的业务代码拆分成不同的APP。
因此我们在项目目录下单独定义一个app
目录,用来存放我们不同业务线的代码文件,这样就很容易进行横向扩展。大致目录结构如下:
app01/shop/handler.go
package shop
import (
"github.com/gin-gonic/gin"
"net/http"
)
func shopHandler(c *gin.Context) {
c.String(http.StatusOK, "shopHandler")
}
func shopInfoHandler(c *gin.Context) {
c.String(http.StatusOK, "shopInfoHandler")
}
app01/shop/router.go
package shop
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/shop", shopHandler)
e.GET("/shopinfo", shopInfoHandler)
}
app01/user/handler.go
package user
import (
"github.com/gin-gonic/gin"
"net/http"
)
func userHandler(c *gin.Context) {
c.String(http.StatusOK, "userHandler")
}
func userInfoHandler(c *gin.Context) {
c.String(http.StatusOK, "userInfoHandler")
}
app01/user/router.go
package user
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/user", userHandler)
e.GET("/userinfo", userInfoHandler)
}
routers/routers.go
package routers
import "github.com/gin-gonic/gin"
type Option func(engine *gin.Engine)
var options=[]Option{}
//注册app的路由配置
func Include(opts ...Option) {
options=append(options,opts...)
}
//初始化
func Init()*gin.Engine {
r:=gin.New()
for _,opt:=range options{
opt(r)
}
return r
}
main.go
package main
import (
"gin_test/app01/shop"
"gin_test/app01/user"
"gin_test/routers"
)
func main() {
routers.Include(shop.Routers,user.Routers)
r:=routers.Init()
r.Run()
}