Go教程文档
何为gin
net/http
gin安装
go get -u github.com/gin-gonic/gin
入门案例
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// 1.创建路由
router:=gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
router.GET("/v1/topic", func(c *gin.Context) {
if c.Query("username") ==""{
c.String(http.StatusOK,"获取帖子列表")
}else {
username :=c.Query("username")
fmt.Print("username= ",username)
c.String(200,"获取用户名为%s的帖子的列表",c.Query("username"))
}
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
router.Run(":8000")
}
模块封装
在项目根目录下创建dao文件夹,将一些逻辑函数封装在这里!
创建TopicDao.go
package dao
import "github.com/gin-gonic/gin"
/*获取帖子列表*/
func GetTopicDetail(c *gin.Context) {
c.String(200,"获取topic id=%s的帖子",c.Param("topic_id"))
}
/*新增帖子*/
func AddTopic(c *gin.Context) {
c.String(200,"新增帖子!")
}
/*删除帖子*/
func DeleteTopic(c *gin.Context) {
c.String(200,"删除帖子!")
}
/*必须登录*/
func MustLogin() gin.HandlerFunc {
return func(c *gin.Context) {
//go语言中可以用下划线表示可忽略参数
if _,status:=c.GetQuery("token");!status{
c.String(401,"缺少token参数")
c.Abort()
}
}
}
函数名首字母要大写,你不大写GoLang会强制纠正你!我们知道go语言里,定义函数的关键字是func,紧跟着是函数名,参数列表与返回值!
主函数里使用
router:=gin.Default()
v1 :=router.Group("/a1/topic")
v1.GET("", func(c *gin.Context) {
if c.Query("username")==""{
c.String(200,"获取帖子列表")
}else {
c.String(200,"获取用户名为%s的帖子的列表",c.Query("username"))
}
})
v1.GET("/:topic_id", GetTopicDetail)
//使用将中间件添加到组中,请参阅GitHub中的示例代码。
v1.Use(MustLogin())//dao层定义的返回值是HandlerFunc,所以这里必须要加括号
v1.POST("", AddTopic)
v1.DELETE("/:id", DeleteTopic)
router.Run()
如果MustLogin函数执行不通过,那么下面的post和delete方法也不会再调用,因为被Abort了!
可以使用postman测试一下!
我这里呢就不再测试去掉Abort的结果了,有兴趣的伙伴可以试试,会调用post的方法哦!
我们再添加token参数,如下图:
结果响应成功!
实体封装
在项目根目录下创建model文件夹,在该文件夹下创建Topic.go
type Topic struct {
/* Id */
TopicId int `json:"topic_id"`
/* 标题 */
TopicTitle string `json:"topic_title"`
}
/* 创建Topic对象 */
func CreateTopic(id int, title string) Topic {
return Topic{id,title}
}
这里的`是左上角Esc下面的那个键,输入法切换至英语
json:"topic_id"
dao层使用:
/*获取帖子列表*/
func GetTopicDetail(c *gin.Context) {
//c.String(200,"获取topic id=%s的帖子",c.Param("topic_id"))
c.JSON(200,Model.CreateTopic(101,"帖子标题"))
}
main函数调用:
v1.GET("/:topic_id", GetTopicDetail)
{
topic_id: 101,
topic_title: "帖子标题"
}
拓展:
/* 查询绑定 */
type TopicQuery struct {
/**
json:相当于绑定一个别名
form:对应输入参数
binding:required表示此参数必有,否则报错
*/
UserName string `json:"username" form:"username" binding:"required"`
Page int `json:"page" form:"page"`
Size int `json:"size" form:"size"`
}
dao层使用:
/*获取帖子列表*/
func GetTopicList(c *gin.Context) {
query:=Model.TopicQuery{}
err:=c.BindQuery(&query)
if err != nil {
c.String(400,"参数错误%s",err.Error())
}else {
c.JSON(200,query)
}
}
main函数使用:
router.GET("v2/topic/list", GetTopicList)
各位朋友可以逐次测试,去掉form,看看能不能接收到参数,下图是正常请求!
实体中UserName不能为空,若为空则报错!
内置验证器的使用
模型:
/*内置验证器的使用*/
type TopicPlus struct {
/* Id */
TopicId int `json:"topic_id"`
/* 标题 */
TopicTitle string `json:"topic_title" binding:"min=4,max=20"`
/* 短标题 nefield不能与要求的字段重复 */
TopicShortTitle string `json:"topic_s_title" binding:"required,nefield=TopicTitle"`
/* 用户IP*/
UserIP string `json:"ip" binding:"ipv4"`
/* 分数 要大于5 */
TopicScore int `json:"score" binding:"gt=5"`
}
binding里面有很多内置的方法,你只需要像Java那样去配置就可以
dao层:
/*新增帖子*/
func AddTopic(c *gin.Context) {
query:=Model.TopicPlus{}
err:=c.BindJSON(&query) //绑定的是json
if err != nil {
c.String(400,"参数错误%s",err.Error())
}else {
c.JSON(200,query)
}
}
然后启动测试:
上图是按照实体里面绑定的规则来写的参数,实际你们可以试着打破这个规则,系统会有非常完美的提示!
正则验证Json参数
先写个实体:
/*内置验证器的使用*/
type TopicPlus struct {
/* Id */
TopicId int `json:"topic_id"`
/* 标题 */
TopicTitle string `json:"topic_title" binding:"min=4,max=20"`
/* 短标题 nefield不能与要求的字段重复 */
TopicShortTitle string `json:"topic_s_title" binding:"required,nefield=TopicTitle"`
/* 用户IP*/
UserIP string `json:"ip" binding:"ipv4"`
/* 分数 要大于5 */
TopicScore int `json:"score" binding:"gt=5"`
/* 链接 */
TopicUrlParam string `json:"url" binding:"omitempty,topicUrl"`
}
关键在于binding:"omitempty,topicUrl",这里topicUrl要与验证规则进行绑定
新建validator包,定义规则匹配类
package validator
import (
"github.com/go-playground/validator/v10"
"regexp"
)
//这是v10的写法,v8需要参照上面的博客
func TopicUrl(fl validator.FieldLevel) bool {
if url,ok:=fl.Field().Interface().(string);ok{
if matched,_ := regexp.MatchString(`\w{4,10}`,url); matched{
return true
}
}
return false
}
在main函数里,将上面两个配置进行关联:
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("topicUrl", TopicUrl)
}
以上是摘自官方和网络,有关自定义参数验证器的方法!
批量提交
相信不论是你学习什么语言,但凡提交必然会有批量提交的需求,Go同样不例外,那么Go的批量提交怎么去做呢?
Model:
/*批量新增*/
type Topics struct {
/* 定义一个切片 gt 大于 lt 小于*/
//dive是使Topic里面定义的规则生效!
TopicList []Topic `json:"topics" binding:"gt=0,lt=3,dive"`
TopicSize int `json:"size"`
}
dao:
/*批量新增帖子*/
func AddTopics(c *gin.Context) {
query:=Model.Topics{}
err:=c.BindJSON(&query)
if err != nil {
c.String(400,"参数错误%s",err.Error())
}else {
c.JSON(200,query)
}
}
main.go
v2 := router.Group("/a2/topic")
{
v2.POST("", AddTopics)
}
postman进行测验:
这样其实有一个问题,我们定义在Topic里面的参数约束会失效,那么我们怎么来解决呢?配置dive,他就会在添加的时候,对子层进行校验,如果子层的子层还有校验,同理添加!
Gorm简单入门
func main() {
//连接数据库
db, _ := gorm.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/leotemp?charset=utf8&loc=Local")
//一个坑,不设置这个参数,gorm会把表名转义后加个s,导致找不到数据库的表
db.SingularTable(true)
rows, _ := db.Raw("select id,className from class").Rows()
for rows.Next(){
var id int
var name string
rows.Scan(&id,&name)
fmt.Println(id,name)
}
defer db.Close()
}
建表:
CREATE TABLE `class` ( `id` int(10) NOT NULL COMMENT 'ID', `className` varchar(255) DEFAULT NULL COMMENT '班级名称', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
http://gorm.book.jasperxu.com/ 建议您在百忙中看完!只需一小时,过个大概!
DB封装
建表:
CREATE TABLE `topic_class` ( `class_id` int(11) NOT NULL COMMENT 'id', `class_name` varchar(255) DEFAULT NULL COMMENT '名称', `class_remark` text CHARACTER SET utf8mb4 COMMENT '备注', PRIMARY KEY (`class_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
model:
type TopicClass struct {
ClassId int `json:"class_id" gorm:"primary_key"`
ClassName string `json:"class_name"`
ClassRemark string `json:"class_remark"`
}
封装DB,先创建DataBase文件夹
package DataBase
import (
"fmt"
"github.com/jinzhu/gorm"
)
/**
封装数据库,需要完善!
*/
var DataHelper *gorm.DB
var err error
func init() {
DataHelper,err = gorm.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/leotemp?charset=utf8&loc=Local")
if err != nil{
fmt.Println(err)
//defer db.Close()
}
//一个坑,不设置这个参数,gorm会把表名转义后加个s,导致找不到数据库的表
DataHelper.SingularTable(true)
DataHelper.LogMode(true)
}
dao:
/*获取帖子列表*/
func GetTopicDetail(c *gin.Context) {
//c.String(200,"获取topic id=%s的帖子",c.Param("topic_id"))
//c.JSON(200,Model.CreateTopic(101,"帖子标题"))
tid := c.Param("topic_id")
topics:=Model.TopicClass{}
DataHelper.Find(&topics,tid)
c.JSON(200,topics)
}
main:
v1 := router.Group("/a1/topic")
v1.GET("/:topic_id", GetTopicDetail)
上面是最基础的代码,但是他存在一个问题就是连接开启后没有关闭,如果你手动关闭的话,那么访问完之后想要再次访问就不行了!