Gin基本使用-基础篇
路由与传参
1、无参路由
package main
import (
"fmt"
"github.com/gin-gonic/gin"
//"github.com/gin-gonic/gin"
)
func main() {
// 1、创建路由engine
// r就是 *Engine 结构体
r := gin.Default()
// 2、路由绑定
/*
"/" 路由
func(c *gin.Context) 处理函数
*/
r.GET("/", func(c *gin.Context) {
// 第一:解析get/post请求的参数
// 第二:根据参数去查询数据库(操作数据库:添加数据、删除数据)
// 第三:返回从数据库查询的数据
c.String(200, "hello world")
})
fmt.Println("http://127.0.0.1:8000")
// 3、启动监听端口
// 对 net/http服务的封装,替换了 http.ListenAndServe(address, engine)
r.Run(":8000")
}
2、API参数
可以通过Context的Param方法来获取API参数
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func GetBookDetailHandler(c *gin.Context) {
bookId := c.Param("id")
// gin.Context,封装了request和response
c.String(http.StatusOK, fmt.Sprintf("成功获取书籍详情:%s", bookId))
}
func
main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// 基本路由 /book/24/
r.GET("/book/:id", GetBookDetailHandler)
// 3.监听端口,默认在8080
fmt.Println("运行地址:http://127.0.0.1:8000/book/24/")
r.Run(":8000")
}
3、url参数
URL参数可以通过DefaultQuery()
或Query()
方法获取
DefaultQuery()
若参数不存在,返回默认值,Query()
若不存在,返回空串
http://127.0.0.1:8080/user?name=zhangsan
package main
import (
"fmt"
"net/http"
)
import (
"github.com/gin-gonic/gin"
)
func GetUserDetailHandler(c *gin.Context) {
//username := c.DefaultQuery("name", "xxx")
username := c.Query("name")
// gin.Context,封装了request和response
c.String(http.StatusOK, fmt.Sprintf("姓名:%s", username))
}
func
main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// 基本路由 /user?name=root
r.GET("/user/", GetUserDetailHandler)
// 3.监听端口,默认在8080
fmt.Println("运行地址:http://127.0.0.1:8000/user?name=root")
r.Run(":8000")
}
4、ShouldBind参数绑定
我们可以基于请求的 Content-Type 识别请求数据类型并利用反射机制
自动提取请求中 QueryString
、 form表单 、 JSON 、 XML 等参数到结构体中
下面的示例代码演示了 .ShouldBind()
强大的功能
它能够基于请求自动提取 JSON 、 form表单 和 QueryString 类型的数据,并把值绑定到指定的结
构体对象。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
// Binding from JSON
type Login struct {
Username string `form:"username" json:"username" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func LoginHandler(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err != nil {
// 如果数据校验不通过直接返回
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
c.String(http.StatusOK, fmt.Sprintf("姓名:%s -- 密码:%s", login.Username, login.Password))
}
func
main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// 基本路由 /login/
r.POST("/login/", LoginHandler)
// 3.监听端口,默认在8080
fmt.Println("运行地址:http://127.0.0.1:8000/login/")
r.Run(":8000")
}
测试
综合示例
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
/*
http请求两块
第一:路由
第二:处理函数
- 获取get请求或者post请求的参数(gin第一步)
(根据参数去查询数据库)
- 从数据库查询并返回数据
*/
func main() {
// 1、生成engine
r := gin.Default()
// 2、注册路由
//r.GET("/hello", func(c *gin.Context) {
// c.String(200, "hello")
//})
// 2.1 无参路由
r.GET("/hello", HelloHandler)
// 2.2 API路由: http://127.0.0.1:8000/book/18
// :id 使用 id来获取 18这是值
r.GET("/book/:id", GetBookDeatilHandler)
// 3.3 url传参: http://127.0.0.1/user?id=20&name=zhangsan
r.GET("/user", GetUserDetailHandler)
// 3.4 shouldBind绑定(解析post请求中复杂的json数据)
r.POST("/login/", LoginHandler)
r.Run(":8000")
}
// 把handler处理函数拿出来
func HelloHandler(c *gin.Context) {
c.String(200, "hello")
}
func GetBookDeatilHandler(c *gin.Context) {
//bookId := c.Param("id1")
// 这里 c.Param("id") 这个id一定要和路由中 :id完全一致
bookId := c.Param("id")
fmt.Println(bookId, "____>")
c.String(200, "API params")
}
func GetUserDetailHandler(c *gin.Context) {
// 1、获取值,如果没有为 nil
name := c.Query("name")
// 2、获取值,如果没有使用默认值
/*
name : key
default val : 如果没传入参数,就是用默认值
*/
name2 := c.DefaultQuery("name", "default val")
fmt.Println("获取的用户名---》", name, name2)
c.String(200, "URL params")
}
type Login struct {
// post请求的数据字段名一定要和 `json:"username" 一模一样
// binding:"required" 要求username字段不能为空
Username string `json:"username" binding:"required"`
//Username string `json:"username"`
Password string `json:"password"`
}
// 第四种:shouldBind方法获取json中复杂数据,并且可以对参数进行校验
func LoginHandler(c *gin.Context) {
var login Login
// c.ShouldBind(&login) 方法必须要传入一个结构体对象
// 将 net/http中的 r.Body数据解析到 Login的结构体中
// c.ShouldBind(&login) => json.Unmarshal(bodyContent, &d)
if err := c.ShouldBind(&login); err != nil {
fmt.Println(err)
c.String(200, "参数校验错误")
}
fmt.Println(login.Username, login.Password)
c.String(200, "success")
}
响应返回
1、响应String
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/response/", ResponseStringHandler)
fmt.Println("http://127.0.0.1:8000/response/")
r.Run(":8000")
}
func ResponseStringHandler(c *gin.Context) {
c.String(http.StatusOK, "返回简单字符串")
}
2、响应JSON
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/response/", ResponseJsonHandler)
fmt.Println("http://127.0.0.1:8000/response/")
r.Run(":8000")
}
func ResponseJsonHandler(c *gin.Context) {
type Data struct {
Msg string `json:"msg"`
Code int `json:"code"`
}
d := Data{
Msg: "Json数据",
Code: 1001,
}
c.JSON(http.StatusOK, d)
//// 也可以直接使用 gin.H返回 json数据
// c.JSON(http.StatusOK, gin.H{
// "msg": "success",
// })
}
3、路由重定向
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "https://gl.sh.cn")
})
fmt.Println("http://127.0.0.1:8000")
r.Run(":8000")
}
路由分发
为什么需要路由分发?
我们一个项目有非常多的模块,如果全部写在一块导致代码结构混乱,不利于后续的扩展
按照大的模块,每个模块有自己独立的路由,主路由可以再main.go中进行注册
1、项目结构
2、main.go
package main
import (
// demo_router_layer 项目根路径
// go.mod文件中指定 module demo_router_layer
"github.com/gin-gonic/gin"
"xxx/routers" // 导入本地的模块
)
/*
1、初始化项目
go mod init xxx
go mod tidy // 更新项目中使用的模块
go get // 下载包
go.mod文件中指定 module demo_router_layer (指定导入根路径)
*/
func main() {
// r本质 实例化 *gin.Engine结构体
r := gin.Default() // 实例化engine引擎实例
// 注册路由
routers.LoadUsers(r)
routers.LoadBooks(r)
//utils.timeConv()
r.Run(":8000")
}
3、routers/users.go
package routers
import "github.com/gin-gonic/gin"
// 分层注册路由
func LoadUsers(r *gin.Engine) {
r.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
//e.GET("/user", UserHandler)
}
func UserHandler(c *gin.Context) {
c.String(200, "用户模块")
}
4、routers/books.go
package routers
import "github.com/gin-gonic/gin"
func LoadBooks(r *gin.Engine) {
// 这个r就是main函数中 gin.Default() 返回的
r.GET("/book", BookHandler)
}
func BookHandler(c *gin.Context) {
c.String(200, "书籍模块")
}
路由分发效果