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 -}}
}