package common import ( "errors" "fmt" "os" "path" "path/filepath" "reflect" "strings" "91porn-server/generate/tpl" ) func NewGen(moduleName, tblComment string) *G { rootPath := RootPath() return &G{ AppGenerate: true, WebGenerate: true, RootPath: rootPath, ModuleName: moduleName, TableComment: tblComment, } } type Field struct { Name string TypeName string Tag string BsonField string FormTag string UpdateTag string Comment string SubField []Field SubStructName string } type G struct { AppGenerate bool WebGenerate bool RootPath string ModuleName string StructName string FileName string TableName string TableComment string Fields []Field } // Generate 生成... func (o *G) Generate(s interface{}) { var err error // 获取model结构 t := reflect.TypeOf(s) o.Fields, err = o.explodeStruct(t) if err != nil { log(err.Error(), "error") return } o.StructName = FirstUpper(t.Name()) if o.TableName == "" { o.TableName = o.StructName } o.FileName = strings.ToLower(o.TableName) // 生成变量表 v := make(map[string]string) v["FileName"] = strings.ToLower(o.TableName) v["ModuleName"] = o.ModuleName v["TableComment"] = o.TableComment v["TableName"] = o.TableName v["StructName"] = o.StructName v["PackageTableName"] = strings.ToLower(o.TableName) v["RouterName"] = FirstLower(o.TableName) v["StructDefine"] = o.genStructDefine(o.StructName, o.Fields) v["AppRespStructFields"] = o.genAppRespStructFields(o.Fields) v["AppRespTransferStatement"] = o.genAppRespTransferStatement(o.Fields) v["CreateReqFields"] = o.genCreateStructFields(o.Fields) v["CreateStatement"] = o.genCreateStatement(o.Fields) v["UpdateReqFields"] = o.genUpdateStructFields(o.Fields) v["UpdateStatement"] = o.genUpdateStatement(o.Fields) // 循环配置进行生成 for tpDir, c := range tpl.Config { // 判断是否生成 app web if !o.AppGenerate && strings.HasPrefix(tpDir, "/app") { continue } if !o.WebGenerate && strings.HasPrefix(tpDir, "/web") { continue } // 遍历目录 tplPath := path.Join(o.RootPath, "/generate/tpl", tpDir) var tpls []string err := filepath.Walk(tplPath, func(path string, info os.FileInfo, err error) error { if !info.IsDir() && strings.HasSuffix(info.Name(), ".tpl") { tpls = append(tpls, path) } return nil }) if err != nil { log(err.Error(), "error") return } // 创建文件 for _, tf := range tpls { err = o.CreateFile(tpDir, tf, c, v) if err != nil { log(err.Error(), "error") } } } // 执行完成 log("生成完毕!", "info") } // CreateFile 根据模板创建文件 func (o *G) CreateFile(dir, tf string, conf tpl.Tpl, val map[string]string) (err error) { val["VariablePrefix"] = FirstUpper(conf.VariablePrefix) _, f := path.Split(tf) f = strings.Replace(TplReplace(f, val), ".tpl", ".go", -1) fPath := path.Join(o.RootPath, dir) if conf.SplitDir { fPath = path.Join(fPath, o.FileName+conf.DirSuffix) } // 创建目录 err = EnsurePath(fPath) if err != nil { return err } fPath = path.Join(fPath, f) // 检查文件是否存在,存在则跳过 //_, err = os.Stat(fPath) //if err == nil { // log("目标文件已存在,不可覆盖!File:"+fPath, "warn") // return nil //} log("准备写入目标文件:"+fPath, "info") // 读取文件并替换内容 b, err := os.ReadFile(tf) if err != nil { return err } tplContent := string(b) tplContent = TplReplace(tplContent, val) // 写入目标文件 if err := os.WriteFile(fPath, []byte(tplContent), 0755); err != nil { log("写入目标文件:"+fPath+"失败!", "error") return err } log("写入目标文件:"+fPath+"成功!", "error") return nil } // genStructDefine 生成结构体定义语句 func (o *G) genStructDefine(structName string, fields []Field) string { var s []string sub := make(map[string][]Field) for _, f := range fields { tmp := fmt.Sprintf(" %s\t%s\t`%s`\t// %s", f.Name, f.TypeName, f.Tag, f.Comment) s = append(s, tmp) if len(f.SubField) > 0 { sub[f.SubStructName] = f.SubField } } ms := fmt.Sprintf("type %s struct {\n%s\n} \n\n", structName, strings.Join(s, "\n")) if len(sub) == 0 { return ms } var subs []string for n, v := range sub { subs = append(subs, o.genStructDefine(n, v)) } ss := strings.Join(subs, "\n\n") return ms + ss } // genAppRespStructFields 生成app返回结构 func (o *G) genAppRespStructFields(fields []Field) string { var s []string for _, f := range fields { tmp := fmt.Sprintf(" %s\t%s\t`%s`\t// %s", f.Name, f.TypeName, f.UpdateTag, f.Comment) s = append(s, tmp) } return strings.Join(s, "\n") } // genAppRespTransferStatement 生成app返回转换过程代码 func (o *G) genAppRespTransferStatement(fields []Field) string { var s []string for _, f := range fields { tmp := fmt.Sprintf(" %s: item.%s,", f.Name, f.Name) s = append(s, tmp) } str := strings.Join(s, "\n") return str } // genCreateStructFields 生成创建数据字段定义 func (o *G) genCreateStructFields(fields []Field) string { var s []string for _, f := range fields { fn := strings.ToLower(f.Name) if fn == "id" || fn == "createdat" || fn == "updatedat" { continue } tmp := fmt.Sprintf(" %s\t%s\t`%s`\t// %s", f.Name, f.TypeName, f.FormTag, f.Comment) s = append(s, tmp) } return strings.Join(s, "\n") } // genCreateStatement 生成创建过程代码 func (o *G) genCreateStatement(fields []Field) string { var s []string hasCreateTime := false hasUpdateTime := false for _, f := range fields { fn := strings.ToLower(f.Name) if fn == "id" { continue } if fn == "createdat" { hasCreateTime = true continue } if fn == "updatedat" { hasUpdateTime = true continue } tmp := fmt.Sprintf(" %s: p.%s,", f.Name, f.Name) s = append(s, tmp) } str := strings.Join(s, "\n") if hasCreateTime { str += "\n CreatedAt: time.Now()," } if hasUpdateTime { str += "\n UpdatedAt: time.Now()," } return str } // genUpdateStructFields 生成更新数据字段定义 func (o *G) genUpdateStructFields(fields []Field) string { var s []string for _, f := range fields { fn := strings.ToLower(f.Name) if fn == "id" || fn == "createdat" || fn == "updatedat" { continue } tmp := fmt.Sprintf(" %s\t*%s\t`%s`\t// %s", f.Name, f.TypeName, f.UpdateTag, f.Comment) s = append(s, tmp) } return strings.Join(s, "\n") } // genUpdateStatement 生成更新过程代码 func (o *G) genUpdateStatement(fields []Field) string { var s []string hasUpdateTime := false for _, f := range fields { fn := strings.ToLower(f.Name) if fn == "id" || fn == "createdat" { continue } if fn == "updatedat" { hasUpdateTime = true continue } tmp := fmt.Sprintf(" if p.%s != nil {\n\t\tdata[\"%s\"] = *p.%s\n\t}", f.Name, f.BsonField, f.Name) s = append(s, tmp) } str := strings.Join(s, "\n") if hasUpdateTime { str += "\n\tdata[\"updatedAt\"] = time.Now()\n" } return str } // SetTableName 自定义表名 func (o *G) SetTableName(n string) { o.TableName = FirstUpper(n) } // NoApp 不生成app func (o *G) NoApp() { o.AppGenerate = false } // NoWeb 不生成web func (o *G) NoWeb() { o.WebGenerate = false } // explodeStruct 解剖struct func (o *G) explodeStruct(t reflect.Type) (f []Field, err error) { if t.Kind() != reflect.Struct { return nil, errors.New("不支持结构体以外的类型!") } // 遍历结构体的字段 for i := 0; i < t.NumField(); i++ { field := t.Field(i) jsonTag := field.Tag.Get("json") if jsonTag == "" { jsonTag = "-" } bsonTag := field.Tag.Get("bson") if bsonTag == "" { bsonTag = "-" } tag := fmt.Sprintf("json:\"%s\" bson:\"%s\"", jsonTag, bsonTag) fTag := fmt.Sprintf("json:\"%s\" form:\"%s\" binding:\"required\"", jsonTag, jsonTag) uTag := fmt.Sprintf("json:\"%s\"", jsonTag) isDefinedType := strings.Count(field.Type.String(), "main.") > 0 typeName := strings.Replace(field.Type.String(), "main.", "", 1) tmp := Field{ Name: field.Name, TypeName: typeName, Tag: tag, BsonField: bsonTag, FormTag: fTag, UpdateTag: uTag, Comment: field.Tag.Get("comment"), } if isDefinedType { if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Pointer { tmp.SubField, _ = o.explodeStruct(field.Type.Elem()) if field.Type.Kind() == reflect.Slice { tmp.SubStructName = strings.TrimLeft(typeName, "[]") } else { tmp.SubStructName = strings.TrimLeft(typeName, "*") } } else if field.Type.Kind() == reflect.Struct { tmp.SubField, _ = o.explodeStruct(field.Type) tmp.SubStructName = typeName } } f = append(f, tmp) } return }