From a389c16f9894e230ed06a8043bdf50e94fe12b19 Mon Sep 17 00:00:00 2001 From: zhengwei Date: Tue, 17 Sep 2024 12:47:58 +0800 Subject: [PATCH] support http multipart request --- tools/goctl/api/gogen/genhandlers.go | 23 +++++++++-------- tools/goctl/api/gogen/genlogic.go | 10 ++++++-- tools/goctl/api/gogen/gentypes.go | 11 ++++++++ tools/goctl/api/gogen/handler.tpl | 2 +- tools/goctl/api/gogen/logic.tpl | 8 ++++++ tools/goctl/api/parser/parser.go | 21 ++++++++++------ tools/goctl/api/spec/spec.go | 1 + tools/goctl/pkg/parser/api/parser/analyzer.go | 25 +++++++++++++------ 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/tools/goctl/api/gogen/genhandlers.go b/tools/goctl/api/gogen/genhandlers.go index 4611be4d7ea2..a99805bab668 100644 --- a/tools/goctl/api/gogen/genhandlers.go +++ b/tools/goctl/api/gogen/genhandlers.go @@ -41,17 +41,18 @@ func genHandler(dir, rootPkg string, cfg *config.Config, group spec.Group, route templateFile: handlerTemplateFile, builtinTemplate: handlerTemplate, data: map[string]any{ - "PkgName": pkgName, - "ImportPackages": genHandlerImports(group, route, rootPkg), - "HandlerName": handler, - "RequestType": util.Title(route.RequestTypeName()), - "LogicName": logicName, - "LogicType": strings.Title(getLogicName(route)), - "Call": strings.Title(strings.TrimSuffix(handler, "Handler")), - "HasResp": len(route.ResponseTypeName()) > 0, - "HasRequest": len(route.RequestTypeName()) > 0, - "HasDoc": len(route.JoinedDoc()) > 0, - "Doc": getDoc(route.JoinedDoc()), + "PkgName": pkgName, + "ImportPackages": genHandlerImports(group, route, rootPkg), + "HandlerName": handler, + "RequestType": util.Title(route.RequestTypeName()), + "LogicName": logicName, + "LogicType": strings.Title(getLogicName(route)), + "Call": strings.Title(strings.TrimSuffix(handler, "Handler")), + "HasResp": len(route.ResponseTypeName()) > 0, + "HasRequest": len(route.RequestTypeName()) > 0, + "HasDoc": len(route.JoinedDoc()) > 0, + "Doc": getDoc(route.JoinedDoc()), + "NeedParseMultipart": len(route.OpenFiles) > 0, }, }) } diff --git a/tools/goctl/api/gogen/genlogic.go b/tools/goctl/api/gogen/genlogic.go index e162eeb64222..342fd9396f9a 100644 --- a/tools/goctl/api/gogen/genlogic.go +++ b/tools/goctl/api/gogen/genlogic.go @@ -51,8 +51,10 @@ func genLogicByRoute(dir, rootPkg string, cfg *config.Config, group spec.Group, } if len(route.RequestTypeName()) > 0 { requestString = "req *" + requestGoTypeName(route, typesPacket) + if len(route.OpenFiles) > 0 { + requestString = "r * http.Request, " + requestString + } } - subDir := getLogicFolderPath(group, route) return genFile(fileGenConfig{ dir: dir, @@ -72,6 +74,7 @@ func genLogicByRoute(dir, rootPkg string, cfg *config.Config, group spec.Group, "request": requestString, "hasDoc": len(route.JoinedDoc()) > 0, "doc": getDoc(route.JoinedDoc()), + "openFiles": route.OpenFiles, }, }) } @@ -91,7 +94,10 @@ func getLogicFolderPath(group spec.Group, route spec.Route) string { func genLogicImports(route spec.Route, parentPkg string) string { var imports []string - imports = append(imports, `"context"`+"\n") + imports = append(imports, `"context"`) + if len(route.OpenFiles) != 0 { + imports = append(imports, fmt.Sprintf("\"net/http\"\n")) + } imports = append(imports, fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, contextDir))) if shallImportTypesPackage(route) { imports = append(imports, fmt.Sprintf("\"%s\"\n", pathx.JoinPackages(parentPkg, typesDir))) diff --git a/tools/goctl/api/gogen/gentypes.go b/tools/goctl/api/gogen/gentypes.go index 5ee51abe940d..65a8c7bc37a0 100644 --- a/tools/goctl/api/gogen/gentypes.go +++ b/tools/goctl/api/gogen/gentypes.go @@ -91,6 +91,17 @@ func writeType(writer io.Writer, tp spec.Type) error { func writeMember(writer io.Writer, members []spec.Member) error { for _, member := range members { + var existFileTag bool + for _, t := range member.Tags() { + if t.Key == "file" { + existFileTag = true + break + } + } + if existFileTag { + continue + } + if member.IsInline { if _, err := fmt.Fprintf(writer, "%s\n", strings.Title(member.Type.Name())); err != nil { return err diff --git a/tools/goctl/api/gogen/handler.tpl b/tools/goctl/api/gogen/handler.tpl index fce5acc2d157..deb7496e2c4a 100644 --- a/tools/goctl/api/gogen/handler.tpl +++ b/tools/goctl/api/gogen/handler.tpl @@ -17,7 +17,7 @@ func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { } {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx) - {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}}) + {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .NeedParseMultipart}}r,{{end}}{{if .HasRequest}}&req{{end}}) if err != nil { httpx.ErrorCtx(r.Context(), w, err) } else { diff --git a/tools/goctl/api/gogen/logic.tpl b/tools/goctl/api/gogen/logic.tpl index 94611c577b29..c5a44c6c5a8a 100644 --- a/tools/goctl/api/gogen/logic.tpl +++ b/tools/goctl/api/gogen/logic.tpl @@ -21,6 +21,14 @@ func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) *{{.logic}} func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} { // todo: add your logic here and delete this line + {{ range $k,$v:=.openFiles }} + {{$v}},{{$v}}Header, err := r.FormFile("{{$v}}") + if err != nil { + return + } + defer {{$v}}.Close() + _ = {{$v}}Header + {{end}} {{.returnString}} } diff --git a/tools/goctl/api/parser/parser.go b/tools/goctl/api/parser/parser.go index d29be54ad2c8..c6186c7af70a 100644 --- a/tools/goctl/api/parser/parser.go +++ b/tools/goctl/api/parser/parser.go @@ -147,7 +147,7 @@ func (p parser) fillTypes() error { for _, member := range v.Members { switch v := member.Type.(type) { case spec.DefineStruct: - tp, err := p.findDefinedType(v.RawName) + tp, _, err := p.findDefinedType(v.RawName) if err != nil { return err } @@ -167,16 +167,22 @@ func (p parser) fillTypes() error { return nil } -func (p parser) findDefinedType(name string) (*spec.Type, error) { +func (p parser) findDefinedType(name string) (*spec.Type, []string, error) { for _, item := range p.spec.Types { - if _, ok := item.(spec.DefineStruct); ok { + if s, ok := item.(spec.DefineStruct); ok { if item.Name() == name { - return &item, nil + var fileTagNames []string + for _, m := range s.Members { + if m.Tag == "file" { + fileTagNames = append(fileTagNames, m.Name) + } + } + return &item, fileTagNames, nil } } } - return nil, fmt.Errorf("type %s not defined", name) + return nil, nil, fmt.Errorf("type %s not defined", name) } func (p parser) fieldToMember(field *ast.TypeField) spec.Member { @@ -351,19 +357,20 @@ func (p parser) fillRouteType(route *spec.Route) error { if route.RequestType != nil { switch route.RequestType.(type) { case spec.DefineStruct: - tp, err := p.findDefinedType(route.RequestType.Name()) + tp, tagNames, err := p.findDefinedType(route.RequestType.Name()) if err != nil { return err } route.RequestType = *tp + route.OpenFiles = tagNames } } if route.ResponseType != nil { switch route.ResponseType.(type) { case spec.DefineStruct: - tp, err := p.findDefinedType(route.ResponseType.Name()) + tp, _, err := p.findDefinedType(route.ResponseType.Name()) if err != nil { return err } diff --git a/tools/goctl/api/spec/spec.go b/tools/goctl/api/spec/spec.go index 8249c66f8195..0baddf30dc99 100644 --- a/tools/goctl/api/spec/spec.go +++ b/tools/goctl/api/spec/spec.go @@ -76,6 +76,7 @@ type ( Path string RequestType Type ResponseType Type + OpenFiles []string Docs Doc Handler string AtDoc AtDoc diff --git a/tools/goctl/pkg/parser/api/parser/analyzer.go b/tools/goctl/pkg/parser/api/parser/analyzer.go index cecb0c5977c4..c7d6682f4e14 100644 --- a/tools/goctl/pkg/parser/api/parser/analyzer.go +++ b/tools/goctl/pkg/parser/api/parser/analyzer.go @@ -216,19 +216,20 @@ func (a *Analyzer) fillRouteType(route *spec.Route) error { if route.RequestType != nil { switch route.RequestType.(type) { case spec.DefineStruct: - tp, err := a.findDefinedType(route.RequestType.Name()) + tp, tagNames, err := a.findDefinedType(route.RequestType.Name()) if err != nil { return err } route.RequestType = tp + route.OpenFiles = tagNames } } if route.ResponseType != nil { switch route.ResponseType.(type) { case spec.DefineStruct: - tp, err := a.findDefinedType(route.ResponseType.Name()) + tp, _, err := a.findDefinedType(route.ResponseType.Name()) if err != nil { return err } @@ -347,7 +348,7 @@ func (a *Analyzer) fillTypes() error { for _, member := range v.Members { switch v := member.Type.(type) { case spec.DefineStruct: - tp, err := a.findDefinedType(v.RawName) + tp, _, err := a.findDefinedType(v.RawName) if err != nil { return err } @@ -390,16 +391,24 @@ func (a *Analyzer) fillTypeExpr(expr *ast.TypeExpr) error { } } -func (a *Analyzer) findDefinedType(name string) (spec.Type, error) { +func (a *Analyzer) findDefinedType(name string) (spec.Type, []string, error) { for _, item := range a.spec.Types { - if _, ok := item.(spec.DefineStruct); ok { + if s, ok := item.(spec.DefineStruct); ok { if item.Name() == name { - return item, nil + var fileTagNames []string + for _, m := range s.Members { + for _, t := range m.Tags() { + if t.Key == "file" { + fileTagNames = append(fileTagNames, t.Name) + } + } + } + return item, fileTagNames, nil } } } - return nil, fmt.Errorf("type %s not defined", name) + return nil, nil, fmt.Errorf("type %s not defined", name) } func (a *Analyzer) getType(expr *ast.BodyStmt, req bool) (spec.Type, error) { @@ -414,7 +423,7 @@ func (a *Analyzer) getType(expr *ast.BodyStmt, req bool) (spec.Type, error) { if IsBaseType(body.Value.Token.Text) { tp = spec.PrimitiveType{RawName: body.Value.Token.Text} } else { - tp, err = a.findDefinedType(body.Value.Token.Text) + tp, _, err = a.findDefinedType(body.Value.Token.Text) if err != nil { return nil, err }