golang利用模板生成Controller Container

2021-07-30  本文已影响0人  EasyNetCN

终于完成了基于模板生成Controller Container。路由直接注释到Controller上,比如:// @RequestMapping("/apps"),还是类似生成Service Container一样,通过直接解析controller的go文件实现。

package utility

import (
    "fmt"
    "html/template"
    "io/ioutil"
    "os"
    "regexp"
    "sort"
    "strings"
    "testing"
)

type ControllerProp struct {
    Name     string
    TypeName string
}

type Controller struct {
    Name           string
    RequestMapping string
    Props          []ControllerProp
}

type ControllerContext struct {
    Controllers []Controller
}

func Test_GenerateControllerContainer(t *testing.T) {
    files, err1 := os.ReadDir("../controller")

    if err1 != nil {
        fmt.Println("parse file err:", err1)
        return
    }

    controllers := make([]Controller, 0)

    for _, file := range files {
        filename := file.Name()

        if strings.HasSuffix(filename, "_controller.go") {
            controllerName := UpperCamelCase(filename[:len(filename)-3])

            controller, err2 := ParseController(fmt.Sprintf("../controller/%s", filename), controllerName)

            if err2 != nil {
                fmt.Println(err2)

                return
            }

            controllers = append(controllers, *controller)

        }
    }

    if f, err := os.Stat("../controller/controller_container.go"); f != nil && err == nil {
        if err := os.Remove("../controller/controller_container.go"); err != nil {
            fmt.Println("remove file err:", err)
            return
        }
    }

    f, err2 := os.OpenFile("../controller/controller_container.go", os.O_CREATE|os.O_WRONLY, 0666)

    defer f.Close()

    if err2 != nil {
        fmt.Println("can not create output file,err:", err2)

        return
    }

    funcMap := template.FuncMap{"unescaped": Unescaped}
    tpl, err3 := template.New("controller-container.tpl").Funcs(funcMap).ParseFiles("./controller-container.tpl")

    if err3 != nil {
        fmt.Println("parse file err:", err3)
        return
    }

    if err := tpl.Execute(f, &ControllerContext{Controllers: controllers}); err != nil {
        fmt.Println("There was an error:", err.Error())
    }
}

func Unescaped(x string) interface{} { return template.HTML(x) }

func UpperCamelCase(txt string) string {
    sb := new(strings.Builder)

    strs := strings.Split(txt, "_")

    for _, str := range strs {
        sb.WriteString(strings.ToUpper(string(str[0])))
        sb.WriteString(str[1:])
    }

    return sb.String()
}

func ParseController(filename, controllerName string) (*Controller, error) {
    txt, err1 := ReadGoFile(filename)

    if err1 != nil {
        return nil, err1
    }

    requestMapping := RequestMapping(txt)
    props := ControllerProps(txt, controllerName)

    return &Controller{Name: controllerName, RequestMapping: requestMapping, Props: props}, nil
}

func ControllerProps(txt, controllerName string) []ControllerProp {
    startTxt := fmt.Sprintf("type %s struct {", controllerName)

    firstIndex := strings.Index(txt, startTxt) + len(startTxt)
    lastIndex := firstIndex + strings.Index(txt[firstIndex:], "}")

    strs := strings.Split(txt[firstIndex:lastIndex], "\n")

    props := make([]ControllerProp, 0)

    for _, str := range strs {
        strs := strings.Split(strings.TrimSpace(str), " ")

        if len(strs) > 1 {
            props = append(props, ControllerProp{Name: strs[0], TypeName: strs[1]})
        }
    }

    return props
}

func RequestMapping(txt string) string {
    startTxt := "// @RequestMapping("

    firstIndex := strings.Index(txt, startTxt) + len(startTxt)
    lastIndex := firstIndex + strings.Index(txt[firstIndex:], ")")

    return strings.TrimSpace(txt[firstIndex:lastIndex])
}

func ReadGoFile(fileName string) (string, error) {
    f, err := os.OpenFile(fileName, os.O_RDONLY, 0600)

    defer f.Close()

    if err != nil {
        return "", err
    } else {
        if bytes, err := ioutil.ReadAll(f); err != nil {
            return "", err
        } else {
            return string(bytes), nil
        }
    }
}

service container模板文件

package controller

import (
    "github.com/kataras/iris/v12/mvc"
)

type ControllerContainer struct {
    mvcApp           *mvc.Application
    serviceContainer *service.ServiceContainer
}

func NewControllerContainer(mvcApp *mvc.Application, serviceContainer *service.ServiceContainer) *ControllerContainer {
    return &ControllerContainer{mvcApp: mvcApp, serviceContainer: serviceContainer}
}

func (c *ControllerContainer) InitMvc() {
    {{range $controller := .Controllers -}}
    c.mvcApp.Party({{.RequestMapping | unescaped}}).Configure(func(app *mvc.Application) {
        {{range $prop := .Props -}}
        app.Register(c.serviceContainer.{{.Name}})
        {{end -}}
        app.Handle(new({{.Name}}))
    })
    
    {{end -}}
}
上一篇 下一篇

猜你喜欢

热点阅读