本文介绍: 让框架去做http解包封包等,让我们的精力用在应用层开发MVC模式M: model,操作数据库gormview 视图 处理模板页面contoller 控制器 路由 +逻辑函数解决gin相关代码飘红的问题。
让框架去做http解包封包等,让我们的精力用在应用层开发
MVC模式
M: model,操作数据库gorm
view 视图 处理模板页面
contoller 控制器 路由 +逻辑函数
记得启用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端口 类似django的runserver
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 code码 html名称 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,模板文件,v指view,视图函数;都素是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的使用
5.1 创建数据库链接
// 创建数据库链接
//parseTime=True:将 MySQL 中的时间类型(如 datetime、timestamp 等)解析为 Go 中的时间类型(time.Time)。如果不设置此参数,查询出来的时间类型会是 []uint8,需要手动转换为 time.Time。
//loc=Local:指定时区为本地时区。如果不设置此参数,时间会被转换为 UTC 时间,需要手动转换为本地时区
//DSN(Data Source Name),用于指定数据库的连接信息。
dsn := "用户名:密码@tcp(127.0.0.1:3306)/数据库名?charset=utf8mb4&parseTime=True&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), &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(&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
- 默认值0
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: &now,
Remark: "第一位老师",
}
//新增数据
res:=db.Create(&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(&Teacher{})
来指定要操作的表,结果可以定义为 map[string]interface{}{}
或var teacher3 Teacher
这把返回数据扫描到相应的结构中
res := map[string]interface{}{}
db.Model(&Teacher{}).First(&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(&Teacher{}).Where("name=?",name).Where("id=?",1).Limit(10).Order("id desc").Find(&res1) //SELECT * FROM `teachers` WHERE name='游' AND id=1 ORDER BY id desc LIMIT 10
fmt.Println(res1)
- 实际业务中,一般使用db.Table指定表明 table_name是指go语言中的表明,如struct中存在SsElectricTicket表使了tablename函数
func (*SsElectricTicket) TableName() string { return "ss_electric_ticket" }
那么他的表名就是ss_electric_ticket
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(&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进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。