project exercise
工程实践
技术选型
基于生产级别的技术选型:
- Gin v1.9.1
- Go v1.20
- go-redis v9
- gorm v1.25.5
- Redis v7.2.0
- MySQL 8.2.0
- Goflow v0.1.4
创建工程
mkdir ContentSystemcd ContentSystemgo mod init ContentSystem
创建需要的目录
├── cmd
│ └── main.go
├── go.mod
├── internal
│ ├── cache
│ ├── config
│ ├── dao
│ ├── model
│ ├── services
│ └── utils
└── pkggin快速入门
安装
go get -u github.com/gin-gonic/gin简单代码
package cmd
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
err := r.Run()
if err != nil {
fmt.Printf("r run error = %v\n", err)
return
}
}路由模块
原先我们是直接卸载了main.go文件中,现在我们需要将路由进行剥离出去,在internal目录下新建api/routers.go
package api
import (
"content-system/internal/services"
"github.com/gin-gonic/gin"
)
// 路由都会有分组的概念,分组可以让我们更好的管理路由
const (
rootPath = "/api/" // 根路径
)
func CmsRouters(r *gin.Engine) {
root := r.Group(rootPath)
{
// /api/ping
root.GET("/ping", func (ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "pong",
})
})
}
}我们这样处理之后,还有点问题,函数的具体实现也在里面,到时候路由文件就会变得非常的大,所以也需要将对应的处理逻辑方法进行抽离
package api
import (
"content-system/internal/services"
"github.com/gin-gonic/gin"
)
// 路由都会有分组的概念,分组可以让我们更好的管理路由
const (
rootPath = "/api/" // 根路径
)
func CmsRouters(r *gin.Engine) {
cmsApp := services.NewCmsApp()
root := r.Group(rootPath)
{
// /api/ping
root.GET("/ping", cmsApp.Ping)
}
}新建internal/services/cms.go
package services
import "github.com/gin-gonic/gin"
type CmsApp struct{}
func NewCmsApp() *CmsApp {
return &CmsApp{}
}
func (c *CmsApp) Ping(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "pong",
})
}通过这样的方式进行将对应的逻辑进行抽离,可以更好的在各自的方法里去实现对应的功能,而不会显得臃肿.
中间件
Gin框架中,中间件是用于处理HTTP请求和响应的功能模块.中间件函数位于请求处理程序和路由之间,可以在请求被处理之前或之后执行一些额外的操作.
新建internal/api/middleware.go
package api
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
const SessionKey = "session_id"
type SessionAuth struct{}
func (s *SessionAuth) Auth(ctx *gin.Context) {
sessionId := ctx.GetHeader(SessionKey)
if sessionId == "" {
ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"message": "session is null",
})
}
fmt.Println("session id:", sessionId)
ctx.Next()
}在路由里进行注册
package api
import (
"content-system/internal/services"
"github.com/gin-gonic/gin"
)
// 路由都会有分组的概念,分组可以让我们更好的管理路由
const (
rootPath = "/api/" // 根路径
)
func CmsRouters(r *gin.Engine) {
cmsApp := services.NewCmsApp()
// 注册中间件
session := &SessionAuth{}
root := r.Group(rootPath).Use(session.Auth)
{
// /api/ping
root.GET("/ping", cmsApp.Ping)
}
}模型的绑定与验证
在gin中,模型绑定和验证是一种方便 HTTP 请求数据的处理和验证的功能
模型绑定指的是将请求中的数据自动绑定到Go的结构体,当收到一个包含表单数据,JSON数据或者查询字符串的http请求时,gin可以自动将这些数据解析并绑定到目标结构体中的字段.
package services
import (
"fmt"
"github.com/gin-gonic/gin"
)
type HelloReq struct {
Name string `json:"name" binding:"required"`
}
type HelloResp struct {
Message string `json:"message" binding:"required"`
}
func (c *CmsApp) Hello(ctx *gin.Context) {
var req HelloReq
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(400, gin.H{"error": err.Error()})
return
}
ctx.JSON(200, gin.H{
"code": 0,
"msg": "ok",
"data": &HelloResp{
Message: fmt.Sprintf("hello %s", req.Name),
},
})
}package api
import (
"content-system/internal/services"
"github.com/gin-gonic/gin"
)
// 路由都会有分组的概念,分组可以让我们更好的管理路由
const (
rootPath = "/api/" // 根路径
)
func CmsRouters(r *gin.Engine) {
cmsApp := services.NewCmsApp()
// 注册中间件
session := &SessionAuth{}
root := r.Group(rootPath).Use(session.Auth)
{
// /api/ping
root.GET("/ping", cmsApp.Ping)
root.GET("/hello", cmsApp.Hello)
}
}注册流程
graph TD
A[用户] --> B[server api]
B --> C[存储]
B --> D[密码加密]
D --> E[信息校验]
E --> F[mysql]database tool 的工程实践
新建script/user.sql
第一版本
create database `cms_account`;
use `cms_account`;
create table `account`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键 id',
`user_id` varchar(64) DEFAULT '' COMMENT '用户 id',
`nickname` varchar(64) DEFAULT '' COMMENT '昵称',
`password` varchar(100) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;到你的数据库里进行执行即可.