基于Gin框架的Go Web 学习

1 篇文章 0 订阅

Go Mod–我的理解

创建一个项目 在终端初始化一个mod go mod init 项目名(也可以是别的名字)然后自动创建一个.mod文件
然后 go get 包名 就可以下载相关的依赖 这样一来就不需要向gopath里导包 ,你下载的依赖以及依赖所需要的依赖都放在自动创建.sum文件中,.mod文件中就是你需要导入你项目的包
自己结构下的文件要加上init的名字 例如:原本的目录结构是 a/utils 这里要改成 initname/a/utils

----------------------------------------------------------------------------------

Web 入门------Hello Wrold

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/hello",handler)  //路径为/hello 调用handler处理器
	//路由器
	http.ListenAndServe(":8080",nil) //端口8080  nil使用默认复用器
}

//处理函数
func handler(writer http.ResponseWriter,request *http.Request){
	fmt.Fprintln(writer,"hello world")
}




连接MySQL数据库–实现增删改查

项目结构

在这里插入图片描述

db.go

package utils

import (
	"database/sql"
	_"github.com/go-sql-driver/mysql"
)

var(
	Db *sql.DB
	err error
)

func init() {
	Db,err=sql.Open("mysql","root:root@tcp(localhost:3306)/lyf")
	if err!=nil{
		panic(err.Error())
	}
}

users.go

package main

import (
	"fmt"
	"webstudy/DB_CURD/utils"
)

type User struct{
	ID int
	Username string
	Password string
	Email string
}

//********************增加*********************************
//预编译插入
func(u *User) Add() error{
	//1、sql语句
	sqlStr:="insert into users(username,password,email) values(?,?,?)"

	//2、预编译
	inStmt,err1:=utils.Db.Prepare(sqlStr)
	if err1!=nil{
		fmt.Println("预编译错误")
		return err1
	}

	//3、执行
	_,err2:=inStmt.Exec("ooo","666","1266621@qq.com")
	if err2!=nil{
		fmt.Println("执行错误")
		return err2
	}
	return nil
}

//******************删除******************
func (u *User) Del(id int) bool{
	//sql
	sqlStr:="delete from users where id=?"
	//预编译
	stmt,err1:=utils.Db.Prepare(sqlStr)
	if err1!=nil{
		fmt.Println("预编译错误")
		return false
	}
	res,err2:=stmt.Exec(id)
	if err2!=nil{
		fmt.Println("执行错误")
		return false
	}
	num,err3:=res.RowsAffected()
	if err3!=nil{
		return false
	}
	fmt.Printf("影响行:%d",num)
	return true
}

//**************************修改********************
func (u *User) Update(username string,password string,email string,id int) bool{
	sqlStr:="update users set username=?,password=?,email=? where id=?"
	stmt,err1:=utils.Db.Prepare(sqlStr)
	if err1!=nil{
		fmt.Println("预编译错误")
		return false
	}
	res,err2:=stmt.Exec(username,password,email,id)
	if err2!=nil{
		fmt.Println("执行错误")
		return false
	}
	num,err3:=res.RowsAffected()
	if err3!=nil{
		return false
	}
	fmt.Printf("影响行:%d",num)
	return true
}

//*************************查询***************
//查询单条数据,QueryRow 函数
func (u *User) SelectOne(id int){
	var username,password,email string
	err:=utils.Db.QueryRow("select username,password,email from users where id=?",id).Scan(&username,&password,&email)
	if err!=nil{
		err.Error()
		return
	}
	fmt.Println("username:",username,"password:",password,"email:",email)
}

//查询多条数据,并遍历
//Query 获取数据,for xxx.Next() 遍历数据
func (u *User) SelectAll(){
	rows,err:=utils.Db.Query("select username,password,email from users")
	if err!=nil{
		err.Error()
		return
	}
	for rows.Next(){
		var username,password,email string
		if err:=rows.Scan(&username,&password,&email);err==nil{
			fmt.Println("username:",username,"password:",password,"email:",email)
		}
	}
}

func main() {
	user:=&User{}
	//user.Add()
	//user.Del(1)
	//user.Update("嗯嗯嗯","00000","iii@00.222","2")
	//user.SelectOne(2)
	user.SelectAll()
}

初探Gin框架

(不允许转载!) 这是对Gin框架的初步介绍博客


Templates 入门小例子

文件结构

在这里插入图片描述

第一步 定义模板

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>hello</title>
</head>
<body>
    <p>Hello {{.}}</p>  {{/*    语法:后端传入什么 后面那一块就是什么*/}}
</body>
</html>

第二部 解析模板

	t,err:=template.ParseFiles("./templates/hello.tmpl")
	if err!=nil{
		fmt.Println("parse template err:",err)
		return
	}

第三步 渲染模板

	name:="haha"
	err2:=t.Execute(w,"哈哈哈哈哈"+name)  //这里用"哈哈哈哈哈"+name 去替换模板里的{{.}}
	if err2!=nil{
		fmt.Println("execute err",err2)
		return
	}

整个代码块

package main

import (
	"fmt"
	"html/template"
	"net/http"
)

//处理函数
func say(w http.ResponseWriter,r *http.Request){
	//定义模板  在hello.tmpl文件中
	//解析模板
	t,err:=template.ParseFiles("./templates/hello.tmpl")
	if err!=nil{
		fmt.Println("parse template err:",err)
		return
	}
	//渲染模板
	name:="haha"
	err2:=t.Execute(w,"哈哈哈哈哈"+name)  //这里用"哈哈哈哈哈"+name 去替换模板里的{{.}}
	if err2!=nil{
		fmt.Println("execute err",err2)
		return
	}
}

func main() {
	http.HandleFunc("/",say)
	err:=http.ListenAndServe(":8080",nil)
	if err!=nil{
		fmt.Println("开启端口错误",err)
	}
}

效果截图

在这里插入图片描述

(禁止转载!)更详细templates内容

自定义模板函数

目录结构

在这里插入图片描述

f1.tmpl
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>自定义函数模板</title>
</head>
<body>
    {{haha .}}  //haha是自己定义的模板函数
</body>
</html>
test.go (只给出了处理函数)
func handler(w http.ResponseWriter,r *http.Request){
	k:= func(name string)string {
		return name+"真帅!"
	}

	//      创建一个名字是f1的模板对象,名字要与模板名字相同(也可以直接template.New.Parse....)
	t:=template.New("f1.tmpl")

	//告诉模板引擎  我现在多了一个自定义的函数haha  一定要在解析模板之前
	t.Funcs(template.FuncMap{
		"haha":k,
	})

	//解析模板
	_,err:=t.ParseFiles("f1.tmpl")
	if err!=nil{
		fmt.Println(err)
		return
	}
	//渲染模板
	en:="李一夫"
	t.Execute(w,en)
}

模板的嵌套

u1.tmpl
<ul>
    <li>注释</li>
    <li>日志</li>
    <li>测试</li>
</ul>
t.tmpl
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>测试嵌套templates</h1>
    <hr>
{{/*    嵌套了另一个单独模板文件*/}}
{{template "ul.tmpl"}}

<hr>
{{/*嵌套另一个define定义的template模板*/}}
{{template "ol.tmpl"}}

<div>你好 , {{.}}</div>
</body>
</html>
{{/*****************************************************************************************/}}

{{/*通多define定义一个template模板*/}}
{{define "ol.tmpl"}}
    <ol>
        <li></li>
        <li></li>
        <li>rap</li>
    </ol>
{{end}}
test.go(只给出了处理函数)
func handler02(w http.ResponseWriter,r *http.Request){
	//解析模板
	t,err:=template.ParseFiles("./t.tmpl","ul.tmpl")//把大的模板文件写在前面
	if err!=nil{
		fmt.Println(err)
		return
	}
	//渲染模板
	name:="李一夫"
	t.Execute(w,name)
}
测试结果

在这里插入图片描述

模板的继承

例如此时我有A、B两个模板 他们的大致内容相同 我现在需要写两份高度相似的模板 浪费时间
现在我们可以写一个母板 然后A、B分别继承母板 只需要改动自己不同的那一小部分即可

test.go(只给出了处理函数部分)
func index02(w http.ResponseWriter,r *http.Request){
	//解析模板
	t,err:=template.ParseFiles("./templates/base.tmpl","./templates/index02.tmpl") //母板要放在前面
	if err!=nil{
		fmt.Println(err)
		return
	}
	//渲染模板
	name:="李一夫"
	//需要告诉模板引擎我们渲染的是哪一个模板  要用ExecuteTemplate
	t.ExecuteTemplate(w,"index02.tmpl",name)
}

func home02(w http.ResponseWriter,r *http.Request){
	//解析模板
	t,err:=template.ParseFiles("./templates/base.tmpl","./templates/home02.tmpl") //母板要放在前面
	if err!=nil{
		fmt.Println(err)
		return
	}
	//渲染模板
	name:="李一夫"
	//需要告诉模板引擎我们渲染的是哪一个模板  要用ExecuteTemplate
	t.ExecuteTemplate(w,"home02.tmpl",name)
}
base.tmpl(母板)
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>母板继承</title>
    <style>
        *{
            margin: 0;
        }
        .nav{
            height: 50px;
            width: 100%;
            position: fixed;
            top: 0;
            background-color: burlywood;
        }
        .main{
            margin-top: 50px;
        }
        .menu{
            width: 20%;
            height: 100%;
            position: fixed;
            left: 0;
            background-color: cornflowerblue;
        }
        .center{
            text-align: center;
        }
    </style>
</head>
<body>
<div class="nav"></div>
<div class="main">
    <div class="menu"></div>
    <div class="content center">
{{/*        block块  是被继承后需要改的   其他地方被继承后相同  后面的 . 不要忘记*/}}
{{/*        "content  是块名"*/}}
       {{block "content" .}}
        {{end}}
    </div>
</div>
</body>
</html>
index02.tmpl(继承模板)
{{/*继承跟模板   后面用来接收数据的 . 别忘记了*/}}
    {{template "base.tmpl" .}}
{{/*重新定义块模板*/}}
    {{define "content"}}
        <h1>这是index页面</h1>
        <p> hello {{.}}</p>
    {{end}}
home02.tmpl(继承模板)
{{/*继承跟模板*/}}
{{template "base.tmpl" .}}
{{/*重新定义块模板*/}}
{{define "content"}}
    <h1>这是home页面</h1>
    <p> hello {{.}}</p>
{{end}}

template 自定义标识符

	//Delims函数可以修改标识符
	t,err:=template.New("hello.tmpl").Delims("{[","]}").ParseFiles("./hello.tmpl")

Gin 模板的渲染

目录结构

在这里插入图片描述

main.go(解析模板 于 加载静态文件部分(代码先后顺序改变了))
	//解析模板
	//r.LoadHTMLFiles("./template/index.tmpl")
	//解析多个模板文件可以用下面的格式
	r.LoadHTMLGlob("./template/**/*")//访问template目录下的所有子目录的文件
		//路径为/index01时  用此匿名函数
	r.GET("/index01",func(c *gin.Context){
						//  name是模板的名称,users实在.tmpl中起的别名,否则就是文件名		//H 是一个map
		c.HTML(200,"users",gin.H{  //模板的渲染
			"title":"我是index01",
		})
	})
		//路径为/index01时  用此匿名函数
	r.GET("/index02",func(c *gin.Context){
		//  name是模板的名称,posts实在.tmpl中起的别名,否则就是文件名			//H 是一个map
		c.HTML(http.StatusOK,"posts",gin.H{  //模板的渲染
			"title":"<a href='https://liwenzhou.com'>大佬的博客</a>",
		})
	})
	//加载静态文件
	r.Static("/ha","./statics")  //.css文件中的路径要和relativePath相同  我的理解:将root路径起别名
	
	//Gin框架中给模板自定义函数   要在解析之前
	r.SetFuncMap(template.FuncMap{
		"safe": func(str string)template.HTML { //该匿名函数 将字符串转为HTML格式
			return template.HTML(str)
		},
	})
users/index.tmpl
{{/*起别名*/}}
{{define "users"}}

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="./ha/index.css">
{{/*    引用  css文件*/}}
    <title>Document</title>
</head>
<body>
{{.title}}
<script src="./ha/index.js"></script>
</body>
</html>
{{end}}
posts/index.tmpl
{{/*起别名*/}}
{{define "posts"}}

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    {{.title | safe}}
{{/*   |  是管道符号  类似于Linux中的用法  讲.title传来的数据用于safe方法*/}}
</body>
</html>
{{end}}

Gin框架返回json

json.go
package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

//*************************返回 json数据
func main() {
	//创建默认路由引擎
	r:=gin.Default()
	r.GET("/json", func(c *gin.Context) {
		//方法一:使用map
		data:=map[string]interface{}{
			"name":"李一夫",
			"message":"hello world!",
			"age":19,
		}
		//也可以使用下面的方法
		//data:=gin.H{
		//	"name":"李一夫",
		//	"message":"hello world!",
		//	"age":19,
		//}

		c.JSON(http.StatusOK,data)
	})

	//方法二 : 结构体
	type msg struct{
		Name string `json:"name"`  //用tag对结构体做定制化操作
		Age int
		Message string
	}

	r.GET("/struct", func(c *gin.Context) {
		data:=msg{
			Name:    "李一夫",
			Age:     19,
			Message: "很帅",
		}
		c.JSON(http.StatusOK,data)
	})
	r.Run(":8080")
}

Gin 获取querystring参数

querystring参数就是 GET请求 URL ?后面的就是querystiring参数
package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

//************gin 获取querystirng参数
func main() {
	r:=gin.Default()
	r.GET("/web", func(c *gin.Context) {  //与请求相关的基本都 与 c参数有关
		//获取浏览器发送请求携带的querystirng参数
		name:=c.Query("query") //通过Query获取请求中的querystring参数  格式:get请求 url ?query=xxx,取得值就是xxx
		age:=c.Query("age")
		//name:=c.DefaultQuery("query","hahahha")//如果取不到  默认值就是"hahahah"
		//name,ok:=c.GetQuery("query")  //返回值时string,bool   取的到就取 取不到就给默认值
		//if !ok{
		//	name="ennenen"
		//}
		c.JSON(http.StatusOK,gin.H{ //两个querystring参数可以用 & 来连接
			"name":name,
			"age":age,
		})
	})
	r.Run(":8080")
}

Gin 获取form表单参数

第一个GET是处理以get请求访问的login路径 ,返回login.html 在login.html中通过post请求提交表单 ,再次通过POST方法处理以post请求访问的login路径,返回index.html
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    <form action="/login" method="post" novalidate autocomplete="off">
        <label for="username">username:</label>
        <input type="text" name="username" id="username">

        <label for="password">password:</label>
        <input type="password" name="password" id="password">

        <input type="submit" value="登入">
    </form>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Hello {{.Name}}</h1>
    <h1>你的密码是:{{.Password}}</h1>
</body>
</html>
form.go
package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

// *************Gin 获取form表单提交的参数
//一次请求对应一个响应
func main() {
	r:=gin.Default()
	r.LoadHTMLFiles("./login.html","./index.html")
	//GET请求得到login.html里的格式  再用submit提交post请求时,则会再次新一次响应
	r.GET("/login", func(c *gin.Context) {
		c.HTML(http.StatusOK,"login.html",nil)
	})
	
	r.POST("/login", func(c *gin.Context) {
		//获取form表单提交的数据
		username:=c.PostForm("username") //key值是html中的name值
		password:=c.PostForm("password")
		//username:=c.DefaultPostForm("username","haha")没找到给默认值haha
		//username,ok:=c.GetPostForm("username") //第二个参数 bool   是否取到
		//if !ok{
		//	username="sb"
		//}
		c.HTML(http.StatusOK,"index.html",gin.H{
			"Name":username,
			"Password":password,
		})
	})
	r.Run(":8080")
}

Gin获取URL路径参数

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

//************gin 获取url路径参数

func main() {
	r:=gin.Default()
	r.GET("/:name/:age", func(c *gin.Context) {
		name:=c.Param("name")
		age:=c.Param("age")
		c.JSON(http.StatusOK,gin.H{
			"name":name,
			"age":age,
		})
	})
	r.Run(":8080")
}

效果截图

在这里插入图片描述


Gin绑定参数

package main

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

//  gin参数绑定:因为从页面取数据时  需要放在结构体中,使用shouldBind可简化操作

type User struct {
	Name string `form:"name" json:"name"`
	Age string	`form:"age" json:"age"`
	Sex string	`form:"sex" json:"sex"`
}

func main() {
	r:=gin.Default()

	//绑定querystring
	r.GET("/hello", func(c *gin.Context) {
		//***********使用下面的注释的步骤非常繁琐,要是结构体成员多,那就要写很多的c.Query方法
		//name:=c.Query("name")
		//age:=c.Query("age")
		//sex:=c.Query("sex")
		//u:=User{
		//	Name: name,
		//	Age:  age,
		//	Sex:  sex,
		//}
		//fmt.Println(u)
		//c.JSON(http.StatusOK,"ok")

		var u User
		err:=c.ShouldBind(&u)
		if err==nil{
			fmt.Println(u)
			c.JSON(http.StatusOK,"ok")
		}else{
			c.JSON(http.StatusBadRequest,gin.H{
				"err":err.Error(),
			})
		}

	})

	//绑定form
	r.POST("/hello", func(c *gin.Context) {
		var u User
		err:=c.ShouldBind(&u)
		if err==nil{
			fmt.Println(u)
			c.JSON(http.StatusOK,"ok")
		}else{
			c.JSON(http.StatusBadRequest,gin.H{
				"err":err.Error(),
			})
		}
	})

	//绑定json
	r.POST("/json", func(c *gin.Context) {
		var u User
		err:=c.ShouldBind(&u)
		if err==nil{
			fmt.Println(u)
			c.JSON(http.StatusOK,"ok")
		}else{
			c.JSON(http.StatusBadRequest,gin.H{
				"err":err.Error(),
			})
		}

	})
	r.Run(":8080")
}

(1)绑定json在postman中执行

在这里插入图片描述

(2)绑定form表单在postman中执行

在这里插入图片描述

(3)绑定querystring表单在postman中执行

在这里插入图片描述


Gin 上传文件

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"path"
)

//GIn 上传文件

func main() {
	r:=gin.Default()
	r.LoadHTMLFiles("./file.html")
	r.GET("/file", func(c *gin.Context) {
		c.HTML(http.StatusOK,"file.html",nil)
	})
	
	r.POST("/upload", func(c *gin.Context) {
		//从请求中读取文件
		f,err:=c.FormFile("f1")
		if err!=nil{
			c.JSON(http.StatusBadRequest,gin.H{
				"err":err.Error(),
			})
		}else {
			//将读取到的文件保存本地(服务端)
			//filepath:=fmt.Sprintf("./%s",f.Filename)  //也可以用下面的
			filepath:=path.Join("./",f.Filename)
			c.SaveUploadedFile(f,filepath)
			c.JSON(http.StatusOK,"ok")
		}

	})
	r.Run(":8080")
}

Gin重定向

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

//Gin重定向

//跳转到搜狗页面
func hello(c *gin.Context){
	c.Redirect(http.StatusMovedPermanently,"http://www.sogo.com")
}
func main() {
	r:=gin.Default()

	r.GET("/index",hello)

	r.GET("/a", func(c *gin.Context) {
		//跳转到b对应的处理函数
		c.Request.URL.Path="/b"  //把请求的url更改
		r.HandleContext(c)  //继续后续的处理
	})

	//返回json
	r.GET("/b", func(c *gin.Context) {
		c.JSON(http.StatusOK,"ok")
	})
	r.Run(":8080")
}

路由与路由组

//这就是路由
r.GET("/index", func(c *gin.Context) {...})
r.GET("/login", func(c *gin.Context) {...})
r.POST("/login", func(c *gin.Context) {...})
//这个是特殊的  是一个大杂烩,包括很多路由  可以在内部用switch语句来选择用哪个路由
r.Any("/test", func(c *gin.Context) {...})
//路由组
func main() {
	r := gin.Default()
	//把共用前缀提取出来,创建一个路由组
	userGroup := r.Group("/user")
	{
		userGroup.GET("/index", func(c *gin.Context) {...})
		userGroup.GET("/login", func(c *gin.Context) {...})
		userGroup.POST("/login", func(c *gin.Context) {...})

	}
	shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
	}
	//没有路由到的页面
	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound,gin.H{
			"err":"找不到你要的页面",
		})
	})
	r.Run()
}


Gin中间件

package main

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

//中间件  : 我的理解,类似于拦截器吧,比如你有n个页面,但是你需要让注册了账号的人才能访问,你不可能每一个页面中都写入if 是会员然后登入,
//			这时候就可以写一个中间件     浏览器---> 中间件 ---> 页面

//m1 相当于中间件 (统计处理函数的耗时时长)
func m1(c *gin.Context){
	fmt.Println("执行m1中间件..")
	//计时
	start:=time.Now()
	c.Next()  //接着调用后面的处理函数  下一个是匿名的
	//c.Abort()  //阻止调用下一个处理函数
	costtime:=time.Since(start) //从start到现在耗费的时间
	fmt.Printf("耗费的时间是:%v \n",costtime)
	fmt.Println("m1 执行完毕。。。")
}

func m2(c *gin.Context){
	fmt.Println("执行m2。。。")
	c.Set("name","李一夫")  //在中间件创建值  使得处理函数可以拿到
	c.Next()
	fmt.Println("结束m2")
}

func main() {
	r:=gin.Default()//默认使用了Logger()和Recovery()中间件
	//r:=gin.New()  //自定义一个空的路由引擎
	//r.Use(m1)  全局注册m1中间件  下面就可以省略写m1
	//					先执行m1   此时m1就相当于中间件
	r.GET("/index", m1,m2,func(c *gin.Context) {
		fmt.Println("执行handlerfun()")
		name:=c.MustGet("name")
		c.JSON(http.StatusOK,gin.H{
			"msg":name,
		})
	})
	r.Run(":9090")
}



Gorm框架学习

Gorm连接数据库以及模型的定义

package main
//   使用Gorm框架

import (
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql" //驱动
)

type UserInfo struct {
	Id uint `gorm:"primary_key"` //设置主键
	Name string `gorm:"column:user_name"`  //修改表字段名
	Gender string `gorm:"default :'不详'"` //默认值,下面没有实例此字段或者设置字段为空,都会使用默认值
								// 但会出现一个问题,如果我想把字段设为空值,但系统还是会使其默认为默认值
//解决方法1:可以将类型改为指针类型,在下面实例改为Gender: new(string)     new()函数的作用是将对应类型变为相应的指针类型
//解决方法2:先将结构体字段改为Gender sql.NullString `gorm:"default :'不详'"`
//			再将下面实例改为 Gender: sql.NullString{String:"",Valid:true}(true的意思是空字符串)
	Hobby string
}

//唯一指定表名   不自己定义表表名的话,系统会自动生成表名
func(UserInfo)TableName()string{
	return "haha"
}

func main()	 {
	//新建的默认表名都加上aaa_前缀
	//gorm.DefaultTableNameHandler= func(db *gorm.DB, defaultTableName string) string {
	//	return "aaa_"+defaultTableName
	//}
	db,err:=gorm.Open("mysql","root:root@tcp(localhost:3306)/lyf?charset=utf8mb4&parseTime=True&loc=Local")
	if err!=nil{
		panic(err )
	}
	defer db.Close()

	//在数据库自动创建表  自动迁移 (把结构体和数据表进行对应)
	db.AutoMigrate(&UserInfo{})
	//db.Table("liyifu").CreateTable(&UserInfo{})  使用UserInfo结构体创建指定名字的表
	//u1:=UserInfo{
	//	Id:     1,
	//	Name:   "李一夫",
	//	Gender: "男",
	//	Hobby:  "篮球",
	//}
	//创建数据行  类似于插入吧
	//db.Create(&u1)

	//查询
	var user UserInfo
	db.First(&user)  //查询表中第一条数据  并保存到user中
	fmt.Printf("user:%v\n",user)

	//更新
	db.Model(&user).Update("hobby","肉肉")

	//删除
	db.Delete(&user)
}




Gorm 的增删改查

具体看文档

package main

import (
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

//1、定义模板
type Person struct {
	//gorm.Model   //框架自带的四个字段  ID(主键id)  CreatAt(创建时间)  UpdataAt(修改时间) DeleteAt(删除时间)
	ID int `gorm:primary_key`
	Name string
	Age int
}
func main() {
	//连接MySQL数据库
	db, err := gorm.Open("mysql", "root:root@tcp(localhost:3306)/lyf?charset=utf8")
	if err != nil {
		panic(err)
	}
	defer db.Close()

	//2、把模板和数据库中的表对应
	db.AutoMigrate(&Person{})

	//3、插入数据
	//p1:=Person{
	//	Name:  "lyf",
	//	Age:   19,
	//}
	//db.Create(&p1)
	//p2:=Person{Name:"whh",Age:19,}
	//db.Create(&p2)

	//********************查询
	//if db.HasTable("people"){		 检测people表是否存在
	//	fmt.Println("存在表people")
	//}

	// 删除模型`Person`的表和表`people`
	//db.DropTableIfExists(&Person{}, "people")

	//var p Person
	//db.Debug().First(&p,1)//查询id为1的数据   主键是数字才可以使用
	//fmt.Printf("person: %#v \n",p)

	//db.Debug().First(&p,"name=?","whh") //查询name为whh的数据
	//fmt.Printf("person: %#v \n",p)

	//db.Debug().First(&p)  // 查询第一条数据  只适用于主键是数字
	//fmt.Printf("person: %#v \n",p)

	//var ps []Person
	//db.Debug().Find(&ps)   //任何操作前加一个Debug()可以看执行过程
	//fmt.Printf("persons:%#v \n",ps)

	//****************************where()查询
	//查询第一个name=whh的数据
	//db.Where("name=?","whh").First(&p)
	//fmt.Println(p)

	//查询所有age=19的数据
	//db.Where("age=?","19").Find(&ps)
	//fmt.Println(ps)

	//模糊查询
	//db.Where("name like ?","_h_").First(&p)
	//fmt.Println(p)

	//and
	//db.Where("name = ? and age >= ?","whh","18").Find(&ps)
	//fmt.Println(ps)

	//or
	//db.Where("name = ? or age >= ?","whh","18").Find(&ps)
	//fmt.Println(ps)

	//in
	//db.Where("name in (?)",[]string{"whh","lyf","lyf22"}).Find(&ps)
	//fmt.Println(ps)

	//struct 于 map
	// Struct
	//db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
	// Map
	//db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)

	//db.Where(Person{Name: "whh"}).FirstOrInit(&p)   FirstOrInit()没有就创造一个

	//  查找的name为lyf的数据中没有age的值是则创键  有则不变
	//db.Where(Person{Name: "lyf"}).Attrs(Person{Age: 20}).FirstOrInit(&p)

	//	无论name为lyf的数据有没有age的值   都将30赋予
	//db.Where(Person{Name: "lyf"}).Assign(Person{Age: 30}).FirstOrInit(&p)

	//db.Select("id, age").Find(&ps)
	//fmt.Println(ps)
	// SELECT name, age FROM people;

	//排序
	//db.Order("age desc, name").Find(&ps)
	 SELECT * FROM users ORDER BY age desc, name;

	//limit  指定查询几条记录
	//db.Limit(3).Find(&ps)

	//offset  跳过前几条数据
	//db.Offset(3).Find(&ps)

	//count  获取一共有多少条记录
	//var count int
	//db.Select("id,age").Find(&ps).Count(&count)
	//fmt.Println(count)

	//分组 group
	//rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()

	//*************************更新
	//var p Person
	//var ps []Person

	//save()  无论是否赋值  全部更新
	//db.First(&p)
	//fmt.Println(p)
	//p.Name="mzyf"
	//p.Age=20
	//db.Save(&p)
	//fmt.Println(p)

	//update()  修改单个字段值
	//db.Model(&p).Update("name","baba").Where("name=?","mzyf")
	//db.First(&p)
	//fmt.Println(p)
	//  使用结构体修改多个值
	// 使用 map 更新多个属性,只会更新其中有变化的属性
	//db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
	// 使用 struct 更新多个属性,只会更新其中有变化且为非零值的字段
	//db.Model(&user).Updates(User{Name: "hello", Age: 18})

	//******************删除
	//var p Person
	var ps []Person
	//db.Delete(&p)   删除所有
	//db.Find(&ps)
	//fmt.Println(ps)

}

一般开发的目录结构

在这里插入图片描述

controller层 :写路由中的方法,类似于c.json()…
dao层 : 连接数据库有关操作
logic层 : 大型项目处理复杂业务逻辑,小项目一般用不着
models层 : 放结构体模型以及增删改查的方法
routers层 : 创建默认引擎及r.RUN()之间的内容
static层 : 放静态资源
templates层 : 放模板文件
go.mod : 放项目依赖

-----于2020.4.27 17:23 学习完毕!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值