Go Web 实战编程-gin

我爱海鲸 2024-06-19 15:57:30 go语言学习

简介gin、gorm、restful、泛型的使用

0、参考文章:http://www.haijin.xyz/article/629

1、入门:

package main

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

func main() {
	r := gin.Default()
	r.GET("/hi", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "gin",
		})
		c.Header("site","haijin")
	})
	r.Run(":8068")
}

 

package main

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

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

	v1 := router.Group("/v1")
	{
		v1.POST("/login", login)
		v1.POST("/submit", submit)
		v1.POST("/read", read)
	}

	v2 := router.Group("/v2")
	{
		v2.POST("/login", login)
		v2.POST("/submit", submit)
		v2.POST("/read", read)
	}

	router.Run(":8080")
}

func login(c *gin.Context) {
}
func submit(c *gin.Context) {
}
func read(c *gin.Context) {
}

 

package main

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

type LoginForm struct {
	Username     string `form:"username" binding:"required"`
	Password string `form:"password" binding:"required"`
}

func main() {
	router := gin.Default()
	router.POST("/login", func(c *gin.Context) {
		var form LoginForm
		if c.ShouldBind(&form) == nil {
			if form.Username == "user" && form.Password == "password" {
				c.JSON(200, gin.H{"status": "you are logged in"})
			} else {
				c.JSON(401, gin.H{"status": "not authorized"})
			}
		}
	})
	router.Run(":8058")
}

 

2、gin-cookie:

package main

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

func main() {
	r := gin.Default()
	router := gin.Default()
	router.GET("/cookie", func(c *gin.Context) {
		// 设置cookie
		c.SetCookie("my_cookie", "cookievalue", 3600, "/", "localhost", false, true)
	})

	r.Run(":8068")
}

func Handler(c *gin.Context) {
	// 根据cookie名字读取cookie值
	data, err := c.Cookie("my_cookie")
	if err != nil {
		// 直接返回cookie值
		c.String(200,data)
		return
	}
	c.String(200,"not found!")
}

 

3、gin-file:

package main

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

func main() {
	r := gin.Default()
	r.GET("/hi", func(c *gin.Context) {
		//通过File函数,直接返回本地文件,参数为本地文件地址。
		//函数说明:c.File("文件路径")
		c.File("/var/www/gin/test.jpg")
	})

	r.Run(":8068")
}

 

4、gin-fileupload:

package main

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

func main() {
	router := gin.Default()
	// 设置文件上传大小限制,默认是32m
	router.MaxMultipartMemory = 64 << 20 // 64 MiB

	router.POST("/upload", func(c *gin.Context) {
		// 获取上传文件,返回的是multipart.FileHeader对象,
		// 代表一个文件,里面包含了文件名之类的详细信息
		// file是表单字段名字
		file, _ := c.FormFile("file")
		// 打印上传的文件名
		log.Println(file.Filename)

		// 将上传的文件,保存到./data/shirdon.jpg 文件中
		c.SaveUploadedFile(file, "./data/shirdon.jpg")

		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
	})
	router.Run(":8086")
}

 

upload.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Gin 上传文件示例</title>
</head>
<body>
<h1>上传文件示例</h1>
<form action="http://127.0.0.1:8086/upload" method="post" enctype="multipart/form-data">
    文件: <input type="file" name="file"><br><br>
    <input type="submit" value="上传">
</form>
</body>
</html>

 

5、gin-header:

 

package main

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

func main() {
	r := gin.Default()
	r.GET("/hi", func(c *gin.Context) {
		c.Header("Content-Type", "text/html; charset=utf-8")
		c.Header("site","shirdon")
	})

	r.Run(":8068")
}

 

6、gin-hello:

package main

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

func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()
	// GET:请求方式;/hello:请求的路径
	// 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数
	r.GET("/hello", func(c *gin.Context) {
		// c.JSON:返回JSON格式的数据
		c.JSON(200, gin.H{
			"message": "Hello world!",
		})
	})
	// 启动HTTP服务,默认在0.0.0.0:8080启动服务
	r.Run()
}

 

7、gin-middleware:

package main

// 导入gin包
import (
	"github.com/gin-gonic/gin"
	"log"
	"time"
)

// 自定义个日志中间件
func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		// 可以通过上下文对象,设置一些依附在上下文对象里面的键/值数据
		c.Set("example", "hi!这是一个中间件数据")
		// 在这里处理请求到达控制器函数之前的逻辑

		// 调用下一个中间件,或者控制器处理函数,具体得看注册了多少个中间件。
		c.Next()

		// 在这里可以处理请求返回给用户之前的逻辑
		latency := time.Since(t)
		log.Print(latency)

		// 例如,查询请求状态吗
		status := c.Writer.Status()
		log.Println(status)
	}
}

func main() {
	r := gin.New()
	// 注册上面自定义的日志中间件
	r.Use(Logger())

	r.GET("/hi", func(c *gin.Context) {
		// 查询我们之前在日志中间件,注入的键值数据
		example := c.MustGet("example").(string)

		// it would print: "hi!"
		log.Println(example)
	})

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

 

8、gin-redis:

package main

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/redis"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 初始化基于Redis的存储引擎
	// 参数说明:
	// 第1个参数 - Redis最大的空闲连接数
	// 第2个参数 - 数通信协议tcp或者udp
	// 第3个参数 - Redis地址, 格式,host:port
	// 第4个参数 - Redis密码
	// 第5个参数 - session加密密钥
	store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("passord"))
	r.Use(sessions.Sessions("mysession", store))

	r.GET("/incr", func(c *gin.Context) {
		session := sessions.Default(c)
		var count int
		v := session.Get("count")
		if v == nil {
			count = 0
		} else {
			count = v.(int)
			count++
		}
		session.Set("count", count)
		session.Save()
		c.JSON(200, gin.H{"count": count})
	})
	r.Run(":8000")
}

 

9、gin-router:

package main

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

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

	// 创建v1组
	v1 := router.Group("/v1")
	{
		v1.POST("/login", login)
	}
	// 创建v2组
	v2 := router.Group("/v2")
	{
		v2.POST("/login", login)
	}
	router.Run(":8080")
}

 

10、gin-session:

package main

import (
	// 导入session包
	"github.com/gin-contrib/sessions"
	// 导入session存储引擎
	"github.com/gin-contrib/sessions/cookie"
	// 导入gin框架包
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 创建基于cookie的存储引擎,password123456参数是用于加密的密钥
	store := cookie.NewStore([]byte("password123456"))
	// 设置session中间件,参数mysession,指的是session的名字,也是cookie的名字
	// store是前面创建的存储引擎,我们可以替换成其他存储引擎
	r.Use(sessions.Sessions("mysession", store))

	r.GET("/hello", func(c *gin.Context) {
		// 初始化session对象
		session := sessions.Default(c)

		// 通过session.Get读取session值
		// session是键值对格式数据,因此需要通过key查询数据
		if session.Get("hello") != "world" {
			// 设置session数据
			session.Set("hello", "world")
			// 删除session数据
			session.Delete("shirdon")
			// 保存session数据
			session.Save()
			// 删除整个session
			// session.Clear()
		}

		c.JSON(200, gin.H{"hello": session.Get("hello")})
	})
	r.Run(":8000")
}

func Handler(c *gin.Context) {
	// 根据cookie名字读取cookie值
	data, err := c.Cookie("my_cookie")
	if err != nil {
		// 直接返回cookie值
		c.String(200, data)
		return
	}
	c.String(200, "not found!")
}

 

11、gin-static:

package main

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

func main() {
	router := gin.Default()
	router.Static("/assets", "/var/www/gin/assets")
	router.StaticFile("/favicon.ico", "./static/favicon.ico")

	// 启动服务
	router.Run(":8080")
}

2024-06-18 start

13、gorm&restful:

package main

import (
	"crypto/md5"
	"encoding/hex"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	"net/http"
)

var (
	db *gorm.DB
	sqlConnection = "root:a123456@tcp(127.0.0.1:3306)/chapter8?" +
		"charset=utf8&parseTime=true"
)

//初始化
func init() {
	//打开数据库连接
	var err error
	db, err = gorm.Open("mysql", sqlConnection)
	if err != nil {
		panic("failed to connect database")
	}

	db.AutoMigrate(&User{})
}

func main() {
	router := gin.Default()
	v2 := router.Group("/api/v2/user")
	{
		v2.POST("/", createUser)      //POST方法,创建新用户
		v2.GET("/", fetchAllUser)     //GET方法,获取所有用户
		v2.GET("/:id", fetchUser)     //GET方法,获取某一个用户,形如:/api/v2/user/1
		v2.PUT("/:id", updateUser)    //PUT方法,更新用户,形如:/api/v2/user/1
		v2.DELETE("/:id", deleteUser) //DELETE方法,删除用户,形如:/api/v2/user/1
	}
	router.Run("127.0.0.1:8086")
}

type (
	// 数据表结构体类
	User struct {
		ID       uint   `json:"id"`
		Phone    string `json:"phone"`
		Name     string `json:"name"`
		Password string `json:"password"`
	}

	//响应返回的结构体
	UserRes struct {
		ID    uint   `json:"id"`
		Phone string `json:"phone"`
		Name  string `json:"name"`
	}
)

//md5加密
func md5Password(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

// 创建新用户
func createUser(c *gin.Context) {
	phone := c.PostForm("phone") //获取POST请求参数phone
	name := c.PostForm("name")   //获取POST请求参数name
	user := User{
		Phone:    phone,
		Name:     name,
		Password: md5Password("666666"), //用户密码
	}
	db.Save(&user) //保存到数据库
	c.JSON(
		http.StatusCreated,
		gin.H{
			"status":  http.StatusCreated,
			"message": "User created successfully!",
			"ID":      user.ID,
		})         //返回状态到客户端
}

// 获取所有用户
func fetchAllUser(c *gin.Context) {
	var user []User        //定义一个数组去数据库总获取数据
	var _userRes []UserRes //定义一个响应数组用户返回数据到客户端

	db.Find(&user)

	if len(user) <= 0 {
		c.JSON(
			http.StatusNotFound,
			gin.H{
				"status":  http.StatusNotFound,
				"message": "No user found!",
			})
		return
	}

	//循环遍历,追加到响应数组
	for _, item := range user {
		_userRes = append(_userRes,
			UserRes{
				ID:    item.ID,
				Phone: item.Phone,
				Name:  item.Name,
			})
	}
	c.JSON(http.StatusOK,
		gin.H{"status":
		http.StatusOK,
			"data": _userRes,
		}) //返回状态到客户端
}

// 获取单个用户
func fetchUser(c *gin.Context) {
	var user User       //定义User结构体
	ID := c.Param("id") //获取参数id

	db.First(&user, ID)

	if user.ID == 0 { //如果用户不存在,则返回
		c.JSON(http.StatusNotFound,
			gin.H{"status": http.StatusNotFound, "message": "No user found!"})
		return
	}

	//返回响应结构体
	res := UserRes{ID: user.ID, Phone: user.Phone, Name: user.Name}
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": res})
}

//更新用户
func updateUser(c *gin.Context) {
	var user User           //定义User结构体
	userID := c.Param("id") //获取参数id
	db.First(&user, userID) //查找数据库

	if user.ID == 0 { //如果数据库不存在,则返回
		c.JSON(http.StatusNotFound,
			gin.H{"status": http.StatusNotFound, "message": "No user found!"})
		return
	}

	//更新对应的字段值
	db.Model(&user).Update("phone", c.PostForm("phone"))
	db.Model(&user).Update("name", c.PostForm("name"))
	c.JSON(http.StatusOK,
		gin.H{"status": http.StatusOK, "message": "Updated User successfully!"})
}

// 删除用户
func deleteUser(c *gin.Context) {
	var user User           //定义User结构体
	userID := c.Param("id") //获取参数id

	db.First(&user, userID) //查找数据库

	if user.ID == 0 { //如果数据库不存在,则返回
		c.JSON(http.StatusNotFound,
			gin.H{"status": http.StatusNotFound, "message": "No user found!"})
		return
	}

	//删除用户
	db.Delete(&user)
	c.JSON(http.StatusOK,
		gin.H{"status": http.StatusOK, "message": "User deleted successfully!"})
}

实现 Tabler 接口:在结构体中定义一个名为 TableName 的无参数函数,返回表名字符串。

func (Video) TableName() string {
    return "spider_video"
}

end

2024-06-19 start:

使用泛型和包装器进行数据对象的转换:

package main

import (
	"time"
)

// 定义一个泛型转换函数
func Convert[T, U any](items []T, converter func(T) U) []U {
	result := make([]U, len(items))
	for i, item := range items {
		result[i] = converter(item)
	}
	return result
}

type Video struct {
	ID            int        `json:"id"`
	VideoName     string     `json:"video_name"`
	VideoIcon     string     `json:"video_icon"`
	VideoSearchID int        `json:"video_search_id"`
	CreateTime    *time.Time `json:"create_time"`
	UpdateTime    *time.Time `json:"update_time"`
	DetailURL     string     `json:"-"`
}

func (Video) TableName() string {
	return "spider_video"
}

// VideoRes 响应返回的结构体
type VideoRes struct {
	ID        int    `json:"id"`
	VideoName string `json:"video_name"`
	VideoIcon string `json:"video_icon"`
}

// 定义一个转换单个Video到VideoRes的函数
func convertVideoToVideoRes(video Video) VideoRes {
	return VideoRes{
		ID:        video.ID,
		VideoName: video.VideoName,
		VideoIcon: video.VideoIcon,
	}
}

func main() {
	// 示例:创建Video对象数组
	videos := []Video{
		{ID: 1, VideoName: "Video 1", VideoIcon: "/path/to/icon1.png"},
		{ID: 2, VideoName: "Video 2", VideoIcon: "/path/to/icon2.png"},
	}

	// 使用泛型Convert函数转换Video数组到VideoRes数组
	videoResList := Convert(videos, convertVideoToVideoRes)

	// 打印转换后的结果,此处省略打印代码
	// ...
}

end

你好:我的2025