1.安装Gin
go mod init 项目名
go get -u github.com/gin-gonic/gin
2.最简单的服务器
// 创建一个路由引擎
router := gin.Default()
// 配置路由
router.GET("/", func(ctx *gin.Context) {
ctx.String(200, "值:%v", "你好,Gin")
})
// 默认8080服务
router.Run(":8000") // 启动 web 8000服务
3.安装热加载air
go get -tool github.com/air-verse/air@latest
go tool air // 执行air
4.json
type Article struct {
Title string `json:"title"`
Content string `json:"content"`
}
type Response[T any] struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data T `json:"data"`
}
// 方式一 不推荐
router.POST("/json", func(ctx *gin.Context) {
ctx.JSON(200, map[string]any{
"code": 200,
"data": "ok",
})
})
// 方式二 不推荐
router.POST("/json2", func(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"code": 200,
"data": "ok",
})
})
// 方式三 推荐
router.POST("/json3", func(ctx *gin.Context) {
ctx.JSON(200, &Response[*Article]{
Code: 200,
Msg: "",
Data: &Article{
Title: "标题",
Content: "内容",
},
})
})
/* 打印
{
"code": 200,
"msg": "",
"data": {
"title": "标题",
"content": "内容"
}
}
*/
5.将数据绑定到结构体 方式一:
// GET 获取query数据
ctx.Query("xx")
ctx.DefaultQuery("xx","")
// POST 获取form数据
ctx.PostForm("")
ctx.DefaultPostForm("xx", "")
// POST 获取raw数据
ctx.GetRawData()
// 动态路由
ctx.Param("uid")
方式二:
type User struct {
Name string `form:"name" json:"name"`
// 解决前端传类型不规范问题,一会儿传 20(数字),一会儿传 "20"(字符串)
Age json.Number `form:"age" json:"age"`
}
router.POST("/json2", func(ctx *gin.Context) {
user := &User{}
// 自动绑定:无论前端传的是 Form 数据还是 JSON(Raw) 数据
// 这一句都能自动解析并转换类型!
ctx.ShouldBind(&user)
fmt.Println("绑定到结构体:", user)
ctx.JSON(200, map[string]any{
"code": 200,
"data": "ok",
})
})
6.路由分组
apiRoutes := router.Group("/api")
{
apiRoutes.POST("/add", func(ctx *gin.Context) {
ctx.String(200, "api添加")
})
apiRoutes.POST("/update", func(ctx *gin.Context) {
ctx.String(200, "api修改")
})
}
adminRoutes := router.Group("/admin")
{
adminRoutes.POST("/add", func(ctx *gin.Context) {
ctx.String(200, "admin添加")
})
adminRoutes.POST("/update", func(ctx *gin.Context) {
ctx.String(200, "admin修改")
})
}
7.抽离router admin.go
package routers
import "github.com/gin-gonic/gin"
func AdminInit(router *gin.Engine) {
adminRoutes := router.Group("/admin")
{
adminRoutes.POST("/add", func(ctx *gin.Context) {
ctx.String(200, "admin添加")
})
adminRoutes.POST("/update", func(ctx *gin.Context) {
ctx.String(200, "admin修改")
})
}
}
api.go
package routers
import "github.com/gin-gonic/gin"
func ApiInit(router *gin.Engine) {
apiRoutes := router.Group("/api")
{
apiRoutes.POST("/add", func(ctx *gin.Context) {
ctx.String(200, "api添加")
})
apiRoutes.POST("/update", func(ctx *gin.Context) {
ctx.String(200, "api修改")
})
}
}
main.go
router := gin.Default()
routers.ApiInit(router) // 初始化api
routers.AdminInit(router) // 初始化admin
8.抽离controller admin.go
package routers
import (
"gindemo/controllers/admin"
"github.com/gin-gonic/gin"
)
func AdminInit(router *gin.Engine) {
adminRoutes := router.Group("/admin")
{
adminRoutes.POST("/user/add", admin.UserController{}.UserAdd)
adminRoutes.POST("/user/update", admin.UserController{}.UserUpdate)
adminRoutes.POST("/article/add", admin.ArticleController{}.ArticleAdd)
adminRoutes.POST("/article/update", admin.ArticleController{}.ArticleUpdate)
}
}
admin文件夹下面新建两个文件,userController.go 和 articleController.go userController.go
package admin
import "github.com/gin-gonic/gin"
type UserController struct{}
func (con UserController) UserAdd(ctx *gin.Context) {
ctx.String(200, "admin user添加")
}
func (con UserController) UserUpdate(ctx *gin.Context) {
ctx.String(200, "admin user修改")
}
articleController.go
package admin
import "github.com/gin-gonic/gin"
type ArticleController struct{}
func (con ArticleController) ArticleAdd(ctx *gin.Context) {
ctx.String(200, "admin article添加")
}
func (con ArticleController) ArticleUpdate(ctx *gin.Context) {
ctx.String(200, "admin article修改")
}
8.中间件
func initMiddleware(ctx *gin.Context) {
fmt.Println("请求前")
ctx.Next()
fmt.Println("请求结束")
}
adminRoutes.POST("/article/add", initMiddleware, admin.ArticleController{}.ArticleAdd)
func (con ArticleController) ArticleAdd(ctx *gin.Context) {
fmt.Println("请求中")
ctx.String(200, "admin article添加")
}
/*输出 请求前,请求中,请求结束*/
判断用户是否登录
func InitMiddleware(ctx *gin.Context) {
ctx.Set("token", "1") // 设置token
fmt.Println("请求前")
ctx.Next()
fmt.Println("请求结束")
}
adminRoutes.POST("/article/add", middlewares.InitMiddleware, admin.ArticleController{}.ArticleAdd)
func (con ArticleController) ArticleAdd(ctx *gin.Context) {
token, _ := ctx.Get("token") // 获取token
if token != "" {
fmt.Println("已登录")
} else {
fmt.Println("未登录")
}
ctx.String(200, "admin article添加")
}
/*输出 请求前,已登录,请求结束*/
9.单文件上传和多文件上传 // 单文件
func (con UserController) UserUpload(ctx *gin.Context) {
// 获取前端上传的avator图片
file, err := ctx.FormFile("avator")
dst := path.Join("./upload", file.Filename)
if err == nil {
// 保存到当前项目的upload文件夹
ctx.SaveUploadedFile(file, dst)
}
fmt.Println(dst)
ctx.String(200, "admin user单文件上传")
}
// 多文件
func (con UserController) UserMultipleUpload(ctx *gin.Context) {
// 获取前端上传的avators图片
form, _ := ctx.MultipartForm()
files, ok := form.File["avators[]"]
if ok {
// 保存到当前项目的upload文件夹
for _, file := range files {
dst := path.Join("./upload", file.Filename)
ctx.SaveUploadedFile(file, dst)
}
}
ctx.String(200, "admin user多文件上传")
}
10.设置cookie
func (con UserController) UserAdd(ctx *gin.Context) {
// 设置/删除cookie,第三个参数 -1 为删除
ctx.SetCookie("token", "3271DF3DEAEB65C53EF9C848EB7964B7", 3600, "/", "localhost", false, false)
ctx.String(200, "admin user添加")
}
func (con UserController) UserUpdate(ctx *gin.Context) {
// 获取token
cookie, _ := ctx.Cookie("token")
fmt.Println("cookie----", cookie) // 3271DF3DEAEB65C53EF9C848EB7964B7
ctx.String(200, "admin user修改")
}
11.设置session session保存在服务器,cookie保存在浏览器
创建基于cookie的store
// 安装session
go get github.com/gin-contrib/sessions
1.配置session中间件
import {
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
...
}
router := gin.Default()
// 创建基于cookie的store,加密的密钥
store := cookie.NewStore([]byte("secret"))
// 配置session中间件
router.Use(sessions.Sessions("mysession", store))
2.设置session
session := sessions.Default(ctx)
session.Set("soken", "3271DF3DEAEB65C53EF9C848EB7964B7")
session.Save()
3.获取session
session := sessions.Default(ctx)
soken := session.Get("soken")
fmt.Println("session----", soken)
创建基于redis的store
import {
...
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/redis"
}
// 创建基于redis的store,加密的密钥
/* 六个参数:
size=10:连接池大小
network="tcp"
address="localhost:6379"
username="":Redis 无用户名认证时留空
password="":Redis 无密码时留空(如果你的 Redis 设置了密码,填在这里)
keyPairs=[]byte("secret"):真正用于 session 加密签名的密钥
*/
store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", "", []byte("secret"))
// 配置session中间件
router.Use(sessions.Sessions("mysession", store))
// 设置session过期时间
session.Options(sessions.Options{
MaxAge: 3600 * 6, // 6hrs
})
12.mysql常用命令
// 查看数据库
show databases;
// 选择数据库
use beego;
// 查看表
show tables;
// 查看表字段
describe users;
// 简单查询
select * from users;
// 单个字段查询
select username from users;
// 简单条件查询
select * from users where id = 1;
// 创建数据库
create database books;
// 删除数据库
drop database books;
// 创建表
create table users(
id int(11),
name varchar(255),
age int(3),
PRIMARY KEY (id)
);
// 删除表
drop table users;
// 添加数据
insert into users(name, age) values ("ww", 33);
// 修改数据
update users set id = 1 where name = "ww";
// 删除数据
delete from users where id = 1;
// 排序,升序,降序desc
select * from users order by id desc;
// 统计数量
select count(1) from users;
// 分页limit
select * from users limit 2; //
select * from users limit 1, 2; //跳过第1个,取2
13.mysql常用
整数型:tinyint,smallint,int,bigint
浮点型:float,double,decimal(m,d)
字符型:char,varchar
备注型:tinytext,text,longtext
where表达式常用运算符:=,>,<,>=,<=,!=,is not null,is null,between,not between,in,or,and,not,like "%x%"
分组函数:avg,count,max,min,sum
别名:`as`
内连接:inner join...on...
左外连接:left join...on...
右边连接:right join...on...
索引(提升查询速度):普通索引,唯一索引,(全文索引,空间索引 了解即可)
创建索引:
alter table 表名 add index 索引名(列名);
删除索引:
alter table 表名 drop index 索引名;
查看索引:
show index from 表名;
14.mysql事务和锁 事务
begin; -- 开启事务
update users set age = age - 40 where id = 563;
update users set age = age + 40 where id = 2490631;
commit; -- 事务确认
-- rollback; -- 事务回滚
锁,表级锁,行级锁
-- 添加读锁,可以并发读,不能并发写
lock table users read; --加读锁
unlock tables; --解锁
-- 添加写锁,只能一个人写
lock table users write; --加写锁
unlock tables; --解锁
15.gorm库1.安装 go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite
2.init中初始化gorm对象 core.go
package models
import (
"fmt"
"reflect"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func init() {
dsn := "root:@tcp(127.0.0.1:3306)/books?charset=utf8mb4&parseTime=True&loc=Local"
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
} else {
fmt.Println("数据库连接成功")
fmt.Println(reflect.ValueOf(DB), reflect.TypeOf(DB))
}
}
3.创建表及操作的models 创建user表
create table user(
id int(11) AUTO_INCREMENT,
username varchar(255),
age tinyint,
email varchar(255),
add_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
insert into user(username,age,email) values("ww", 33, "test1@gmail.com");
得到该数据:
+----+----------+------+-----------------+---------------------+
| id | username | age | email | add_time |
+----+----------+------+-----------------+---------------------+
| 1 | ww | 33 | test1@gmail.com | 2026-09-19 10:42:57 |
+----+----------+------+-----------------+---------------------+
声明user的models
package models
import (
"encoding/json"
"time"
"gorm.io/gorm"
)
type User struct {
Id int `json:"id"`
Username string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
AddTime time.Time `json:"-"` // 数据库为 DATETIME 类型(dsn 开启了 parseTime),需用 time.Time 接收,否则 Scan 类型不匹配导致该字段恒为 0
}
func (User) TableName() string {
// 自定义表名
return "user"
}
// BeforeCreate GORM 钩子:插入前自动填充创建时间,避免调用方遗漏赋值导致 AddTime 为零值
func (u *User) BeforeCreate(tx *gorm.DB) error {
if u.AddTime.IsZero() {
u.AddTime = time.Now()
}
return nil
}
// MarshalJSON 将 AddTime 以 Unix 时间戳的形式返回给前端
func (u User) MarshalJSON() ([]byte, error) {
type Alias User
return json.Marshal(&struct {
Time int64 `json:"time"`
Alias
}{
Time: u.AddTime.Unix() * 1000,
Alias: Alias(u),
})
}
声明响应Response的struct:
package controllers
type Response[T any] struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data T `json:"data"`
}
查询数据:
func (con UserController) List(ctx *gin.Context) {
// 查询数据
userList := []models.User{}
// 前三条
models.DB.Limit(3).Find(&userList)
// age 大于20
models.DB.Where("age >= ?", 20).Find(&userList)
// 第一条
models.DB.First(&userList)
ctx.JSON(200, &Response[*[]models.User]{
Code: 200,
Msg: "",
Data: &userList,
})
}
数据返回:
{
"code": 200,
"msg": "",
"data": [
{
"time": 1789785777000,
"id": 1,
"name": "ww",
"age": 33,
"email": "test1@gmail.com"
}
]
}
新增数据:
func (con UserController) Add(ctx *gin.Context) {
// 创建数据
user := models.User{
Username: "vv",
Age: 40,
Email: "test2@gmail.com",
}
models.DB.Create(&user)
ctx.JSON(200, &Response[string]{
Code: 200,
Msg: "",
Data: "ok",
})
}
数据返回:
{
"code": 200,
"msg": "",
"data": [
{
"time": 1789785777000,
"id": 1,
"name": "ww",
"age": 33,
"email": "test1@gmail.com"
},
{
"time": 1789789724000,
"id": 2,
"name": "vv",
"age": 40,
"email": "test2@gmail.com"
}
]
}
修改数据:
func (con UserController) Edit(ctx *gin.Context) {
// 修改数据
user := models.User{}
models.DB.Where("id = ?", 2).Find(&user)
user.Age = 8
models.DB.Save(&user)
ctx.JSON(200, &Response[string]{
Code: 200,
Msg: "",
Data: "ok",
})
}
删除数据:
func (con UserController) Delete(ctx *gin.Context) {
// 修改数据
user := models.User{}
models.DB.Where("id = ?", 2).Delete(&user)
ctx.JSON(200, &Response[string]{
Code: 200,
Msg: "",
Data: "ok",
})
}
where条件查询例子:
// ==
db.Where("name = ?", "jinzhu").First(&user)
// !=
db.Where("name <> ?", "jinzhu").Find(&users)
// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
原生语句:
// 增、删、改
db.Exec("DELETE from users WHERE id = ?",1)
// 查
db.Raw("SELECT * FROM users WHERE id = ?", 1).Scan(&result)
表的关联查询: 一对一
// User 有一张 CreditCard,UserID 是外键
type User struct {
CreditCard CreditCard
}
type CreditCard struct {
Number string
UserID uint
}
func GetAll(db *gorm.DB) ([]User, error) {
var users []User
db.Preload("CreditCard").Find(&users)
fmt.println(users)
}
一对多
// User 有多张 CreditCard,UserID 是外键
type User struct {
CreditCards []CreditCard
}
type CreditCard struct {
Number string
UserID uint
}
// 检索用户列表并预加载信用卡
func GetAll(db *gorm.DB) ([]User, error) {
var users []User
db.Preload("CreditCards").Find(&users)
fmt.println(users)
}
多对多
// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
Name string
}
// 检索 User 列表并预加载 Language
func GetAllUsers(db *gorm.DB) ([]User, error) {
var users []User
db.Preload("Languages").Find(&users)
fmt.println(users)
}
// 检索 Language 列表并预加载 User
func GetAllLanguages(db *gorm.DB) ([]Language, error) {
var languages []Language
db.Preload("Users").Find(&languages)
fmt.println(languages)
}