# fm **Repository Path**: xluomo945/fm ## Basic Information - **Project Name**: fm - **Description**: Gin二开, 对gin多封装一层web框架常用操作 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-02-23 - **Last Updated**: 2024-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: Go语言, Gin, Framework ## README # FM 此项目仅为Gin封装和自定义工具,并没有对Gin核心做出修改 ## 待办清单 - [x] 自定义日志 - [x] jwt鉴权 - [x] 文档生成 - [x] 配置文件 - [x] 路由注册 - [x] 参数绑定 - [ ] 响应封装 - [ ] 文件上传 ## 使用手册 ### 启动服务 创建App结构体,调用RunServer即可启动服务.App结构体存在很多配置属性 ``` func main() { app := &fm.App{} app.RunServer() } ``` ### 注册路由 在创建App结构体时,传递路由注册函数,在服务启动过程中加载完默认中间件 后会创建一个空路由组传递到路由注册函数. ``` main.go func main() { app := &fm.App{ AppConfig: AppConfig{ RegisterRoute: route.Register, }, } app.RunServer() } ``` ``` route.go import "gitee.com/xluomo945/fm/route" func Register(basic route.RouterHandler) error { // 创建路由分组 userGroup := basic.Group("user") orderGroup := basic.Group("order", middleware.Auth) // 注册路由 userServer := &server.UserServer{} route.GET(userGroup, "info", userServer.Info) orderServer := &server.OrderServer{} route.POST(orderGroup, "delete", orderServer.Delete) } ``` 在路由注册函数中传入的basic提供两个方法 1.`Use(...gin.HandlerFunc)`: 是与Gin相同的使用方法,对当前路由组增加使用中间件 2.`Group(string, ...gin.HandlerFunc)`: 创建一个新路由组,参数分别为路由组路径和路由组中间件 ### 参数绑定 路由注册函数进行封装后,不支持Gin原本的注册Handler, 在Handler中除上下文外,增加出入参数和error > func Handler(ctx *gin.Context, dto any) (any error) {} 样例: ``` type InfoRequest struct { Id string `json:"id"` } type InfoResponse struct { Name string `json:"name"` } func Register(basic route.RouterHandler) error { userGroup := basic.Group("user") route.GET(userGroup, "info", func(ctx *gin.Context, dto *InfoRequest) (*InfoResponse, error) { fmt.Println(dto.Id) return &InfoResponse{Name: "test"}, nil }) } ``` 样例中的注册方式,会调用Gin原本的ShouldBind()方法按照Tag进行绑定然后在传递到注册的handler中,响应值默认使用Json响应出去 ``` { "code": 1, "data": any } { "code": -1, "msg": err.Error() } ``` ### jwt鉴权 增加了jwt令牌生成与解密,以及助手函数,在注册时提供JwtConfig后可使用助手函数快速生成与解密令牌 ``` app := &App{ Middleware: Middleware{ JwtConfig: JwtConfig, }, } app.RunServer() ``` 其中JwtConfig需要实现setting.JwtConfig接口 * `GetSignKey`: 返回用以生成jwt令牌的签名key * `GetExpireTime`: 返回令牌的有效时长 * `GetToken`: 每次请求来到时,获取令牌返回出去 * `UnAuthorizedCode`: 当令牌校验失败时的异常code,此code会作为响应json的code值返回 * `UnAuthorizedMessage`: 当令牌校验失败时的异常信息,参数为校验err,返回的异常信息作为json的msg值返回 * `UnAuthorizedHttpCode`: 当令牌校验失败时响应的http code ``` type JwtSetting struct {} var JwtConfig = new(JwtSetting) func(j *JwtSetting) GetSignKey() string { return "jwt sign key" } func(j *JwtSetting) GetExpireTime() time.Duration { return 2*time.Hour } func(j *JwtSetting) GetToken(*gin.Context) string { return ctx.GetHeader("token") } func(j *JwtSetting) UnAuthorizedCode() int { return -1 } func(j *JwtSetting) UnAuthorizedMessage(error) string { return "令牌无效" } func(j *JwtSetting) UnAuthorizedHttpCode() int return { 503 } ``` 生成令牌, 直接使用快捷方法NewToken即可 ``` user := &UserModel{} token, err := jwt.NewToken(user.Id) token, err := jwt.NewToken(user) ``` 校验令牌, 响应值v即为生成时传入的data ``` v, e := jwt.ParseToken(token) ``` 除生成和校验外还提供了另外一组方法,用以在上下文中设置载荷内容 * GetPayload\[T\]()方法为泛型获取 ``` u := &User{ID:1} jwt.SetPayload(ctx, u) v, e := jwt.GetPayload[*User](ctx) fmt.Println(v.ID) // 1 ``` > 上述操作提供了用来验证令牌并设置载荷的中间件: middleware.Auth ### 配置文件 在创建App时,传入配置属性的相关配置即可开启配置文件,且在AppConfig中设置配置注册Handler > 目前只实现了读取yaml ``` app := &App{ AppConfig: AppConfig{ RegisterConfig: RegisterConfig }, ConfigurationConfig: setting.ConfigurationConfig{ Path: "config/config.yaml", }, } app.RunServer() ``` 根据在AppConfig中设置的注册函数,解析完配置之后会调用此方法将注册函数传入. 传入的注册函数会接收两个参数,第一个为配置名字,为yaml中的分组名, 第二个为解析到的结构体,按照名字从yaml中读取配置然后序列化到传入的结构体中 > type BindConfig func(name string, c any) error 示例: ```yaml app: mode: debug domain: https://123123.com ``` ``` type AppConfig struct { Mode string Domain string } var App = new(AppConfig) func RegisterConfig(config BindConfig) error { if err := config("app", &App); err != nil { return err } } ```