diff --git a/define/openapi.go b/define/openapi.go index c590a60..ec82b92 100644 --- a/define/openapi.go +++ b/define/openapi.go @@ -134,6 +134,9 @@ type Schema struct { Items *PropertyXOf `json:"items,omitempty"` // items 必须存在如果 type 的值是 array。 Ref string `json:"$ref,omitempty"` // 类型引用 Format string `json:"format,omitempty"` // 格式化类型 + Maximum *int64 `json:"maximum,omitempty"` // 最大值 + Minimum *int64 `json:"minimum,omitempty"` // 最小值 + Default any `json:"default,omitempty"` // 默认值 } // Property 是从 JSON Schema 提取出来的,但是做了一些调整以适应 OpenAPI Specification。 @@ -147,6 +150,8 @@ type Property struct { Enum []any `json:"enum,omitempty"` // 枚举值列表 Default any `json:"default,omitempty"` // 默认值 : 不同于 JSON Schema,这个值必须符合定义与相同级别的 Schema 对象 中定义的类型,比如 type 是 string,那么 default 可以是 "foo" 但不能是 1。 Description string `json:"description,omitempty"` // 数据描述, CommonMark syntax可以被用来呈现富文本格式. + Maximum *int64 `json:"maximum,omitempty"` // 最大值 + Minimum *int64 `json:"minimum,omitempty"` // 最小值 AllOf []*PropertyXOf `json:"allOf,omitempty"` // type 是一个对象, allOf 指向对象描述 OneOf []*PropertyXOf `json:"oneOf,omitempty"` // type 是一个对象, allOf 指向对象描述 AnyOf []*PropertyXOf `json:"anyOf,omitempty"` // type 是一个对象, allOf 指向对象描述 @@ -162,9 +167,11 @@ type Property struct { // // Date : 17:13 2024/7/19 type PropertyXOf struct { - Type string `json:"type,omitempty"` // 基础类型 - Format string `json:"format,omitempty"` // 真实类型 - Ref string `json:"$ref,omitempty"` // 引用的结构描述 + Type string `json:"type,omitempty"` // 基础类型 + Format string `json:"format,omitempty"` // 真实类型 + Maximum *int64 `json:"maximum,omitempty"` // 最大值 + Minimum *int64 `json:"minimum,omitempty"` // 最小值 + Ref string `json:"$ref,omitempty"` // 引用的结构描述 } // SchemaDiscriminator 当一个 request bodies 或 response payloads 可以是多种 schemas 时,可以使用一个 discriminator 对象来帮助序列化、反序列化和校验 diff --git a/generate.go b/generate.go index 08fa1b3..3214430 100644 --- a/generate.go +++ b/generate.go @@ -354,8 +354,11 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe Required: ValidateRule.IsRequired(inputType.Field(i)), Deprecated: ParseStructFieldTag.Deprecated(inputType.Field(i)), Schema: &define.Schema{ - Type: convertBaseType, - Format: realInputTypeFormat, + Minimum: ValidateRule.Minimum(inputType.Field(i)), + Maximum: ValidateRule.Maximum(inputType.Field(i)), + Type: convertBaseType, + Format: realInputTypeFormat, + Default: ParseStructFieldTag.GetDefaultValue(inputType.Field(i)), }, AllowEmptyValue: false, Style: "", @@ -367,7 +370,6 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe if inputType.Field(i).Type.Kind() == reflect.Ptr { // 处理指针 if inputType.Field(i).Type.Elem().Kind() == reflect.Struct { - // 结构体指针 schemaNameNext := g.AddComponentsSchema("", propertyName, inputType.Field(i).Type.Elem()) baseReqCfg.Parameters = append(baseReqCfg.Parameters, &define.PathConfigParameter{ @@ -521,6 +523,8 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ Type: convertBaseType, Format: inputType.Field(i).Type.String(), + Maximum: ValidateRule.Maximum(inputType.Field(i)), + Minimum: ValidateRule.Minimum(inputType.Field(i)), Default: ParseStructFieldTag.GetDefaultValue(inputType.Field(i)), Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), } diff --git a/redoc-free/index.html b/redoc-free/index.html index b24dbd1..eef2e3c 100644 --- a/redoc-free/index.html +++ b/redoc-free/index.html @@ -1,7 +1,7 @@ - Redoc + {{DOC_TITLE}} diff --git a/struct_field.go b/struct_field.go index ac8932c..cdcc96e 100644 --- a/struct_field.go +++ b/struct_field.go @@ -70,31 +70,34 @@ func (psf parseStructFieldTag) GetDefaultValue(structField reflect.StructField) defaultTagList := []string{define.TagD, define.TagDefault} fieldType := structField.Type.Kind().String() for _, tag := range defaultTagList { - if val, exist := structField.Tag.Lookup(tag); exist && val != "" { - if strings.HasPrefix(fieldType, "int") { - i, _ := strconv.Atoi(val) - return i - } - if strings.HasPrefix(fieldType, "uint") { - uintVal, _ := strconv.ParseUint(val, 10, 64) - return uintVal - } - if strings.HasPrefix(fieldType, "float") { - floatVal, _ := strconv.ParseFloat(val, 64) - return floatVal - } - if strings.HasPrefix(fieldType, "string") { - return val - } - if strings.HasPrefix(fieldType, "bool") { - if val == "true" { - return true - } else { - return false - } - } + val, exist := structField.Tag.Lookup(tag) + val = strings.TrimSpace(val) + if !exist || len(val) == 0 { + continue + } + if strings.HasPrefix(fieldType, "int") { + i, _ := strconv.Atoi(val) + return i + } + if strings.HasPrefix(fieldType, "uint") { + uintVal, _ := strconv.ParseUint(val, 10, 64) + return uintVal + } + if strings.HasPrefix(fieldType, "float") { + floatVal, _ := strconv.ParseFloat(val, 64) + return floatVal + } + if strings.HasPrefix(fieldType, "string") { return val } + if strings.HasPrefix(fieldType, "bool") { + if val == "true" { + return true + } else { + return false + } + } + return val } return nil } diff --git a/swagger_ui.go b/swagger_ui.go index dc8c56b..e9bc91d 100644 --- a/swagger_ui.go +++ b/swagger_ui.go @@ -9,6 +9,7 @@ package api_doc import ( "embed" + "fmt" "git.zhangdeman.cn/gateway/api-doc/define" "git.zhangdeman.cn/zhangdeman/consts" "github.com/gin-gonic/gin" @@ -178,6 +179,7 @@ func (su *SwaggerUI) HandleRedocFreeUI() func(ctx *gin.Context) { return func(ctx *gin.Context) { // TODO : 这部分数据支持外部传参替换 replaceTable := map[string]string{ + "{{DOC_TITLE}}": fmt.Sprintf("【%v】%v", su.docInstance.Doc().Info.Version, su.docInstance.Doc().Info.Title), "{{CSS_FAMILY}}": "https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700", "{{DOC_PATH}}": "doc.json", "{{REDOC_STANDALONE_JS}}": "https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js", diff --git a/validate_rule.go b/validate_rule.go index e33f0e9..b55fba5 100644 --- a/validate_rule.go +++ b/validate_rule.go @@ -78,6 +78,84 @@ func (r validateRule) Enum(structField reflect.StructField) []any { return anySlice } +// Minimum 最小值 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 21:51 2025/2/18 +func (r validateRule) Minimum(structField reflect.StructField) *int64 { + ruleTable := r.getValidateRuleTable(structField) + var ( + err error + minVal, gteVal int64 + minStr, gteStr string + minStrExist, gteStrExist bool + ) + if minStr, minStrExist = ruleTable[consts.ValidatorRuleCommonMin.String()]; minStrExist && len(minStr) > 0 { + if minVal, err = strconv.ParseInt(minStr, 10, 64); nil != err { + panic("validate rule min val = " + minStr + " : " + err.Error()) + } + } + if gteStr, gteStrExist = ruleTable[consts.ValidateRuleGte.String()]; gteStrExist && len(gteStr) > 0 { + if gteVal, err = strconv.ParseInt(gteStr, 10, 64); nil != err { + panic("validate rule gte val = " + gteStr + " : " + err.Error()) + } + } + if !minStrExist && !gteStrExist { + // 未配置 + return nil + } + if len(minStr) > 0 { + if len(gteStr) > 0 { + if gteVal > minVal { + return &minVal + } + return >eVal + } + return &minVal + } + return >eVal +} + +// Maximum 最大值 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 22:00 2025/2/18 +func (r validateRule) Maximum(structField reflect.StructField) *int64 { + ruleTable := r.getValidateRuleTable(structField) + var ( + err error + maxVal, gleVal int64 + maxStr, gleStr string + maxStrExist, gleStrExist bool + ) + if maxStr, maxStrExist = ruleTable[consts.ValidatorRuleCommonMax.String()]; maxStrExist && len(maxStr) > 0 { + if maxVal, err = strconv.ParseInt(maxStr, 10, 64); nil != err { + panic("validate rule min val = " + maxStr + " : " + err.Error()) + } + } + if gleStr, gleStrExist = ruleTable[consts.ValidateRuleLte.String()]; gleStrExist && len(gleStr) > 0 { + if gleVal, err = strconv.ParseInt(gleStr, 10, 64); nil != err { + panic("validate rule gte val = " + gleStr + " : " + err.Error()) + } + } + if !maxStrExist && !gleStrExist { + // 未配置 + return nil + } + if len(maxStr) > 0 { + if len(gleStr) > 0 { + if gleVal > maxVal { + return &gleVal + } + return &maxVal + } + return &maxVal + } + return &gleVal +} + // getValidateRuleTable 解析验证规则表 // // Author : go_developer@163.com<白茶清欢>