Bootstrap

go+gin+mysql+gorm快速实现增删改查接口

Gin 是一个用 Go (Golang) 编写的轻量级但功能强大的Web框架,具有极高的性能。适合开发API和微服务。

1.安装 Gin

前置任务,首先你本地需要安装过go语言环境

go get -u github.com/gin-gonic/gin

这里直接结合项目代码解析gin的主要功能:

package router

import (
	"time"
	"todolist/controller"
	"todolist/logger"

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

// SetupRouter 设置路由
func SetupRouter() *gin.Engine {
	r := gin.New()
	r.Use(logger.GinLogger(), logger.GinRecovery(true))
	r.GET("/", func(c *gin.Context) {
		controller.ResponseSuccess(c, gin.H{
			"time": time.Now(),
		})
	})
	v1 := r.Group("/api/v1")
	v1.GET("/captcha", controller.CaptchaHandler)              // 获取邮箱验证码   用于注册
	v1.GET("/captcha/pic", controller.CaptchaPicHandler)       // 获取图片验证码   用于登录
	v1.POST("/captcha/pic", controller.CheckCaptchaPicHandler) // 获取图片验证码校验   用于登录
	v1.POST("/signup", controller.SignUpHadnler)               // 注册
	v1.POST("/login", controller.LoginHandler)                 // 登录
	v1.GET("/accesstoken", controller.AccessTokenHandler)      // 刷新accesstoken
	//v1.Use(middlewares.JWTAuthMiddleware())//中间件

	//RESTful风格的优势在于其简洁性和可扩展性。通过使用标准的HTTP方法,RESTful风格使得接口的设计更加清晰,易于理解和维护。
	{
		v1.POST("/task", controller.AddTaskHanler)          // 增加task
		v1.GET("/tasks", controller.GetTestByUseridHandler) // 获取tasks
		v1.DELETE("/tasks", controller.DeleteTaskHandler)   // 删除tasks
		v1.PUT("/tasks", controller.UptateTaskHandler)      // 更新tasks
	}
	{
		v1.POST("/test", controller.AddTestHanler)         // 增加test
		v1.GET("/test", controller.GetTestByUseridHandler) // 根据userid获取test对象
		v1.GET("/testList", controller.GetTestListHandler) // 获取test列表
		v1.PUT("/test", controller.UptateTestHandler)      // 更新test
		v1.DELETE("/test", controller.DeleteTestHandler)   // 批量删除test
	}
	return r
}

gin.Engine 结构体

初始引擎:
返回一个新的空白的,没有任何中间件的引擎实例
在这里插入图片描述

路由与路由组:

Gin 提供了灵活的路由管理功能,你可以通过 GET、POST、PUT、DELETE 等方法定义路由。路由组可以将相关的路由组织在一起,方便管理。

在这里插入图片描述

这里设置路由组:
在这里插入图片描述

中间件:

Gin 提供了轻量级的中间件支持,可以实现如身份验证、日志等功能。
定义中间件:

package middlewares

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"strings"
	"todolist/controller"
	"todolist/controller/code"
	"todolist/utils"
)

func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		// 从请求体里面获取token
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			zap.L().Warn("Error Authorization")
			controller.ResponseError(c, code.CodeNeedLogin)
			c.Abort()
			return
		}
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 && parts[0] != "Bearer" {
			zap.L().Warn("Error Authorization")
			controller.ResponseError(c, code.CodeInvalidToken)
			c.Abort()
			return
		}
		claims, err := utils.ParseAccessToken(parts[1])
		if err != nil {
			zap.L().Warn("Error Authorization")
			controller.ResponseError(c, code.CodeInvalidToken)
			c.Abort()
			return
		}
		userId, email := claims.UserId, claims.Email
		// 将当前请求的用户信息保存到请求的上下文c上
		c.Set(controller.CtxUserIDKey, userId)
		c.Set(controller.CtxUserEmail, email)
	}
}

使用中间件:

在这里插入图片描述

gin.context:

gin.Context 上下文对象,可以方便地处理 HTTP 请求和响应的各种细节。

package controller

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"todolist/controller/code"
	"todolist/dao/dmysql"
	"todolist/logic"
	"todolist/models"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
)

// GetTestByUseridHandler 查询
func GetTestByUseridHandler(c *gin.Context) {
	ids := c.Query("id")

	fmt.Println("=======" + ids)

	intNum, _ := strconv.Atoi(ids) //字符串转int
	var uid uint = uint(intNum)    // int转uint显式转换

	tasks, err := dmysql.QueryTasksIdByUid(uid)
	if err != nil {
		zap.L().Error("Error GetTasks about logic", zap.Error(err))
		ResponseError(c, code.CodeServerBusy)
		return
	}

	tasks[0].TaskContent = "测试内容" //修改返回值

	b, _ := json.Marshal(tasks) //结构体转json
	s3 := string(b)
	fmt.Println("tasks=======" + s3) //json转字符串

	data := map[string]interface{}{
		"user_id": uid,
		"tasks":   tasks,
	}
	jsonBytes, _ := json.Marshal(data)
	m := string(jsonBytes)
	fmt.Println("data=======" + m) //map转字符串
	ResponseSuccess(c, data)
	return
}

// GetTestListHandler 查询列表
func GetTestListHandler(c *gin.Context) {
	ids := c.Query("id")
	fmt.Println("=======" + ids)
	arr := strings.Split(ids, ",") //字符串转数组

	tasks, err := dmysql.QueryTasksIdByTid(arr)
	if err != nil {
		zap.L().Error("Error GetTasks about logic", zap.Error(err))
		ResponseError(c, code.CodeServerBusy)
		return
	}

	ResponseSuccess(c, tasks)
	return
}

// AddTestHanler 新增
func AddTestHanler(c *gin.Context) {

	var uid uint = 1                            //创建人
	p := new(models.ParamTask)                  //new一个空的结构体
	if err := c.ShouldBindJSON(p); err != nil { //使用 ShouldBindJSON() 或 BindJSON() 解析 JSON 数据并绑定到结构体
		zap.L().Error("GetTask with invalid param:ParamDate", zap.Error(err))
		if errs, ok := err.(validator.ValidationErrors); ok {
			ResponseErrorWithMsg(c, code.CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
			return
		}
		ResponseError(c, code.CodeServerBusy)
		return
	}
	logic.AddTask(uid, p)

	ResponseSuccess(c, nil)
	return
}

// UptateTestHandler 更新
func UptateTestHandler(c *gin.Context) {

	var uid uint = 1 //修改人
	p := new(models.ParamTask)

	if err := c.ShouldBindJSON(p); err != nil { //使用 ShouldBindJSON() 或 BindJSON() 解析 JSON 数据并绑定到结构体
		zap.L().Error("GetTask with invalid param:ParamTask", zap.Error(err))
		if errs, ok := err.(validator.ValidationErrors); ok {
			ResponseErrorWithMsg(c, code.CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
			return
		}
		ResponseError(c, code.CodeServerBusy)
		return
	}

	logic.UpdateTask(uid, p)

	ResponseSuccess(c, nil)
	return
}

// DeleteTestHandler 批量删除test
func DeleteTestHandler(c *gin.Context) {
	var uid uint = 1 //修改人

	// 2. 校验参数
	p := new(models.ParamTaskIDs)

	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("DeleteTasks with invalid param:ParamTaskIDs", zap.Error(err))
		if errs, ok := err.(validator.ValidationErrors); ok {
			ResponseErrorWithMsg(c, code.CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
			return
		}
		ResponseError(c, code.CodeServerBusy)
		return
	}
	fmt.Println(p.TaskIDs) //获取id
	logic.DelTasks(uid, p)
	fmt.Println("-----------")
	ResponseSuccess(c, nil)
	return
}

Query方法:

用于获取 URL 中的查询参数。例如,对于请求http://127.0.0.1:8080/api/v1/test?id=1,可以使用以下方式获取参数:
在这里插入图片描述

在这里插入图片描述

ShouldBindJSON方法:

用于绑定 JSON 格式的请求体数据到一个结构体。
在这里插入图片描述

在这里插入图片描述

JSON方法:

用于返回一个 JSON 格式的响应。例如:
在这里插入图片描述

func ResponseSuccess(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, &ResponseData{
		Code: code.CodeSuccess,
		Msg:  code.CodeSuccess.Msg(),
		Data: data,
	})
}

2.Gorm

Go Gorm 是一个非常强大的 Go 语言的 ORM(对象关系映射)库,它可以让开发者更加方便地在 Go 应用程序中操作数据库

安装Gorm :

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

配置连接mysql数据库

package dmysql

import (
	"fmt"
	"time"
	"todolist/models"
	"todolist/setting"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var db *gorm.DB

func InitClient(mcg *setting.MysqlConfig) (err error) {
	//var dsn = "root:root@tcp(127.0.0.1:3306)/todolist?charset=utf8mb4&parseTime=True&loc=Local"
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", mcg.User, mcg.Password, mcg.Host, mcg.Port, mcg.Db)
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		// 设置日志模式为Info,将会打印出所有SQL语句
		Logger: logger.Default.LogMode(logger.Info),
	})
	if err != nil {
		return err
	}
	sqlDB, _ := db.DB()
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)
	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(100)
	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)
	//automigrate是gorm库中一个非常重要的功能,它可以自动创建数据库表和对应的字段,无需手动编写SQL语句。
	err = db.AutoMigrate(&models.User{}, &models.Task{})
	if err != nil {
		return err
	}
	return
}

主要功能使用方法

package dmysql

import (
	"fmt"
	"todolist/models"
	"todolist/utils"
)

// AddTask 增加task
func AddTask(task *models.Task) (*models.Task, error) {
	// 1. 生成id
	tid := utils.GenID()
	// 2. 创建
	task = &models.Task{Tid: tid, Level: task.Level, State: 0, UserID: task.UserID, TaskContent: task.TaskContent}
	err := db.Create(task).Error
	if err != nil {
		return nil, err
	}
	return task, nil
}

// QueryTasksByUidAndDate 通过的uid和日期查询
func QueryTasksByUidAndDate(uid uint, date *models.ParamDate) (tasks []models.Task, err error) {
	// 1. 解析日期
	startDate := date.StartDate
	endDate := date.EndDate
	// 2. 查询数据库
	err = db.Select("tid", "level", "state", "user_id", "task_content", "created_at").Where("user_id = ? and created_at >= ?  and  created_at < ?", uid, startDate, endDate).Find(&tasks).Error
	return
}

func DelTasks(taskIDs []int64) (err error) {
	fmt.Println("-------删除数据库-----")
	fmt.Println(taskIDs)
	err = db.Where("tid in ?", taskIDs).Delete(&models.Task{}).Error
	fmt.Println(err)
	fmt.Println("-------删除数据库结束-----")
	return
}

// QueryTasksIdByUid 根据用户id 查询tids
func QueryTasksIdByUid(uid uint) (tids []models.Task, err error) {
	err = db.Model(&models.Task{}).Debug().Select("tid", "created_at").Where("user_id = ?", uid).Find(&tids).Error
	return
}

// QueryTasksIdByTid 根据tid 返回详细task
func QueryTasksIdByTid(tids []string) (task []models.Task, err error) {
	err = db.Debug().Where("tid in ?", tids).Find(&task).Error
	return
}

func UpdateTask(tid int64, task map[string]interface{}) (err error) {
	err = db.Debug().Model(&models.Task{}).Where("tid = ?", tid).Updates(task).Error
	return
}

3.demo项目地址:

https://github.com/nanist/golang

基于go+gin+redis+mysql+gorm实现的todo-list项目,适合go新手小白入门项目 功能:登录注册,日志,token验证,redis缓存,RefreshToken,todo-list的增删改查,邮件发送,图形验证码。

;