Day16 gin基础01 路由和视图
01 web应用程序介绍
数据库:存储数据的单元
前端:展示数据的单元
web层: 创建绑定 响应 这些功能都一样,重复。
业务层不一样,剔除业务层,其他的做成框架
只需填充业务代码即可
意义
用于搭建Web应用程序
免去不同Web应用相同代码部分的重复编写,只需关心Web应用核心的业务逻辑实现
web编程 特指浏览器发送的应用请求,按http协议响应
web框架和web应用程序关系:
Web 框架包含一系列库和一个主要的处理器 (handler),通过构建代码实现 Web 应用
02 web开发流程
===
http
请求协议:
请求首行: get 请求方式 /s?key=value请求路径 HTTP/1.1请求协议
请求头: user-agent:”win chrome”
空行
请求体 (post请求数据)
===
响应协议
响应首行 HTTP/1.1 200 ok
响应头: server-name:gin 响应服务器、响应时间、等
空行
响应体:”动态页面”
前后端不分离
数据直接嵌入到页面返回给客户端
03 gin下载与简单案例
1 安装
下载
$ go get -u github.com/gin-gonic/gin
导入
import "github.com/gin-gonic/gin"
(可选)
import "net/http"
====
使用go mod方式。
1 编写 go后缀文件
引入 import githob.com/gin-gonic/gin
2 初始化
go mod init demo
3 自动整理下载
go mod tidy
小案例
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func test(c *gin.Context){
fmt.Println("test...")
c.String(200,"hello world")
}
func main() {
r:=gin.Default()
//返回一个json数据
r.GET("/test",test)
r.Run()
}
04 restful
REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的请求方法代表不同的动作
restful接口规范
rpc接口
软件架构模式
没有遵循restful风格,通过url路径区分请求
/add_book/ add_book()
/select_book/ select_book()
/update_book/ update_book()
/delete_book/ delete_book()
通过GET POST 请求方法 符合restful规范接口
GET /books/ select_book()
POST /books/ add_book()
PUT /books/1 update_book()
DELETE /books/1 delete_book()
示例
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func test(c *gin.Context){
fmt.Println("test...")
c.String(http.StatusOK,"hello world")
}
func selectBook(c *gin.Context){
c.String(http.StatusOK,"查询书籍")
}
func addBook(c *gin.Context){
c.String(http.StatusOK,"添加书籍")
}
func updateBook(c *gin.Context){
c.String(http.StatusOK,"更新书籍")
}
func deleteBook(c *gin.Context){
c.String(http.StatusOK,"删除书籍")
}
func main() {
r:=gin.Default()
r.GET("/test",test)
r.GET("/books",selectBook)
r.POST("/books",addBook)
r.PUT("/books",updateBook)
r.DELETE("/books/1",deleteBook)
r.Run()
}
postman
05 路由方法
OPTIONS 请求跨域的方法
Any 任意路由
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func test(c *gin.Context) {
c.String(http.StatusOK, "测试页!")
}
func main() {
r := gin.Default()
r.Any("/test", test)
r.Run()
}
测试
noRoute
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func test(c *gin.Context) {
c.String(http.StatusOK, "测试页!")
}
func noMatch(c *gin.Context){
c.String(200,"没有匹配的路由,请重新发起请求!")
}
func main() {
r := gin.Default()
r.Any("/test", test)
r.NoRoute(noMatch)
r.Run()
}
路由分组
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func test(c *gin.Context) {
c.String(http.StatusOK, "测试页!")
}
func shop(c *gin.Context) {
c.String(200, "购物商城")
}
func cart(c *gin.Context) {
c.String(200, "购物车")
}
func noMatch(c *gin.Context) {
c.String(200, "没有匹配的路由,请重新发起请求!")
}
func main() {
r := gin.Default()
r.Any("/test", test)
r.GET("/app01/shop", shop)
r.GET("/app01/cart", cart)
r.NoRoute(noMatch)
r.Run()
}
维护性太差
func shop(c *gin.Context){
c.String(http.StatusOK,"购物商城")
}
func cart(c *gin.Context){
c.String(http.StatusOK,"购物车")
}
r.GET("/app01/shop",shop)
r.GET("/app01/cart",cart)
改为分组
func main() {
r := gin.Default()
r.Any("/test", test)
//r.GET("/app01/shop", shop)
//r.GET("/app01/cart", cart)
//路由分组
app01Group:=r.Group("/app01")
app01Group.GET("/shop",shop)
app01Group.GET("/cart",cart)
r.NoRoute(noMatch)
r.Run()
}
嵌套分组
func main() {
r := gin.Default()
r.Any("/test", test)
//r.GET("/app01/shop", shop)
//r.GET("/app01/cart", cart)
//路由分组
//app01Group:=r.Group("/app01")
//app01Group.GET("/shop",shop)
//app01Group.GET("/cart",cart)
//嵌套分组
app01Group:=r.Group("/app01")
app01Shop:=app01Group.Group("/shop")
app01Shop.GET("/index",shop)
app01Shop.GET("/cart",cart)
r.NoRoute(noMatch)
r.Run()
}
第二节 06 Gin视图 获取请求数据
请求参数和响应信息获取
获取基本请求信息
信息:
请求方式
请求ip
获取请求方式和请求路径URL
func test(c *gin.Context){
fmt.Println("请求方式:",c.Request.Method) //GET
fmt.Println("请求路径:",c.Request.URL) // /test
c.String(http.StatusOK,"test...")
}
func main() {
r:=gin.Default()
r.Any("/test",test)
_ =r.Run()
}
请求头c.Request.Header
func test(c *gin.Context){
fmt.Println("请求方式:",c.Request.Method) //GET
fmt.Println("请求路径:",c.Request.URL) // /test
fmt.Println("请求头:",c.Request.Header) //
c.String(http.StatusOK,"test...")
}
请求方式: GET
请求路径: /test
请求头: map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9] Accept-Encoding:[gzip, deflate, br] Accept-Language:[zh-CN,zh;q=0.9] Cache-Control:[max-age=0] Connection:[keep-alive] Sec-Ch-Ua:[" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"] Sec-Ch-Ua-Mobile:[?0] Sec-Ch-Ua-Platform:["Windows"] Sec-Fetch-Dest:[document] Sec-Fetch-Mode:[navigate] Sec-Fetch-Site:[none] Sec-Fetch-User:[?1] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36]]
获取请求头
func test(c *gin.Context){
fmt.Println("请求方式:",c.Request.Method) //GET
fmt.Println("请求路径:",c.Request.URL) // /test
fmt.Println("请求头:",c.Request.Header) //
fmt.Println("请求头:",c.Request.Header["User-Agent"]) //
fmt.Println("请求头:",c.GetHeader("User-Agent")) //
c.String(http.StatusOK,"test...")
}
请求方式: GET
请求路径: /test
请求头: map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9] Accept-Encoding:[gzip, deflate, br] Accept-Language:[zh-CN,zh;q=0.9] Cache-Control:[max-age=0] Connection:[keep-alive] Sec-Ch-Ua:[" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"] Sec-Ch-Ua-Mobile:[?0] Sec-Ch-Ua-Platform:["Windows"] Sec-Fetch-Dest:[document] Sec-Fetch-Mode:[navigate] Sec-Fetch-Site:[none] Sec-Fetch-User:[?1] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36]]
请求头: [Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36]
请求头: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36
获取请求ip
func test(c *gin.Context){
c.String(http.StatusOK,"test...")
fmt.Println("请求IP:",c.Request.RemoteAddr)
fmt.Println("请求IP:",c.ClientIP())
}
请求IP: 127.0.0.1:52647
请求IP: 127.0.0.1
06-02 请求数据的获取
获取GET请求参数
Query
DefaultQuery
没查到返回默认值
GetQuery
返回 bool值
func test(c *gin.Context){
c.String(http.StatusOK,"test...")
//GET请求数据的获取
fmt.Println(c.Query("name"))
fmt.Println(c.DefaultQuery("name","root"))
fmt.Println(c.GetQuery("name"))
}
访问:http://127.0.0.1:8080/test?name=zhangsan
发送name数据,返回:
zhangsan
zhangsan
zhangsan true
访问:http://127.0.0.1:8080/test?user=zhangsan
没发送name数据,返回:返回空 DefaultQuery返回默认值 GetQuery返回false
root
false
示例:应用返回的bool值
func test(c *gin.Context){
c.String(http.StatusOK,"test...")
//GET请求数据的获取
fmt.Println(c.Query("name"))
fmt.Println(c.DefaultQuery("name","root"))
fmt.Println(c.GetQuery("name"))
value,isExist:=c.GetQuery("name")
if isExist{
fmt.Println("value",value)
}else{
fmt.Println("没有传入name数据")
}
}
func main() {
r:=gin.Default()
r.Any("/test",test)
_ =r.Run()
}
请求:http://127.0.0.1:8080/test?user=zhangsan
返回
root
false
没有传入name数据
请求:http://127.0.0.1:8080/test?name=zhangsan
返回
zhangsan
zhangsan
zhangsan true
value zhangsan
获取Post请求参数
PostForm
DefaultPostForm
GetPostForm
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func test(c *gin.Context){
//(3) POST请求数据的获取 PostForm:解析contentType="urlencoded"
fmt.Println(c.PostForm("user"))
fmt.Println(c.DefaultPostForm("user","admin"))
fmt.Println(c.GetPostForm("user"))
c.String(200,"test...")
}
func main() {
r:=gin.Default()
r.Any("/test",test)
_=r.Run()
}
返回结果: user01 user01 user01 true
返回结果 admin false
数据类型标识,格式
浏览器请求协议:
浏览器请求协议:
""
post /s HTTP/1.1
user-agent:"win-chrome"
contentType:"json"
...
user=yuan&pwd=123
{"user":"user1","pwd":"123"}
请求体(post请求)
""
07 登录页面
demo\templates\index.html
Title
这是一个首页页面
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
)
func test(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Any("/test",test)
_=r.Run()
}
下午1 登录页面
demo\templates\login.html
Title
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
)
func test(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func loginHtml(c *gin.Context){
c.HTML(200,"login.html",nil)
}
func loginAuth(c *gin.Context){
//获取用户名和密码
user:=c.PostForm("user")
pwd:=c.PostForm("pwd")
if user=="root" && pwd=="123" {
//响应成功
c.String(200,"登录成功!")
}else{
//响应失败
c.String(200,"用户名或者密码错误!")
}
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Any("/test",test)
r.GET("/login",loginHtml)
r.POST("/login",loginAuth)
_=r.Run()
}
下午2路径参数
r.GET("/article/:year/:month",article)
对应
y:=c.Param("year")
m:=c.Param("month")
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func test(c *gin.Context){
c.String(200,"test...")
}
func loginHtml(c *gin.Context) {
c.HTML(200,"login.html",nil)
}
func loginAuth(c *gin.Context){
user:=c.PostForm("user")
pwd:=c.PostForm("pwd")
if user=="root" && pwd=="123"{
c.String(200,"登录成功!")
}else{
c.String(200,"用户名或者密码错误!")
}
}
func article(c *gin.Context) {
y:=c.Param("year")
fmt.Println(y)
c.String(200,y)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Any("/test",test)
r.GET("/login",loginHtml)
r.POST("/login",loginAuth)
r.GET("/article/:year",article)
_=r.Run()
}
添加带月份的路径参数
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func test(c *gin.Context){
c.String(200,"test...")
}
func loginHtml(c *gin.Context) {
c.HTML(200,"login.html",nil)
}
func loginAuth(c *gin.Context){
user:=c.PostForm("user")
pwd:=c.PostForm("pwd")
if user=="root" && pwd=="123"{
c.String(200,"登录成功!")
}else{
c.String(200,"用户名或者密码错误!")
}
}
func article(c *gin.Context) {
y:=c.Param("year")
m:=c.Param("month")
fmt.Println(y+" "+m)
c.String(200,y+" "+m)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Any("/test",test)
r.GET("/login",loginHtml)
r.POST("/login",loginAuth)
r.GET("/article/:year/:month",article)
_=r.Run()
}
练习
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func test(c *gin.Context){
fmt.Println("test...")
c.String(http.StatusOK,"hello world!")
}
func loginHtml(c *gin.Context){
c.HTML(200,"login.html",nil)
}
func loginAuth(c *gin.Context){
user:=c.PostForm("user")
pwd:=c.PostForm("pwd")
fmt.Println(user)
fmt.Println(pwd)
if user== "user1" && pwd=="123" {
c.String(200,"登录成功")
}else{
c.String(200,"登录失败")
}
}
func article(c *gin.Context) {
y:=c.Param("year")
m:=c.Param("month")
c.String(200,y+" "+m)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("template/*")
r.Any("/test",test)
r.GET("/login",loginHtml)
r.POST("/login",loginAuth)
r.GET("/article/:year/:month",article)
r.Run()
}
下午3 shouldbind函数
基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中querystring、form表单、JSON、XML等类型的数据,绑定到指定的结构体对象
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
type User struct {
Name string `json:"name" form:"name"`
Email string `json:"email" form:"email"`
}
func sb(c *gin.Context){
fmt.Println(c.PostForm("name"))
user:=User{}
err:=c.ShouldBind(&user)
if err!=nil{
fmt.Println("err",err)
}
fmt.Println(user)
fmt.Println(user.Name)
fmt.Println(user.Email)
c.String(200,"OK")
}
func main() {
r:=gin.Default()
r.POST("/shouldBind",sb)
_=r.Run()
}
发送json类型验证
发送urlencoded类型验证
postform只能接收urlencoded数据
下午4 09 gin框架的响应方式
1 响应字符串
package main
import (
"github.com/gin-gonic/gin"
)
func getStr(c *gin.Context){
c.String(200,"hello string!")
}
func main() {
r:=gin.Default()
r.GET("/str",getStr)
_=r.Run()
}
2 响应html页面
demo\templates\index.html
Title
这是一个首页页面
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
)
func getStr(c *gin.Context){
c.String(200,"hello string!")
}
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/str",getStr)
r.GET("/html",getHtml)
_=r.Run()
}
3 响应json
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
)
func getStr(c *gin.Context){
c.String(200,"hello string!")
}
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func getJson(c *gin.Context) {
c.JSON(200,gin.H{
"name":"user01",
"age":18,
})
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/str",getStr)
r.GET("/html",getHtml)
r.GET("/json",getJson)
_=r.Run()
}
Content-Type: application/json; charset=utf-8
4 响应xml
package main
import (
"github.com/gin-gonic/gin"
)
func getStr(c *gin.Context){
c.String(200,"hello string!")
}
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func getJson(c *gin.Context) {
c.JSON(200,gin.H{
"name":"user01",
"age":18,
})
}
func getXml(c *gin.Context) {
c.XML(200,gin.H{
"name":"user01",
"age":18,
})
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/str",getStr)
r.GET("/html",getHtml)
r.GET("/json",getJson)
r.GET("/xml",getXml)
_=r.Run()
}
Content-Type: application/xml; charset=utf-8
响应protobuf格式(未测试,待补充)
func getProtobuf(c *gin.Context){
//c.YAML(http.StatusOK, gin.H{"message":"消息"})
reps := []int64{int64(9),int64(55)}
// 自定义数据
label := "你好啊,今天天气挺好的"
// 传protobuf格式数据
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
fmt.Println(data)
c.ProtoBuf(200,data)
}
练习
package main
import (
"github.com/gin-gonic/gin"
)
func getStr(c *gin.Context){
c.String(200,"hello")
}
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func getJson(c *gin.Context){
c.JSON(200,gin.H{
"name":"user1",
"age":22,
})
}
func getXml(c *gin.Context){
c.XML(200,gin.H{
"name":"user2",
"age":18,
})
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("template/*")
r.GET("/str",getStr)
r.GET("/html",getHtml)
r.GET("/json",getJson)
r.GET("/xml",getXml)
_ = r.Run()
}
下午5 静态文件
让浏览器访问请求直接能访问到静态文件 css 和js等
示例1
demo\templates\index.html
Title
这是一个首页页面
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
)
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/html",getHtml)
_=r.Run()
}
测试访问
示例2
1 修改静态文件
修改静态文件
demo\statics\common.css
h3{
text-align: center;
}
demo\statics\index.js
window.onload=function (){
dom=document.querySelector("h3")
dom.onclick=function(){
this.style.color="green"
}
}
demo\templates\index.html
Title
这是一个首页页面
2修改main.go 增加Static
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
)
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Static("/static","statics")
r.GET("/html",getHtml)
_=r.Run()
}
3 测试访问到静态资源
http://127.0.0.1:8080/static/common.css
3.2 测试访问
测试访问http://127.0.0.1:8080/html,点击页面变绿色
正常1个请求1个响应
发送三个请求
下午6 重定向
c.Redirect(http.StatusFound,"https://www.baidu.com")
demo\main.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func getRedirect(c *gin.Context) {
c.Redirect(http.StatusFound,"https://www.baidu.com")
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Static("/static","statics")
r.GET("/html",getHtml)
r.GET("/redirect",getRedirect)
_=r.Run()
}
站内重定向
c.Redirect(http.StatusFound,"/html")
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func getHtml(c *gin.Context){
c.HTML(200,"index.html",nil)
}
func getRedirect(c *gin.Context) {
c.Redirect(http.StatusFound,"/html")
}
func main() {
r:=gin.Default()
r.LoadHTMLGlob("templates/*")
r.Static("/static","statics")
r.GET("/html",getHtml)
r.GET("/redirect",getRedirect)
_=r.Run()
}