1.初始化项目:go mod init
2.下载gin框架:go get -u github.com/gin-gonic/gin
可能用到的命令:go env -w GOSUMDB=off
3.引入:import "github.com/gin-gonic/gin"
注意点:
报错:$GOPATH/go.mod exists but should not
去掉goland编辑器里面的gopath文件(setting->GO):
手动设置(goland编辑器):setting-> Modules GOPROXY=https://goproxy.cn
示例:
//包名
package main
//引入包
import "github.com/gin-gonic/gin"
//主函数
func main() {
//gin框架初始化
r := gin.Default()
//初始化GET请求并返回json格式数据(200表示状态码)
r.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "hello gin!",
})
})
//运行(记住,run命令一定是在最后,后面的都不执行。默认监听8080端口)
r.Run() //r.Run(":8080");修改参数可以修改监听端口
}
测试命令: go run 文件路径
请求方式(前面讲到GET请求,http请求方法其实请求方式一共有8中,这8着重学习,RESTFUL风格接口和这一部分有紧密的练习,所以一定要研究透彻)
OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE、CONNECT
先讲一下常见的几个(掌握):
GET:返回实体信息(相当于sql里面的select)
POST:新增数据(相当于sql里面的insert)
PUT:修改数据(相当于sql里面的update)
DELETE:删除数据(相当于sql里面的delte)
不常见的几个(熟悉)
OPTIONS:用于获取目的资源所支持的通信选项,一般也是用于客户端查看服务器的性能
HEAD:设置请求信息
1.Accept:浏览器端能够处理的内容类型
2.Accept-Encoding:请求端能够处理的的压缩编码
3.Accept-Language:浏览器当前设置的语言
4.Connection:浏览器与服务器的连接类型
5.Host:发送请求的页面的域名
6.Referer:发送请求的页面的URI
7.User-Agent:浏览器的用户代理字符串
TRACE:沿着目标资源的路径执行消息环回测试
CONNECT:开启一个客户端与所请求资源之间的双向沟通的通道
来个例子尝尝(RESTful风格):
func index() {
r := gin.Default()
r.GET("/index", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "GET",
})
})
r.POST("/index", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "POST",
})
})
r.PUT("/index", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "PUT",
})
})
r.DELETE("/index", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "DELETE",
})
})
}
(MVC模式:控制层相当于搞定了,视图层该怎么做嘞?那么接下来简介视图部分),视图怎么渲染?使用LoadHTMLGlob()或者LoadHTMLFiles()方法进行HTML模板渲染(相当于模板引擎,模板引擎是个啥?这里就不描述了,此外前端还需要自己摸索一下,要不然就很丑,看下面的示例图就知道,css样式也不描述了,要不然讲不完了,主要还是讲我们的函数的使用)
HTML页面:
主方法:
注意:GET请求中c.HTML中第二个参数:描述html位置即模板位置的时候:注意放的是相对位置
详细解释一下:
1.view/*:表示预加载view文件加下的所有文件
2.文件夹下只有一层:view/* 或者 文件夹下有两层:view/**/* 依此类推
3.c.HTML加载的2文件,在示例中相当于:view/index.html
func main() {
r := gin.Default() //携带基础中间件启动
//预载入view文件夹下的所有文件
r.LoadHTMLGlob("../view/*") //注意相对位置(一定要注意)
//初始化GET请求
r.GET("/index", func(c *gin.Context) {
//页面输出(注意:输出JSON和输出到页面方法已经有了改变,注意变化)
c.HTML(200,"index.html",gin.H{
"title":"测试",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
函数体:
func main() {
r := gin.Default() //携带基础中间件启动
r.SetFuncMap(template.FuncMap{
"test": func(str string) template.HTML{
return template.HTML(str)
},
})
//预载入view文件夹下的所有文件(注意相对地址)
r.LoadHTMLFiles("../view/index.html")
//r.LoadHTMLGlob("../view/*")
//初始化GET请求
r.GET("/index", func(c *gin.Context) {
//页面输出(注意:输出JSON和输出到页面方法已经有了改变,注意变化)
c.HTML(200,"index.html",gin.H{
"title":"测试",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
HTML页面:
效果图:
JSON渲染:c.JSON
XML渲染: c.XML
YAML渲染: c.YAML
PROTOBUF渲染:c.PROTOBUF
示例:只讲JSON渲染 和 XML渲染,其他的可以参考官网
JSON渲染(可以参考一下我前面的文章,需要用到结构体):
r.GET("/jsons", func(c *gin.Context) {
type jsondata struct {
title string
}
var jsondatas jsondata
jsondatas.title = "我是json标题"
c.JSON(200,jsondatas)
})
XML渲染(可以参考一下我前面的文章,需要用到结构体):
r.GET("/xmls", func(c *gin.Context) {
type jsondata struct {
title string
}
var jsondatas jsondata
jsondatas.title = "我是json标题"
c.XML(200,jsondatas)
})
6.参数获取(接收值):
1.获取URL上携带的参数:Query
例如:域名?name=123&weight=60
var name := c.Query("name")
var weight:= c.Query("weight")
2.获取URL上携带的参数:Param(区分于第一种,这个相当于有一个预处理)
r.GET("/index/:username/:weight", func(c *gin.Context) {
username := c.Param("username")
weight := c.Param("weight")
})
3.获取表单提交的参数:Postform
例如:接受一个form表单提交过来的数据(还是以name和weight为例)
var name := c.Postform("name")
var weight:= c.Postform("weight")
4.获取json参数:Unmarshal
例如:
b, _ := c.GetRawData() // 从c.Request.Body读取请求数据
// 定义map或结构体(空接口类型)
var m map[string]interface{}
// 反序列化(将接收到的值反序列化后放入map集合,通过指针的方式实现)
_ = json.Unmarshal(b, &m)
c.JSON(http.StatusOK, m)
理解:通过映射的方式把接收到的参数放入结构体,不需要把参数一个一个放入结构了
例如:
//router.LoadHTMLFiles("../view/index.html")
router.LoadHTMLGlob("../view/*")
router.GET("/tests", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err == nil {
fmt.Printf("login info:%#v\n", login)
c.HTML(200,"index.html",gin.H{
"title": login.User,
"name": login.Password,
})
} else {
c.JSON(400, gin.H{"error": err.Error()})
}
})
涉及函数:
Formfile():单文件
MultipartForm() :多文件 (需要轮询保存文件)
SaveUploadFile():保存文件
//单文件件上传
router.POST("/upload", func(c *gin.Context) {
// 单个文件(判断上传的文件是否为空)
file, err := c.FormFile("f1")
if err != nil {
c.JSON(500, gin.H{
"message": err.Error(),
})
return
}
//文件上传路径
dst := "文件存放地址"//示例:fmt.Sprintf("文件夹绝对路径", file.Filename)
// 上传文件到指定的目录
c.SaveUploadedFile(file, dst)
//返回数据
c.JSON(200, gin.H{
"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
})
})
//多文件上传
router.POST("/uploadmult", func(c *gin.Context) {
//获取多文件
form, _ := c.MultipartForm()
files := form.File["file"]
//轮询上传
for index, file := range files {
log.Println(file.Filename)
//文件上传路径
dst := "文件存放地址"//示例:fmt.Sprintf("文件夹绝对路径", file.Filename,index)
// 上传文件到指定的目录
c.SaveUploadedFile(file, dst)
}
c.JSON(200, gin.H{
"message": fmt.Sprintf("%d files uploaded!", len(files)),
})
})
http重定向:Redirect(code,url)
路由重定向:
c.Request.URL.Path = "/test2"
r.HandleContext(c)
前面讲过RESTFUL风格的请求方式,那么通过前面的例子相比大家已经学习过了,简单的举个例子:
r.GET("/indexget", func(c *gin.Context) {...})
r.POST("/indexget", func(c *gin.Context) {...})
//这个路由方式是新的,这种方式可以接收到任何请求的方式
r.Any("/indexget", func(c *gin.Context) {...})
//这个路由方式是新的,这种路由的设置的作用:没有找到任何路由的请求会走到这个路由
r.NoRoute(func(c *gin.Context) {
c.HTML(http.StatusNotFound, "views/404.html", nil)
})
那么问题来了,我们写项目,会有很多方法,每一个方法我们都要去写路由,这样太麻烦了,那么就诞生一个叫路由组的定西,那么详细讲一下啥叫路由组,直接上例子
func main() {
//初始化框架
router := gin.Default()
//定义路由组
userGroup := router.Group("/user")
{
userGroup.GET("/details", func(c *gin.Context) {...})
userGroup.POST("/adduser", func(c *gin.Context) {...})
}
shopGroup := router.Group("/shop")
{
shopGroup.GET("/details", func(c *gin.Context) {...})
shopGroup.POST("/addshop", func(c *gin.Context) {...})
}
router.Run()
}
中间件类型:HandlerFunc
使用关键字:Use
中间件:中间件适合处理一些公共的业务逻辑,不用频繁的去重复写一个东西,可以理解成一个公共的类,处理大量公共的请求:路由—–> 中间件—–> 控制器
示例:
func middleW() gin.HandlerFunc {
return func(c *gin.Context) {
//todo
}
}
func main() {
router := gin.Default()
router.Use(middleW())
}
中间件的类别举例说明:
特殊方法:
c.Next()//调用剩余方法
c.Abort()//调过剩余方法
c.Set("","")//设置键值对(注意作用域范围)
c.Get("")//获取键值(注意作用域范围)
Return//终止执行当前中间件剩余内容,执行下一个中间件
下载驱动:
go get -u github.com/go-sql-driver/mysql
//定义全局变量
var db *sql.DB
//定义链接方法
func initdb() (err error) {
//定义链接参数
var dsn = "root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True"
//链接
db,err = sql.Open("mysql",dsn)
if err != nil {
fmt.Println("参数错误")
fmt.Println(err)
return err
}
err = db.Ping()
if err !=nil {
fmt.Println("参数错误2")
fmt.Println(err)
return err
}
return nil
}
func main() {
err := initdb()
if err != nil{
fmt.Println("链接失败")
}else{
fmt.Println("链接成功")
}
}
gorm操作数据库
下载驱动:
go get -u github.com/jinzhu/gorm
//引入
imports{
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"//前面的"_"表示只执行init()函数,并不需要全部的包
}
//定义结构体(记住字段名一定要大写)
type User struct {
ID int8
NAME string
SEX int
}
//主方法
func main(){
//连接参数:
var dscn = "root:root@(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
//连接数据库
db,err := gorm.Open("mysql",dscn )
//判断数据是否连接成功
if err != nil{
fmt.Println("error",err)
}
//数据自动迁移(免去了查询的结果要scan进结构体的麻烦)
db.AutoMigrate(&User{})
//定义结构体(自己理解是初始化)
var u = new(User)
//数据插入(定义数据,然后执行插入数据的动作)
u1 := User{1, "哈哈",1}
u2 := User{2, "嘻嘻",0}
//插入数据(用到了指针,这个是插入值,所以需要用到指针获取里面对应的值)
db.Create(&u1)
db.Create(&u2)
//批量插入数据(gorm必须是高版本,低版本不支持)
Userdata := []User{{2, "呼呼", 1}, {3, "嘻嘻", 0}}
db.Create(&Userdata)
//查询第一条数据(select * from users order by id limit 1 )
var u =new(User)
db.First(u)
fmt.Printf("%#v\n", u)
//条件查询(select * from users where id = 2 )
var uu =new(User)
db.Find(uu,"id =2")
fmt.Printf("%#v\n", uu)
//修改(UPDATE users SET name= '呼呼' WHERE id = 2)
db.Model(uu).Update("name", "呼呼")
//删除数据
db.Delete(uu)
}
到此为GIN框架疯速入门已经讲解完成,大家可以按照案例试试