1 启动gin http server

func NewServer(ip string, port int, fs …func(r *gin.Engine)) *GinServer
@param ip string IP地址
@param port int 监听端口
@param fs …func(r *gin.Engine) 处理函数
@return *bzgin.GinServer 结构体,主要用于调用Start()启动服务

// 方式1
server := bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.GET("", func(c *gin.Context) {
		c.String(200, "hello")
	})
})
server.Start()

// 方式2
server := bzgin.NewServer("127.0.0.1", 8080)
server.GET("", func(c *gin.Context) {
	c.String(200, "hello")
})
server.Start()
# curl http://127.0.0.1:8080
hello

2 获取http上下文的数据

func CtxGet[T any](ctx *gin.Context, key string) (T, bool)
@param ctx *gin.Context 传入上下文
@param key string 数据键名
@return T 泛型数据,获得泛型转化后的数据
@return bool 是否获得数据 或 是否转换泛型成功

bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.GET("", func(c *gin.Context) {
		c.Set("float", 3.1415926)
		c.Set("int", 2)
		c.Set("string", "hello")

		f, ok := bzgin.CtxGet[float64](c, "float")
		fmt.Println(f, ok)

		i, ok := bzgin.CtxGet[int](c, "int")
		fmt.Println(i, ok)

		s, ok := bzgin.CtxGet[string](c, "string")
		fmt.Println(s, ok)
	})
}).Start()
3.1415926 true
2 true
hello true

3 跨域

func Cors(urls …string) gin.HandlerFunc
@param urls 允许跨域的域名,为空则默认使用通配符*
@return gin.HandlerFunc gin中间件类型

bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.Use(bzgin.Cors()) // 默认*

	r.Use(bzgin.Cors("http://xxx.com")) // Header Origin(来源链接)
}).Start()

4 下载文件流

func FileStream(ctx *gin.Context, file string)
@param ctx *gin.Context gin http上下文
@paam file string 文件

func FileDataStream(ctx *gin.Context, file string) error
@param ctx *gin.Context gin http上下文
@paam file string 文件
@return error 错误信息

// 两种方式结果一样, 依赖gin处理更安全,os处理更少调用性能更好
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.GET("fileStream", func(c *gin.Context) {
		bzgin.FileStream(c, "./test.txt") // 依赖gin处理文件流
	})

	r.GET("fileDataStream", func(c *gin.Context) {
		bzgin.FileDataStream(c, "./test.txt") // os处理文件流
	})
}).Start()

5 配置默认日志输出文件

func DefaultLog(file string) error
@param file string 文件
@return error 错误信息

bzgin.DefaultLog("./test.log")
bzgin.NewServer("127.0.0.1", 8080).Start()

6 访问日志中间件

func AccessLogHandler(f func(log *ResponseLog)) gin.HandlerFunc
@param f func(log *ResponseLog) 访问日志数据接收方法
@return gin.HandlerFunc gin中间件类型

bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.Use(bzgin.AccessLogHandler(func(log *bzgin.ResponseLog) {
		fmt.Println(log)
	}))
}).Start()

7 捕获http全局错误

func Recover(isPrintStack, isOutStackErr bool, f func(c *gin.Context, err error)) gin.HandlerFunc
@param isPrintStack bool 是否打印堆栈错误
@param isOutStackErr bool 是否向输出函数输出堆栈错误
@param f func(c *gin.Context, err error) 输出函数
@return gin.HandlerFunc gin中间件类型

bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.Use(bzgin.Recover(false, false,
		func(c *gin.Context, err error) {
			c.String(500, err.Error())
		},
	))

	r.GET("", func(c *gin.Context) {
		panic("panic")
	})
}).Start()
# curl http://127.0.0.1:8080
server internal error

8 http响应

Response数据
type Response struct {
  Code int json:"code" // 业务状态码,包含:200、400、500
  Message string json:"message" // 业务信息
  ReasonCode string json:"reasonCode" // 服务状态码,包含 SUCCESS、BAD_REQUEST、SERVER_ERROR
  Reason string json:"reason" // 服务信息
  Data any json:"data" // 业务数据
}

成功响应
func SuccessResponse(c *gin.Context, data any, message …string)
@param ctx *gin.Context gin http上下文
@param data any 业务数据
@message …string 业务信息,不必要字段

请求错误响应
func BadRequestResponse(c *gin.Context, message string, reason …string)
@param ctx *gin.Context gin http上下文
@message string 业务信息
@reason …string 服务信息,不必要字段

服务错误响应
func ErrorResponse(c *gin.Context, message string, reason …string)
@param ctx *gin.Context gin http上下文
@message string 业务信息
@reason …string 服务信息,不必要字段

bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {

	r.GET("bad", func(c *gin.Context) {
		if c.Query("auth") != "b" {
			// 400错误
			bzgin.BadRequestResponse(c, "权限验证失败")
			return
		}

		// 200成功
		bzgin.SuccessResponse(c, struct{ name string }{name: "breeze"})
	})

	r.GET("err", func(c *gin.Context) {
		// 500错误
		bzgin.ErrorResponse(c, "服务异常")
	})
}).Start()

9 参数验证

支持QueryJsonHeaderUri参数验证,提供ValidateQueryValidateJsonValidateHeaderValidateUriValidateQueryWithFilterValidateJsonWithFilterValidateHeaderWithFilterValidateUriWithFilter函数

func ValidateQuery[T any](f func(ctx *gin.Context, param *T), errFunc …ValidateErrFunc) func(ctx *gin.Context)
@param f func(ctx *gin.Context, param *T) bzgin的http handle方法
@param errFunc …bzgin.ValidateErrFunc 可自定义处理异常的方法
@return func(ctx *gin.Context) http handle方法

// 错误类型_err,如:required_err:"userId不能为空"
// err,如:err:"userId错误"
// 没有定义错误,如:user的格式需遵守: required
type RequestDto struct {
	Name string `form:"name" binding:"required" required_err:"name是必要字段"` 
	Age  int    `form:"age" binding:"required" err:"请输入age"` 
	Desc string `form:"desc" binding:"required"`
}
	
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
	r.GET("", bzgin.ValidateQuery(func(c *gin.Context, param *RequestDto) {
		fmt.Println(param.Name)
	}))
	r.GET("filter", bzgin.ValidateQueryWithFilter(func(c *gin.Context, param *RequestDto) {
		fmt.Println(param.Name)
	}))
}).Start()
# curl http://127.0.0.1:8080
{
    "code": 400,
    "message": "请求参数错误",
    "reasonCode": "BAD_REQUEST",
    "reason": "Key: 'RequestDto.Name' Error:Field validation for 'Name' failed on the 'required' tag\nKey: 'RequestDto.Age' Error:Field validation for 'Age' failed on the 'required' tag\nKey: 'RequestDto.Desc' Error:Field validation for 'Desc' failed on the 'required' tag",
    "data": null
}

# curl http://127.0.0.1:8080/filter
{
	"code": 400,
    "message": "请求参数错误",
    "reasonCode": "BAD_REQUEST",
    "reason": "name是必要字段",
    "data": null
}

# curl http://127.0.0.1:8080/filter?name=breeze
{
    "code": 400,
    "message": "请求参数错误",
    "reasonCode": "BAD_REQUEST",
    "reason": "请输入age",
    "data": null
}

# curl http://127.0.0.1:8080/filter?name=breeze&age=18
{
    "code": 400,
    "message": "请求参数错误",
    "reasonCode": "BAD_REQUEST",
    "reason": "Desc的格式需遵守: required",
    "data": null
}

10 jwt

实例化jwt
func NewJwt[C any, T any](signingKey string) *Jwt[C, T]
@type [C] jwt中保存数据的结构体
@type [T] 支持gin中间件中 根据jwt保存的数据解析后 获得关键信息并存储用户信息的结构体
@param signingKey string 加密密钥
@return *Jwt[C, T] 实例结构体

gin中间件方法
func (j *Jwt[C, T]) Handler(
  dataFunc func(claims C, token string) (data T, msg string, err error) , // 解析并存储用户信息
  badResponseFuncs …func(c *gin.Context, msg string, err error), // 注册错误响应方法,默认使用 bzgin.BadRequestResponse
) gin.HandlerFunc
@param func(claims C, token string) (data T, msg string, err error)
      @param claims [C] jwt存储的数据
      @param token string jwt token字符串,方便用于后续到数据库匹配
      @return data [T] 用户信息
      @return msg string 可用于业务信息
      @return err error 错误信息
@return gin.HandlerFunc gin中间件类型

获取用户数据
func (j *Jwt[C, T]) GetJwtData(c *gin.Context) (T, bool)
@param ctx *gin.Context gin http上下文
@return T 用户数据
@return bool 是否获取成功

解析token(有中间件解析的情况下一般用不上)
func (j *Jwt[C, T]) ParseJwtInfo(token string) (C, bool, error)
@param token string 用户token
@return [C] 设置jwt存储的数据
@return error 错误信息

// jwt数据
type MemberClaims struct {
	Id uint
}
// 用户数据
type Member struct {
	Id   uint
	Name string
	Age  int
}

signingKey := "breeze" // 加密密钥
jwt := bzgin.NewJwt[*MemberClaims, *Member](signingKey)

bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {

	r.GET("getToken", func(c *gin.Context) {
		token, err := jwt.GenToken(func(claims *bzgin.Claims[*MemberClaims]) *bzgin.Claims[*MemberClaims] {
		claims.Data = &MemberClaims{Id: 99} // 切记是直接赋值Data
		return claims
		}, 10*time.Minute) // token有效期
		fmt.Println(token, err)
	})

	r.Use(jwt.Handler(
        // 用户数据写入数据缓存到上下文,此处得到token,从数据库获取后,存入上下文用
		func(claims *MemberClaims, token string) (data *Member, msg string, err error) {
			return &Member{ Id:   99, Name: "Breeze", Age:  18 }, "", nil
		}))
        
	r.GET("getMember", func(c *gin.Context) {
		data, ok := jwt.GetJwtData(c) // 从上下文获取用户数据
		fmt.Println(data, ok)
	})
}).Start()
# curl http://127.0.0.1:8080/getToken
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJEYXRhIjp7IklkIjo5OX0sImV4cCI6MTY5MjQ2NTIyNiwiaWF0IjoxNjkyNDY0NjI2fQ._Zce7vBX2kXmuQKbOHtZY3I_QgFXv0lln5NdKUnORfU <nil>

# curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJEYXRhIjp7IklkIjo5OX0sImV4cCI6MTY5MjQ2NTIyNiwiaWF0IjoxNjkyNDY0NjI2fQ._Zce7vBX2kXmuQKbOHtZY3I_QgFXv0lln5NdKUnORfU" http://127.0.0.1:8080/getMember
&{99 Breeze 18} true