From 0047befc07ba0d2f23425dbbe45bb221d8608cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Sat, 15 Feb 2025 20:46:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=B2=E7=9F=A5BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- define/openapi.go | 22 ++++++++--------- generate.go | 61 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/define/openapi.go b/define/openapi.go index f536588..f4f45d0 100644 --- a/define/openapi.go +++ b/define/openapi.go @@ -100,17 +100,17 @@ type ExternalDocs struct { // // Date : 12:29 2024/7/19 type PathConfigParameter struct { - Name string `json:"name"` // 参数名称 - In string `json:"in"` // 必选. 参数的位置,可能的值有 "query", "header", "path" 或 "cookie"。 - Description string `json:"description"` // 对此参数的简要描述,这里可以包含使用示例。CommonMark syntax可以被用来呈现富文本格式. - Required bool `json:"required"` // 标明此参数是否是必选参数。如果 参数位置 的值是 path,那么这个参数一定是 必选 的因此这里的值必须是true。其他的则视情况而定。此字段的默认值是false。 - Deprecated bool `json:"deprecated"` // 标明一个参数是被弃用的而且应该尽快移除对它的使用。 - Schema *Schema `json:"schema,omitempty,omitempty"` // 定义适用于此参数的类型结构。 Schema 对象 | Reference 对象 - AllowEmptyValue bool `json:"allowEmptyValue"` // 设置是否允许传递空参数,这只在参数值为query时有效,默认值是false。如果同时指定了style属性且值为n/a(无法被序列化),那么此字段 allowEmptyValue应该被忽略。 - Style string `json:"style,omitempty"` // 描述根据参数值类型的不同如何序列化参数。默认值为(基于in字段的值):query 对应 form;path 对应 simple; header 对应 simple; cookie 对应 form。 - Explode bool `json:"explode,omitempty"` // 当这个值为true时,参数值类型为array或object的参数使用数组内的值或对象的键值对生成带分隔符的参数值。对于其他类型的参数,这个字段没有任何影响。当 style 是 form时,这里的默认值是 true,对于其他 style 值类型,默认值是false。 - AllowReserved bool `json:"allowReserved,omitempty"` // 决定此参数的值是否允许不使用%号编码使用定义于 RFC3986内的保留字符 :/?#[]@!$&'()*+,;=。 这个属性仅用于in的值是query时,此字段的默认值是false。 - Ref string `json:"$ref,omitempty"` // 一个允许引用规范内部的其他部分或外部规范的对象。 Reference 对象 定义于 JSON Reference 且遵循相同的结构、行为和规则。 + Name string `json:"name"` // 参数名称 + In string `json:"in"` // 必选. 参数的位置,可能的值有 "query", "header", "path" 或 "cookie"。 + Description string `json:"description"` // 对此参数的简要描述,这里可以包含使用示例。CommonMark syntax可以被用来呈现富文本格式. + Required bool `json:"required"` // 标明此参数是否是必选参数。如果 参数位置 的值是 path,那么这个参数一定是 必选 的因此这里的值必须是true。其他的则视情况而定。此字段的默认值是false。 + Deprecated bool `json:"deprecated"` // 标明一个参数是被弃用的而且应该尽快移除对它的使用。 + Schema *Schema `json:"schema,omitempty"` // 定义适用于此参数的类型结构。 Schema 对象 | Reference 对象 + AllowEmptyValue bool `json:"allowEmptyValue"` // 设置是否允许传递空参数,这只在参数值为query时有效,默认值是false。如果同时指定了style属性且值为n/a(无法被序列化),那么此字段 allowEmptyValue应该被忽略。 + Style string `json:"style,omitempty"` // 描述根据参数值类型的不同如何序列化参数。默认值为(基于in字段的值):query 对应 form;path 对应 simple; header 对应 simple; cookie 对应 form。 + Explode bool `json:"explode,omitempty"` // 当这个值为true时,参数值类型为array或object的参数使用数组内的值或对象的键值对生成带分隔符的参数值。对于其他类型的参数,这个字段没有任何影响。当 style 是 form时,这里的默认值是 true,对于其他 style 值类型,默认值是false。 + AllowReserved bool `json:"allowReserved,omitempty"` // 决定此参数的值是否允许不使用%号编码使用定义于 RFC3986内的保留字符 :/?#[]@!$&'()*+,;=。 这个属性仅用于in的值是query时,此字段的默认值是false。 + Ref string `json:"$ref,omitempty"` // 一个允许引用规范内部的其他部分或外部规范的对象。 Reference 对象 定义于 JSON Reference 且遵循相同的结构、行为和规则。 } // Schema ... diff --git a/generate.go b/generate.go index c05be3f..6af7e77 100644 --- a/generate.go +++ b/generate.go @@ -265,13 +265,12 @@ func (g *Generate) setApiDoc(baseCfg *define.UriBaseConfig, apiDocCfg *define.Pa // // Date : 16:10 2025/2/14 func (g *Generate) getApiDocBaseCfg(baseCfg *define.UriBaseConfig, paramType reflect.Type) *define.PathItemOperationConfig { - defaultPkgPath := wrapper.String(strings.TrimLeft(baseCfg.Uri, "/")).SnakeCaseToCamel() cfg := &define.PathItemOperationConfig{ Tags: baseCfg.TagList, Summary: baseCfg.Summary, Description: baseCfg.Description, ExternalDocs: nil, - OperationID: baseCfg.Method + "-" + defaultPkgPath, + OperationID: baseCfg.Method + "-" + baseCfg.Uri, Parameters: make([]*define.PathConfigParameter, 0), RequestBody: &define.RequestBody{ Required: true, @@ -331,13 +330,55 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe if propertyName == "-" { continue } - realInputTypeFormat := inputType.Field(i).Type.Kind().String() - fieldType := inputType.Field(i).Type - if inputType.Field(i).Type.Kind() == reflect.Ptr { - fieldType = inputType.Field(i).Type.Elem() + if inputType.Field(i).Type.Kind() == reflect.Struct && (inputType.Field(i).Type.String() == "Meta" || strings.HasSuffix(inputType.Field(i).Type.String(), ".Meta")) && inputType.Field(i).Type.NumField() == 0 { + // 空Meta字段认为是用来描述元信息的, 忽略 + continue } - if fieldType.Kind() == reflect.Ptr || - fieldType.Kind() == reflect.Struct || + realInputTypeFormat := inputType.Field(i).Type.String() + fieldType := inputType.Field(i).Type + /*if inputType.Field(i).Type.Kind() == reflect.Ptr { + fieldType = inputType.Field(i).Type.Elem() + }*/ + 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{ + Name: propertyName, + In: consts.SwaggerParameterInQuery, + Description: ParseStructField.GetParamDesc(inputType.Field(i)), + Required: ValidateRule.IsRequired(inputType.Field(i)), + Deprecated: ParseStructField.Deprecated(inputType.Field(i)), + Schema: &define.Schema{ + // Format: realInputTypeFormat, + Ref: g.getSchemaRef(schemaNameNext), + }, AllowEmptyValue: false, + Style: "", + Explode: false, + AllowReserved: false, + }) + } else { + // 当做默认基础类型, 默认不会出现 *map *[] + baseReqCfg.Parameters = append(baseReqCfg.Parameters, &define.PathConfigParameter{ + Name: propertyName, + In: consts.SwaggerParameterInQuery, + Description: ParseStructField.GetParamDesc(inputType.Field(i)), + Required: ValidateRule.IsRequired(inputType.Field(i)), + Deprecated: ParseStructField.Deprecated(inputType.Field(i)), + Schema: &define.Schema{ + Type: g.realBaseType2SwaggerType(inputType.Field(i).Type.String()), + Format: realInputTypeFormat, + }, + AllowEmptyValue: false, + Style: "", + Explode: false, + AllowReserved: false, + }) + } + continue + } + if fieldType.Kind() == reflect.Struct || fieldType.Kind() == reflect.Map || fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice { @@ -404,7 +445,7 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe // // Date : 15:25 2025/2/8 func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, inputType reflect.Type) string { - if inputType.Kind() == reflect.Struct && inputType.String() == "Meta" && inputType.NumField() == 0 { + if inputType.Kind() == reflect.Struct && (inputType.String() == "Meta" || strings.HasSuffix(inputType.String(), ".Meta")) && inputType.NumField() == 0 { // 空Meta字段认为是用来描述元信息的, 忽略 return "-" } @@ -648,7 +689,7 @@ func (g *Generate) parseBaseUriConfig(uriPrefix string, paramType reflect.Type) } res.Uri = metaField.Tag.Get(define.TagPath) if len(uriPrefix) > 0 { - res.Uri = strings.TrimRight(uriPrefix, "/") + strings.TrimLeft(res.Uri, "/") + res.Uri = strings.TrimRight(uriPrefix, "/") + "/" + strings.TrimLeft(res.Uri, "/") } // 保证接口路由以 /开头 res.Uri = "/" + strings.TrimLeft(res.Uri, "/")