风离不摆烂学习日志 Day5 — Go Web项目 接口开发全流程

接上篇地址 Web项目学习之项目结构
routes包分析
InitRoutes
package routes
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"go-web-mini/common"
	"go-web-mini/config"
	"go-web-mini/middleware"
	"time"
)
// 初始化
func InitRoutes() *gin.Engine {
	//设置模式
	gin.SetMode(config.Conf.System.Mode)
	// 创建带有默认中间件的路由:
	// 日志与恢复中间件
	r := gin.Default()
	// 创建不带中间件的路由:
	// r := gin.New()
	// r.Use(gin.Recovery())
	// 启用限流中间件
	// 默认每50毫秒填充一个令牌,最多填充200个
	fillInterval := time.Duration(config.Conf.RateLimit.FillInterval)
	capacity := config.Conf.RateLimit.Capacity
	r.Use(middleware.RateLimitMiddleware(time.Millisecond*fillInterval, capacity))
	// 启用全局跨域中间件
	r.Use(middleware.CORSMiddleware())
	// 启用操作日志中间件
	r.Use(middleware.OperationLogMiddleware())
	// 初始化JWT认证中间件
	authMiddleware, err := middleware.InitAuth()
	if err != nil {
		common.Log.Panicf("初始化JWT中间件失败:%v", err)
		panic(fmt.Sprintf("初始化JWT中间件失败:%v", err))
	}
	// 路由分组
	apiGroup := r.Group("/" + config.Conf.System.UrlPathPrefix)
	// 注册路由
	InitBaseRoutes(apiGroup, authMiddleware)         // 注册基础路由, 不需要jwt认证中间件,不需要casbin中间件
	InitUserRoutes(apiGroup, authMiddleware)         // 注册用户路由, jwt认证中间件,casbin鉴权中间件
	InitRoleRoutes(apiGroup, authMiddleware)         // 注册角色路由, jwt认证中间件,casbin鉴权中间件
	InitMenuRoutes(apiGroup, authMiddleware)         // 注册菜单路由, jwt认证中间件,casbin鉴权中间件
	InitApiRoutes(apiGroup, authMiddleware)          // 注册接口路由, jwt认证中间件,casbin鉴权中间件
	InitOperationLogRoutes(apiGroup, authMiddleware) // 注册操作日志路由, jwt认证中间件,casbin鉴权中间件
	common.Log.Info("初始化路由完成!")
	return r
}
设置开发模式(debug/release/test,正式版改为release) => 加载中间件 => 注册路由
base_routes.go
package routes
import (
	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"
)
// 注册基础路由
func InitBaseRoutes(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) gin.IRoutes {
	router := r.Group("/base")
	{
		// 登录登出刷新token无需鉴权
		router.POST("/login", authMiddleware.LoginHandler)
		router.POST("/logout", authMiddleware.LogoutHandler)
		router.POST("/refreshToken", authMiddleware.RefreshHandler)
	}
	return r
}
menu_routes.go
package routes
import (
	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"
	"go-web-mini/controller"
	"go-web-mini/middleware"
)
func InitMenuRoutes(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) gin.IRoutes {
	menuController := controller.NewMenuController()
	router := r.Group("/menu")
	// 开启jwt认证中间件
	router.Use(authMiddleware.MiddlewareFunc())
	// 开启casbin鉴权中间件
	router.Use(middleware.CasbinMiddleware())
	{
		router.GET("/tree", menuController.GetMenuTree)
		router.GET("/list", menuController.GetMenus)
		router.POST("/create", menuController.CreateMenu)
		router.PATCH("/update/:menuId", menuController.UpdateMenuById)
		router.DELETE("/delete/batch", menuController.BatchDeleteMenuByIds)
		router.GET("/access/list/:userId", menuController.GetUserMenusByUserId)
		router.GET("/access/tree/:userId", menuController.GetUserMenuTreeByUserId)
	}
	return r
}
函数格式:
 1. func 函数名(入参1 参数类型,入参2 参数类型) 返回类型
2. func 函数名(入参1 参数类型,入参2 参数类型)(返回值1 返回类型) 
controller包分析
user_controller.go
大致流程:
定义接口
定义结构体 结构体里包含持久层的CRUD
然后实现这些接口 返回出去
对比Java 的 SpringBoot框架 Gin 没有自动注入 我们需要自己写构造函数 来初始化持久层 Controller层type UserController struct { UserRepository repository.IUserRepository } // 构造函数 func NewUserController() IUserController { userRepository := repository.NewUserRepository() userController := UserController{UserRepository: userRepository} return userController }
然后上层调用这个构造函数来完成初始化
repository包分析
大体流程与controller层逻辑一致
type UserRepository struct { //结构体为空 }
内存缓存go-cache用户信息缓存 避免频繁读取数据库
地址:
https://github.com/patrickmn/go-cache
一个基于内存的key-value存储/缓存项目,类似于Memcached,并且可选择定期的垃圾回收,适合单机程序。代码量不多,也不难懂。"github.com/patrickmn/go-cache" // 当前用户信息缓存,避免频繁获取数据库 这里逻辑跟Redis差不多 增 删 改 时更新缓存 查优先走缓存 var userInfoCache = cache.New(24*time.Hour, 48*time.Hour)
model包分析
package model
import "gorm.io/gorm"
type User struct {
	gorm.Model
	Username     string  `gorm:"type:varchar(20);not null;unique" json:"username"`
	Password     string  `gorm:"size:255;not null" json:"password"`
	Mobile       string  `gorm:"type:varchar(11);not null;unique" json:"mobile"`
	Avatar       string  `gorm:"type:varchar(255)" json:"avatar"`
	Nickname     string  `gorm:"type:varchar(20)" json:"nickname"`
	Introduction *string `gorm:"type:varchar(255)" json:"introduction"`
	Status       uint    `gorm:"type:tinyint(1);default:1;comment:'1正常, 2禁用'" json:"status"`
	Creator      string  `gorm:"type:varchar(20);" json:"creator"`
	Roles        []*Role `gorm:"many2many:user_roles" json:"roles"`
}
这里结构体 类似于Java中对象
需要首字母大写 指定 转 json 后的类型 对应长字段 类型存储为 指针 即取地址
dto包分析
user_dto.go
package dto
import "go-web-mini/model"
// 返回给前端的当前用户信息
type UserInfoDto struct {
	ID           uint          `json:"id"`
	Username     string        `json:"username"`
	Mobile       string        `json:"mobile"`
	Avatar       string        `json:"avatar"`
	Nickname     string        `json:"nickname"`
	Introduction string        `json:"introduction"`
	Roles        []*model.Role `json:"roles"`
}
func ToUserInfoDto(user model.User) UserInfoDto {
	return UserInfoDto{
		ID:           user.ID,
		Username:     user.Username,
		Mobile:       user.Mobile,
		Avatar:       user.Avatar,
		Nickname:     user.Nickname,
		Introduction: *user.Introduction,
		Roles:        user.Roles,
	}
}
// 返回给前端的用户列表
type UsersDto struct {
	ID           uint   `json:"ID"`
	Username     string `json:"username"`
	Mobile       string `json:"mobile"`
	Avatar       string `json:"avatar"`
	Nickname     string `json:"nickname"`
	Introduction string `json:"introduction"`
	Status       uint   `json:"status"`
	Creator      string `json:"creator"`
	RoleIds      []uint `json:"roleIds"`
}
func ToUsersDto(userList []*model.User) []UsersDto {
	var users []UsersDto
	for _, user := range userList {
		userDto := UsersDto{
			ID:           user.ID,
			Username:     user.Username,
			Mobile:       user.Mobile,
			Avatar:       user.Avatar,
			Nickname:     user.Nickname,
			Introduction: *user.Introduction,
			Status:       user.Status,
			Creator:      user.Creator,
		}
		roleIds := make([]uint, 0)
		for _, role := range user.Roles {
			roleIds = append(roleIds, role.ID)
		}
		userDto.RoleIds = roleIds
		users = append(users, userDto)
	}
	return users
}
当我们不需要将数据库的数据全部返回出去的时候 或者需要做字段转换 拼接 等操作 皆可在dto层完成
response包分析
封装统一返回格式
package response import ( "github.com/gin-gonic/gin" "net/http" ) // 返回前端 func Response(c *gin.Context, httpStatus int, code int, data gin.H, message string) { c.JSON(httpStatus, gin.H{"code": code, "data": data, "message": message}) } // 返回前端-成功 func Success(c *gin.Context, data gin.H, message string) { Response(c, http.StatusOK, 200, data, message) } // 返回前端-失败 func Fail(c *gin.Context, data gin.H, message string) { Response(c, http.StatusBadRequest, 400, data, message) }
config 包分析
这里结构体对应 config.yml 配置文件中对应的配置
type MysqlConfig struct { //mysql配置
	Username    string `mapstructure:"username" json:"username"`
	Password    string `mapstructure:"password" json:"password"`
	Database    string `mapstructure:"database" json:"database"`
	Host        string `mapstructure:"host" json:"host"`
	Port        int    `mapstructure:"port" json:"port"`
	Query       string `mapstructure:"query" json:"query"`
	LogMode     bool   `mapstructure:"log-mode" json:"logMode"`
	TablePrefix string `mapstructure:"table-prefix" json:"tablePrefix"`
	Charset     string `mapstructure:"charset" json:"charset"`
	Collation   string `mapstructure:"collation" json:"collation"`
}
在一个结构体里包含 各个配置的集合 mysql jwt...
type config struct {
	System    *SystemConfig    `mapstructure:"system" json:"system"`
	Logs      *LogsConfig      `mapstructure:"logs" json:"logs"`
	Mysql     *MysqlConfig     `mapstructure:"mysql" json:"mysql"`
	Casbin    *CasbinConfig    `mapstructure:"casbin" json:"casbin"`
	Jwt       *JwtConfig       `mapstructure:"jwt" json:"jwt"`
	RateLimit *RateLimitConfig `mapstructure:"rate-limit" json:"rateLimit"`
}








![[附源码]java毕业设计养老院管理系统](https://img-blog.csdnimg.cn/b69d6fffdcd5404ab81c3ef14f73c569.png)











