框架去做http解包封包等,让我们的精力用在应用开发
MVC模式
M: model操作数据库gorm
view 视图 处理模板页面
contoller 控制器 路由 +逻辑函数

解决gin相关代码飘红问题

记得启用gomodule
go env -w GO111MODULE=on

然后到相应目录执行 go mod init xxx
go mod tidy 
这样应该可以解决代码飘红,说找不到对应包的问题

由于墙的原因 需要更换代理执行 go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/

一、初步使用

//main.go
package main

import "github.com/gin-gonic/gin"
func main()	{
	gin.Default()
}
go mod init quickstart
go mod tidy
 go env -w GOPROXY=https://proxy.golang.org,direct
//main.go
package main

import "github.com/gin-gonic/gin"
func getuser(ctx *gin.Context){
	ctx.JSON(200,gin.H{
		"username":"you",
	})
}
func main()	{
	//获取引擎对象,即路由对象
	r:=gin.Default()

	//路由映射函数
	r.GET("/user",getuser)
	//启动默认本机8080端口 类似djangorunserver
	r.Run("127.0.0.1:8081")
}

访问相应路径如下
在这里插入图片描述

二、路由系统初识

2.1 服务端客户端发起各种请求方式处理

2.1.1 同一个资源不同请求方式
//路由映射函数同一个路由不同方法执行不同的逻辑
r.GET("/book", func(context *gin.Context) {
	context.JSON(200,gin.H{
		"msg":"查询成功",
	})

})
r.POST("/book", func(context *gin.Context) {
	context.JSON(200,gin.H{
		"msg":"新增成功",
	})

})

r.PUT("/book", func(context *gin.Context) {
	context.JSON(200,gin.H{
		"msg":"修改成功",
	})

})

r.DELETE("/book", func(context *gin.Context) {
	context.JSON(200,gin.H{
		"msg":"删除成功",
	})
})
2.1.2 Any
// any请求方式可以访问
r.Any("/index", func(context *gin.Context) {
	context.JSON(200,gin.H{
		"msg":"任何方式可以访问",
	})

})
2.1.3 NoRoute

//所有路由无法访问时,不管何种请求方式,走noroute返回相应信息
r.NoRoute( func(context *gin.Context) {
	context.JSON(404,gin.H{
		"msg":"404 not find",
	})

})

2.2 路由分组

go mod init route
go mod tidy 

在这里插入图片描述
入口

// main.go
package main

import "github.com/gin-gonic/gin"
import . "route/route"

func main()	{
	//获取引擎对象,即路由对象
	r:=gin.Default()
	//初始化路由
	InitBookRoute(r)
	//启动:默认本机8080端口
	r.Run("127.0.0.1:8081")
}

路由层

// route/book.go
package route

import "github.com/gin-gonic/gin"
import . "route/core" //导入业务函数
func InitBookRoute(r *gin.Engine){
	//路由分组 后面调用时候可以不写前缀
	bookRoute:=r.Group("/books")
	bookRoute.GET("/", Book)
	bookRoute.POST("/", BookAdd)
	bookRoute.PUT("/", BookEdit)
	bookRoute.DELETE("/", BookDelete)
}

业务函数

// core/book.go
package core

import "github.com/gin-gonic/gin"

func Book(context *gin.Context) {
	context.JSON(200, gin.H{
		"msg": "查询成功",
	})
}

func BookAdd(context *gin.Context) {
	context.JSON(200, gin.H{
		"msg": "新增成功",
	})
}

func BookEdit(context *gin.Context) {
	context.JSON(200, gin.H{
		"msg": "编辑成功",
	})
}

func BookDelete(context *gin.Context) {
	context.JSON(200, gin.H{
		"msg": "删除成功",
	})
}

三、请求响应

3.1 请求

3.1.1 请求基本信息
fmt.Println("method:", context.Request.Method) //method: GET
fmt.Println("method:", context.Request.URL) // method: /book?a=1
fmt.Println(context.FullPath()) //book
  • 某个请求头
fmt.Println("user-agent: ", context.GetHeader("user-agent")) //Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
  • 所有请求头
fmt.Println("所有头:", context.Request.Header) //map[Accept-Encoding:[gzip, deflate, br]]
fmt.Println("", context.Request.RemoteAddr)   // 127.0.0.1:50429 带端口
fmt.Println("RemoteIP: ", context.RemoteIP()) //127.0.0.1
fmt.Println("ClientIP: ", context.ClientIP()) //127.0.0.1
3.1.2 获取get请求数据
r.GET("/index", func(context *gin.Context) {

	//获取get请求方式数据 http://127.0.0.1:8081/index?kw=you
	fmt.Println("kw:", context.Query("kw")) //kw: you
	//设置默认值 取不到存在默认值 you
	fmt.Println(context.DefaultQuery("dkw:", "you")) //you
	context.String(200, "index")

	//取get数据如果没有提交则是false
	kw, ok := context.GetQuery("kw")
	if !ok {
		fmt.Println("参数存在:", ok) //参数存在false
	}
	println(kw)

})
3.1.3 获取post请求数据
r.POST("/data", func(context *gin.Context) {
	//PostForm接收form表单的数据 如 Content-Type: application/x-www-form-urlencoded user=youfei&pwd=123 或Content-Type: multipart/form-data;{"pwd":"123","user":"youfei"}
	//如果直接发json数据则不可以 Content-Type: application/json;
	user := context.PostForm("user")
	pwd := context.PostForm("pwd")
	//设置默认值 取不到存在默认值
	fmt.Println(context.DefaultPostForm("user", "'fei"))
	//取get数据如果没有提交则是false
	fmt.Println(context.GetPostForm("user"))
	//获取同一个键的多个返回切片
	fmt.Println(context.PostFormArray("user")) //[youfei zhang]

	context.JSON(200, gin.H{
		"user": user,
		"pwd":  pwd,
	})
})
3.1.4 获取shouldbind(常用)
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

type User struct {
	User string `json:"name"` //传参name 标记json需要content-type json
	Pwd  int    `json:"pwd"`
}

func main() {
	r := gin.Default()
	//shouldbind函数 根据content-type解析 需要结构体 常用
	r.POST("/shouldBind", func(context *gin.Context) {
	
		user := User{}
		//关于json的反序列化--映射到结构体对象上去 shouldbind根据结构体里字段标签处理是何种类型的content-type 如果是form表单,那么就要标记为 `form`
		context.ShouldBind(&user)
		context.JSON(200, gin.H{
			"data": user,
		})
	})
}

3.2 响应

  • 目录结构

在这里插入图片描述

package main
import "github.com/gin-gonic/gin"
//和django比较像 都是要返回render 一个页面
func main(){
	//返回一个默认的路由引擎
	r := gin.Default()

	//注册templates下所有的html文件
	r.LoadHTMLGlob("templates/*")

	//返回字符串
	r.GET("/test01", func(context *gin.Context) {
		context.String(200,"hello world")
	})

	//返回html codehtml名称 obj 修改静态文件不用重启程序
	r.GET("/test02", func(context *gin.Context) {
		context.HTML(200,"index.html",nil)
		
	})
	//返回json数据
	r.POST("/test03", func(context *gin.Context) {
		context.JSON(200,gin.H{
			"user_id": 1001,
			"username": "you",
		})

	})
	//返回xml数据
	r.POST("/test04", func(context *gin.Context) {
		context.XML(200,gin.H{
			"user_id": 1001,
			"username": "you",
			"friends": []string{"a","b","c"},
		})

	})
	//返回protobuf数据(后面补)
	//返回静态文件(配置

	//设置静态资源路径 参数一路由 参数本地真实路径
	r.Static("/static","./statics")

	r.Run("127.0.0.1:8081")
}

————————————————- 2023.328更新———————————————————————–

四、模板语法

django的模板语法大差不差,这种一般叫做MTV m:指模型orm那类,t指template,模板文件,vview,视图函数;都素是render一个渲染好的html文件,前端拿去展示

4.1 就是”.”

//main.go
package main

import "github.com/gin-gonic/gin"

func main(){
	//默认引擎
	r := gin.Default()
	//加载html
	r.LoadHTMLGlob("templates/*")

	name := "you"
	books :=[]string{"曾国藩的中年突围","红星照耀中国","陶庵梦忆"}
	//var stu01 = map[string]string{"name":"you","age":"18"}

	//声明一个map 键是string为空接口 啥子都能装
	stu_map := map[string]interface{}{
		"name":"phil","age":18,
	}

	type Person struct {
		Name string //大写外面才能读得到
		Age int64
	}
	person1 := Person{"you",18}
	//结构体的属性(相当于键)不用加 ""
	person2 := []Person{{Name:"you",Age:19},{Name:"san",Age:20}}
	r.GET("index", func(context *gin.Context) {
		context.HTML(200, "index.html",gin.H{
			"name":name,
			"books":books,
			"stu_map":stu_map,
			"Person":person1,
			"person2":person2,

		})
	})
	//启动
	r.Run("127.0.0.1:8081")

}
{{/*index.html*/}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>变量渲染</p>
{{.}}}
<li>{{.name}}</li>
</body>
</html>

4.2 模板获取变量


<p>取所有值</p>
<li>{{.}}</li>
<p>取某个值</p>
<li>{{.name}}</li>
<p>切片索引</p>
<li>{{index .books 0}}</li>
<p>map取值</p>
<li>{{.stu_map.name}}</li>
<p>struct取值</p>
<li>{{.Person.Name}}</li>
<p>管道(age会传到 %v 这个地方)</p>
<li>{{.Person.Age | printf "姓名:%sn 年龄:%v" "yuan" }}</li>

<h3>条件判断 </h3>
{{/*结尾需要写{{end}}} django是 {{endif}} {{endfor}}*/}}
{{if eq .Person.Age 18}}
    {{index .books 0}}
{{else if lt .Person.Age 18}}
    <p>这是else if</p>
{{end}}

<h3>循环判断</h3>
{{/*<h3> 变量复制使用$符号</h3>*/}}
{{range $key,$value := .stu_map}}
<p>{{$key}}: {{$value}}</p>
{{end}}
{{/*先取到切片在进行操作*/}}
{{range $value := .person2}}
    <p> {{$value.Name}}</p>
{{end}}

在这里插入图片描述

Error #01: template: index.html:44:20: executing "index.html" at <.name>: can't evaluate field name in type main.Person
{{/*<p>person2 := []Person{{Name:"you",Age:19},{Name:"san",Age:20}}"</p>*/}}
<h3>range循环里面使用全局变量需要重新赋值 他是取不到 </h3>
{{$localname := .name}}
<p>{{index .books 0}}</p>
{{$localbook := .books}}

{{range $value := .person2}}
    <p> {{$value.Name}}</p>

{{if eq $value.Name $localname}}
    {{index $localbook 0}}
{{else if eq $value.Age 18}}
    <p>这是else if</p>
{{end}}

{{end}}

在这里插入图片描述

五、gorm使用

gorm官方文档
yuan老师文档

5.1 创建数据库链接

// 创建数据库链接
//parseTime=True:将 MySQL 中的时间类型(如 datetimetimestamp 等)解析为 Go 中的时间类型time.Time)。如果不设置此参数,查询出来的时间类型会是 []uint8,需要手动转换time.Time。
//loc=Local:指定时区为本地时区。如果不设置此参数,时间会被转换为 UTC 时间,需要手动转换为本地时区
//DSN(Data Source Name),用于指定数据库连接信息dsn := "用户名:密码@tcp(127.0.0.1:3306)/数据库名?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"
newLogger := logger.New(
	log.New(os.Stdout, "rn", log.LstdFlags), //标准输出流(os.Stdout) 在每条日志之间添加了一个回车换行符"rn"),时间戳格式标准格式log.LstdFlags)
	logger.Config{
		LogLevel: logger.Info, //记录日志级别
	},
)

//db接收*gorm.DB 类型的对象 gorm.Config{} 是 gorm.Open 函数的第二个参数,用于指定 GORM 库的一些配置
db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{Logger: newLogger}) //配置了日志器
//创建模型type BaseModel struct {
	ID int `gorm:"primaryKey"`
	Name string `gorm:"type:varchar(32);unique;not null"`
	CreateTime *time.Time `grom:"autoCreateTime"`
	UpdateTime *time.Time `grom:"autoCreateTime"`
}

type Teacher struct{
	BaseModel
	Sno int
	Pwd string `gorm:"type:varchar(100);not null"`
	Tel string `gorm:"type:char(11);"`
	Birth *time.Time
	}
db.AutoMigrate(&amp;Teacher{})

模型会执行下面等语句字段全小写,int 会转换bigint

 CREATE TABLE `teachers` (`id` bigint AUTO_INCREMENT,`name` varchar(32) NOT NULL UNIQUE,`create_time` datetime(3) NULL,`update_time` datetime(3) NULL,`sno` bigint,`pwd` varchar(100) NOT NULL,`tel` char(11),`birth` datetime(3) NULL,`remark` varchar(255),PRIMARY KEY (`id`))

上面的表teachers为复数,这是gorm造成的,若想使用单数则需要写个函数

func (t Teacher)TableName() string  {
	return "teacher"
}

继续运行了一下,存在两张表了
在这里插入图片描述

5.2 gorm标签

primaryKey
autoIncrement
default:0
comment:主键id
  • 非空
not null
column:my_name
type Teacher struct {
	Id     int `gorm:"primaryKey;autoIncrement;comment:主键id"` //所谓蛇形复数
	Tno    int `gorm:"default:0"`
	Name   string `gorm:"type:varchar(10);not null"`
	Pwd    string `gorm:"type:varchar(100);not null"`
	Tel    string `gorm:"type:char(11);column:my_name"`
	Birth  *time.Time //它的零值(默认值)将是time.Time{},而不是 nil,因为 time.Time 是值类型,它的默认值是其零值。如果你想要在这个字段存储 NULL 值,就需要使用 *time.Time 类型,并将其设置nil。
	Remark string `gorm:"type:varchar(255);"`
	CreatTime *time.Time `gorm:"autoCreateTime;default null"`
	DeletedTime *time.Time `gorm:"default null"`
	UpdateTime  *time.Time `gorm:"autoUpdateTime;default null"`
}
CREATE TABLE `teachers` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '''主键id''',
  `tno` bigint DEFAULT '0',
  `name` varchar(10) COLLATE utf8mb4_general_ci NOT NULL,
  `pwd` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,
  `my_name` char(11) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `birth` datetime(3) DEFAULT NULL,
  `remark` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `creat_time` datetime(3) DEFAULT NULL,
  `deleted_time` datetime(3) DEFAULT NULL,
  `update_time` datetime(3) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

5.3 增删改查

5.3.1 增
	now := time.Now()
	t1 := Teacher{
		Tno:    001,
		Name:   "游",
		Pwd:    "123",
		Tel:    "136",
		Birth:  &amp;now,
		Remark: "第一位老师",
	}
	//新增数据
	res:=db.Create(&amp;t1)
	fmt.Println(t1) // 可以返回修改后的t1 {4 1 游 123 136 2023-04-24 14:15:57.6376609 +0800 CST m=+5.949186501 第一位老师}
	fmt.Println("错误:",res.Error) //错误: <nil>
	fmt.Println("影响行数:",res.RowsAffected) //影响行数: 1

在生产环境中 查询一般使用 db.Model(&amp;Teacher{})指定操作的表,结果可以定义 map[string]interface{}{}var teacher3 Teacher这把返回数据扫描到相应的结构中

res := map[string]interface{}{}
db.Model(&amp;Teacher{}).First(&amp;res)
fmt.Println(res) //这可以把结果扫描到map里 相当于字典 map[birth:2023-04-24 14:19:17.364 +0800 CST creat_time:<nil> deleted_time:<nil> id:1 my_name:136 name:游 pwd:123 remark:第一位老师 tno:1 update_time:<nil>]
res1 := map[string]interface{}{}
name := "游"
db.Model(&amp;Teacher{}).Where("name=?",name).Where("id=?",1).Limit(10).Order("id desc").Find(&amp;res1) //SELECT * FROM `teachers` WHERE name='游' AND id=1 ORDER BY id desc LIMIT 10
fmt.Println(res1)
deviceAlarm := []DeviceAlarm{}
//var total int64
db.Table("device_alarm a").Select("a.alarm_at").Joins("LEFT JOIN building_door b on b.id=a.door_id").
	Where("a.deleted_at=0 AND type=2 and a.alarm_at BETWEEN UNIX_TIMESTAMP(?) AND (UNIX_TIMESTAMP(?)) AND a.`status`= 1 and b.area_id in ? ",st,et,areaIds).
	Find(&amp;deviceAlarm)

六、gin校验字段

package main

import "github.com/gin-gonic/gin"

type Login struct {
	Username string `json:"username" binding:"required"` //binding:"required" 必传项
	Password string `json:"password" binding:"required"`
	Email    string `json:"email" binding:"required,email"` //binding:"email"` 符合email规则
	Age      int    `json:"age" binding:"required,gte=1,lte=100"` // 大于等于1 小于等于100
}

func loginfunc(c *gin.Context) {
	//1 获取参数
	var login Login
	if err:=c.ShouldBind(&login);err!=nil{
		c.JSON(400,gin.H{
			"code": 401,
			"msg": err.Error(),//
		})
		return
	}
	//2 业务逻辑
}

func main(){
	//初始化gin对象
	r:=gin.Default()
	r.GET("/login",loginfunc)
	r.Run(":9999")
}```
- 发起请求,没传age参数,email格式校验通过
![这里插入图片描述](https://img-blog.csdnimg.cn/d4b5c3d291454fa084ab04c2d92f1680.png)

参考如下
[作者:Yuan 链接http://www.yuan316.com/post/Gin%E6%A1%86%E6%9E%B6/](http://www.yuan316.com/post/Gin%E6%A1%86%E6%9E%B6/)






原文地址:https://blog.csdn.net/weixin_44259638/article/details/129653860

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_30788.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注