Ver código fonte

提交代码生成源码到client v2工程

fei.li 4 anos atrás
pai
commit
0c649cd0d1

+ 83 - 54
client/engineclient.go

@@ -6,6 +6,9 @@ import (
 	"encoding/json"
 	"encoding/xml"
 	"fmt"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/env"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen"
 	"io"
 	"io/ioutil"
 	"mime/multipart"
@@ -13,13 +16,11 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
-	"git.qianqiusoft.com/qianqiusoft/light-apiengine/env"
-	"git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
 )
 
 type EngineClient struct {
 	ProjectName string
-	ServerUrl string
+	ServerUrl   string
 }
 
 type ResponeResult struct {
@@ -82,6 +83,10 @@ func (c *EngineClient) InitDefalutFile(project_name string) {
 }
 
 func (c *EngineClient) GenerateCurrentProject() {
+	c.GenerateCurrentProjectToPath("")
+}
+
+func (c *EngineClient) GenerateCurrentProjectToPath(destPath string) {
 	c.InitDefalutFile(c.ProjectName)
 
 	// 0---0
@@ -89,36 +94,55 @@ func (c *EngineClient) GenerateCurrentProject() {
 	//c.Generate(path + c.ProjectName + ".xml")
 
 	projMainXmlFileTemp := c.MergeXmlToSingle()
-	if projMainXmlFileTemp == ""{
+	if projMainXmlFileTemp == "" {
 		fmt.Println("projMainXmlFileTemp is empty")
 		return
 	}
-	c.Generate(projMainXmlFileTemp)
+
+	c.GenerateToPath(projMainXmlFileTemp, destPath)
+	c.GenSwagger(projMainXmlFileTemp)
 
 	path, _ := utils.GetCurrentPath()
-	CopyDir(env.Get("GOPATH", "") + "/src/git.qianqiusoft.com/qianqiusoft/light-apiengine/sqlconfig",
+	CopyDir(env.Get("GOPATH", "")+"/src/git.qianqiusoft.com/qianqiusoft/light-apiengine/sqlconfig",
 		path+"sqlconfig")
 }
 
-func (c *EngineClient) GenerateToPath(xmlfile string,dest_path string)  {
+func (c *EngineClient) GenerateToPath(xmlfile string, dest_path string) {
 	var result ResponeResult
-	server := "http://qianqiusoft.com:6166"
-	if c.ServerUrl != "" {
-		server = c.ServerUrl
+
+	isCompress := true
+
+	var bJson []byte
+
+	if c.ServerUrl == "local" {
+
+		isCompress = false
+		//dest_path+="../i2-erp-compare/"
+		bs := code_gen.DoGenerate(xmlfile, isCompress)
+		bJson = bs
+	} else {
+		server := "http://qianqiusoft.com:6166"
+		if c.ServerUrl != "" {
+			server = c.ServerUrl
+		}
+		server += "/api/v1/develop/generate"
+
+		bs := DoRequest(xmlfile, server)
+		bJson = bs.Bytes()
 	}
-	server += "/api/v1/develop/generate"
 
-	bs := DoRequest(xmlfile, server)
-	if bs != nil {
-		err := json.Unmarshal(bs.Bytes(), &result)
+	if bJson != nil {
+		err := json.Unmarshal(bJson, &result)
 		if err != nil {
 			fmt.Println(err.Error())
 		}
-		for i := 0; i < len(result.Data); i++ {
-			var b bytes.Buffer
-			b.Write(result.Data[i].Content)
-			unzip := unzipbytes(&b)
-			result.Data[i].Content = unzip.Bytes()
+		if isCompress {
+			for i := 0; i < len(result.Data); i++ {
+				var b bytes.Buffer
+				b.Write(result.Data[i].Content)
+				unzip := unzipbytes(&b)
+				result.Data[i].Content = unzip.Bytes()
+			}
 		}
 		for i := 0; i < len(result.Data); i++ {
 			path := result.Data[i].Name
@@ -128,11 +152,13 @@ func (c *EngineClient) GenerateToPath(xmlfile string,dest_path string)  {
 			fmt.Println(path)
 
 			ft := result.Data[i].Type
-			if result.Data[i].Type == "main" {
+			if ft == "main" {
+				//fmt.Println(string(result.Data[i].Content))
 			} else if ft == "config" || ft == "ci" {
 				_, err := os.Stat(path)
 				if err == nil {
 					fmt.Println(path + "已经存在,忽略...")
+					// fmt.Println(result.Data[i].Content)
 				} else {
 					ioutil.WriteFile(path, result.Data[i].Content, os.ModePerm)
 				}
@@ -151,7 +177,7 @@ func (c *EngineClient) GenerateToPath(xmlfile string,dest_path string)  {
 			} else if ft == "routers" {
 				os.MkdirAll(filepath.Dir(path), os.ModePerm)
 				ioutil.WriteFile(path, result.Data[i].Content, os.ModePerm)
-			} else if ft =="sql"{
+			} else if ft == "sql" {
 				if strings.Index(path, "_gen.xml") > 0 {
 					os.MkdirAll(filepath.Dir(path), os.ModePerm)
 					ioutil.WriteFile(path, result.Data[i].Content, os.ModePerm)
@@ -164,7 +190,7 @@ func (c *EngineClient) GenerateToPath(xmlfile string,dest_path string)  {
 						ioutil.WriteFile(path, result.Data[i].Content, os.ModePerm)
 					}
 				}
-			} else{
+			} else {
 				os.MkdirAll(filepath.Dir(path), os.ModePerm)
 				err := ioutil.WriteFile(path, result.Data[i].Content, os.ModePerm)
 				if err != nil {
@@ -175,12 +201,14 @@ func (c *EngineClient) GenerateToPath(xmlfile string,dest_path string)  {
 	}
 }
 
+/*
 func (c *EngineClient) Generate(xmlfile string) {
 	c.GenerateToPath(xmlfile, "")
 	c.GenSwagger(xmlfile)
 }
+*/
 
-func (c *EngineClient) GenSwagger(xmlfile string){
+func (c *EngineClient) GenSwagger(xmlfile string) {
 	server := "http://swagger.pusher.i2erp.cn"
 	server += "/api/v1/upload"
 
@@ -192,14 +220,14 @@ func (c *EngineClient) GenSwagger(xmlfile string){
 	}
 	client := &http.Client{}
 	resp, err := client.Do(request)
-	if err != nil{
+	if err != nil {
 		fmt.Println("===========================================================================>", err.Error())
-	}else{
+	} else {
 		defer resp.Body.Close()
 		bytess, err := ioutil.ReadAll(resp.Body)
-		if err != nil{
+		if err != nil {
 			fmt.Println("=======================================>ioutil.ReadAll error", err.Error())
-		}else{
+		} else {
 			fmt.Println("=======================================>", string(bytess))
 		}
 	}
@@ -210,16 +238,17 @@ func (c *EngineClient) GenSwagger(xmlfile string){
  * @param: none
  * @return: the path of final xml
  */
-func (c *EngineClient)MergeXmlToSingle()string{
+func (c *EngineClient) MergeXmlToSingle() string {
 	path, _ := utils.GetCurrentPath()
 	// e.g.: c:/gopath/src/hanghua_background_proj
+	path = "D:\\dev\\Go\\go_path\\src\\i2-erp-backend\\"
 	projDir := fmt.Sprintf("%s%s.proj", path, c.ProjectName)
 	projMainXmlFile := projDir + "/" + c.ProjectName + ".xml"
 	projMainXmlFileTemp := projDir + "/" + c.ProjectName + "_temp.xml"
 	_, err := os.Stat(projMainXmlFileTemp)
 	if os.IsNotExist(err) {
 		fmt.Println("-------------------------->remove project main file temp")
-		os.Remove(projMainXmlFileTemp)	// remove
+		os.Remove(projMainXmlFileTemp) // remove
 	}
 
 	_, err = os.Stat(projMainXmlFile)
@@ -231,57 +260,57 @@ func (c *EngineClient)MergeXmlToSingle()string{
 	app := XmlApplication{}
 	bytess, _ := ioutil.ReadFile(projMainXmlFile)
 	err = xml.Unmarshal(bytess, &app)
-	if err != nil{
+	if err != nil {
 		fmt.Println("xml.Unmarshal(bytess, &app) error " + err.Error())
 		return ""
 	}
 
 	controllers, err := scanControllers(projDir + "/controllers")
-	if err != nil{
+	if err != nil {
 		fmt.Println("scanControllers error " + err.Error())
 		return ""
 	}
 
 	beans, err := scanBeans(projDir + "/beans")
-	if err != nil{
+	if err != nil {
 		fmt.Println("scanBeans error " + err.Error())
 		return ""
 	}
 
 	tables, err := scanTables(projDir + "/tables")
-	if err != nil{
+	if err != nil {
 		fmt.Println("scanTables error " + err.Error())
 		return ""
 	}
 
-	if app.Controllers.ControllerList == nil{
+	if app.Controllers.ControllerList == nil {
 		app.Controllers.ControllerList = []XmlController{}
 	}
-	for i := range controllers{
+	for i := range controllers {
 		app.Controllers.ControllerList = append(app.Controllers.ControllerList, controllers[i])
 	}
 	createVueApisFolder(app.Controllers.ControllerList)
 
-	if app.Beans.BeanList == nil{
+	if app.Beans.BeanList == nil {
 		app.Beans.BeanList = []XmlBean{}
 	}
-	for i := range beans{
+	for i := range beans {
 		app.Beans.BeanList = append(app.Beans.BeanList, beans[i])
 	}
-	if app.Tables.TableList == nil{
+	if app.Tables.TableList == nil {
 		app.Tables.TableList = []XmlTable{}
 	}
-	for i := range tables{
+	for i := range tables {
 		app.Tables.TableList = append(app.Tables.TableList, tables[i])
 	}
 
 	bytess, err = xml.Marshal(app)
-	if err != nil{
+	if err != nil {
 		fmt.Println("xml.Marshal(app) error " + err.Error())
 		return ""
 	}
-	err  = ioutil.WriteFile(projMainXmlFileTemp, bytess,os.ModePerm)
-	if err != nil{
+	err = ioutil.WriteFile(projMainXmlFileTemp, bytess, os.ModePerm)
+	if err != nil {
 		fmt.Println("ioutil.WriteFile(projMainXmlFileTemp, bytess,os.ModePerm) error " + err.Error())
 		return ""
 	}
@@ -289,14 +318,14 @@ func (c *EngineClient)MergeXmlToSingle()string{
 	if os.IsNotExist(err) {
 		fmt.Println("main xml file temp of " + c.ProjectName + " does not exist")
 		return ""
-	}else{
+	} else {
 		fmt.Println("main xml file temp of " + c.ProjectName + " exist")
 	}
 
 	return projMainXmlFileTemp
 }
 
-func scanControllers(ctrldir string) ([]XmlController, error){
+func scanControllers(ctrldir string) ([]XmlController, error) {
 	_, err := os.Stat(ctrldir)
 	if os.IsNotExist(err) {
 		fmt.Println("controller dir does not exist", err.Error())
@@ -306,7 +335,7 @@ func scanControllers(ctrldir string) ([]XmlController, error){
 	controllers := []XmlController{}
 	filePaths := []string{}
 	filePaths, err = getAllFile(strings.TrimSuffix(ctrldir, "/"), filePaths)
-	if err != nil{
+	if err != nil {
 		fmt.Println("controller getAllFile error", err.Error())
 		return nil, err
 	}
@@ -330,9 +359,9 @@ func scanControllers(ctrldir string) ([]XmlController, error){
 		}
 
 		// get sub dir name
-		if arr[len(arr) - 2] != "controllers"{
+		if arr[len(arr)-2] != "controllers" {
 			// if sub dir is not controllers, set the dir attr
-			ctrl.Dir = arr[len(arr) - 2]
+			ctrl.Dir = arr[len(arr)-2]
 		}
 		controllers = append(controllers, ctrl)
 	}
@@ -368,7 +397,7 @@ func scanControllers(ctrldir string) ([]XmlController, error){
 	//return controllers, err
 }
 
-func scanBeans(ctrldir string) ([]XmlBean, error){
+func scanBeans(ctrldir string) ([]XmlBean, error) {
 	_, err := os.Stat(ctrldir)
 	if os.IsNotExist(err) {
 		fmt.Println("controller dir does not exist")
@@ -378,7 +407,7 @@ func scanBeans(ctrldir string) ([]XmlBean, error){
 	beans := []XmlBean{}
 	filePaths := []string{}
 	filePaths, err = getAllFile(strings.TrimSuffix(ctrldir, "/"), filePaths)
-	if err != nil{
+	if err != nil {
 		fmt.Println("controller getAllFile error", err.Error())
 		return nil, err
 	}
@@ -430,7 +459,7 @@ func scanBeans(ctrldir string) ([]XmlBean, error){
 	//return beans, err
 }
 
-func scanTables(ctrldir string) ([]XmlTable, error){
+func scanTables(ctrldir string) ([]XmlTable, error) {
 	_, err := os.Stat(ctrldir)
 	if os.IsNotExist(err) {
 		fmt.Println("controller dir does not exist")
@@ -440,7 +469,7 @@ func scanTables(ctrldir string) ([]XmlTable, error){
 	tables := []XmlTable{}
 	filePaths := []string{}
 	filePaths, err = getAllFile(strings.TrimSuffix(ctrldir, "/"), filePaths)
-	if err != nil{
+	if err != nil {
 		fmt.Println("controller getAllFile error", err.Error())
 		return nil, err
 	}
@@ -492,10 +521,10 @@ func scanTables(ctrldir string) ([]XmlTable, error){
 	//return tables, err
 }
 
-func createVueApisFolder(controllers []XmlController){
-	for i := range controllers{
+func createVueApisFolder(controllers []XmlController) {
+	for i := range controllers {
 		fmt.Println("------------------------------>" + controllers[i].Name)
-		os.MkdirAll("vue/api/modules/" + controllers[i].Name, os.ModePerm)
+		os.MkdirAll("vue/api/modules/"+controllers[i].Name, os.ModePerm)
 	}
 }
 

+ 28 - 0
code_gen/apigen/bean_gen.go

@@ -0,0 +1,28 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+const beanTemplate = `
+package models
+import (
+//__import_packages__
+) 
+
+{{$structName := CamelizeStr .data.Name true}}
+//{{.data.Desc}}
+type {{$structName}} struct {
+	
+	{{range .data.PropList -}}
+	//{{.Caption}}
+	{{CamelizeStr .Name true}}   {{.Type}} {{Backquote}}json:"{{.Name}}"{{Backquote}}
+	{{end}}
+}
+
+func init() {
+	AddTableName("{{.data.Name}}")
+}
+`
+
+func GenBean(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(beanTemplate, templateData, params)
+}

+ 220 - 0
code_gen/apigen/controller_gen.go

@@ -0,0 +1,220 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+/*
+
+type XmlController struct {
+	Name            string   `xml:"name,attr"`
+	Desc            string   `xml:"desc,attr"`
+	Dir             string   `xml:"dir,attr"`
+	SkipLogin       bool     `xml:"skip_login,attr"`
+	Apis            []XmlApi `xml:"api"`
+	ApplicationName string   `xml:"-"`
+	PackageName     string   `xml:"-"`
+}
+
+type XmlApi struct {
+	Name string `xml:"name,attr"`
+	Desc string `xml:"desc,attr"`
+	Method string `xml:"method,attr"`
+	Function string `xml:"function,attr"`//page,tree
+	Table string `xml:"table,attr"`
+	ParamList []XmlApiParam `xml:"param"`
+	Return XmlReturn `xml:"return"`
+}
+
+type XmlApiParam struct {
+	Name string `xml:"name,attr"`
+	TransType string `xml:"trans-type,attr"`
+	Type string `xml:"type,attr"`
+	Desc string `xml:"desc,attr"`
+	Ref string `xml:"ref,attr"`
+	Must bool `xml:"must,attr"`
+	DefaultValue string `xml:"default-value,attr"`
+}
+*/
+
+const controllerTemplate = `
+package gen
+
+import (
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys"
+	"github.com/gin-gonic/gin"
+	
+	"{{.app.ApplicationName}}/controllers/partial/{{.data.Dir}}"
+	
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/engine"
+)
+{{$dataName := CamelizeStr .data.Name true}}
+// {{$dataName}}Controller operations for {{$dataName}}
+type {{$dataName}}Controller struct {
+	apiengine *engine.ApiEngine
+}
+
+func New{{$dataName}}Controller(e *engine.ApiEngine) *{{$dataName}}Controller {
+	controller := &{{$dataName}}Controller{e}
+	return controller
+}
+
+
+{{range .data.Apis}}
+// {{CamelizeStr .Name true}}
+// @Title {{CamelizeStr .Name true}}
+// @Description {{.Desc}}
+{{range .ParamList -}}
+// @Param	{{.Name}}    {{.Type}}  {{.Must}}  "{{.Desc}}"
+{{end -}}
+// @Success 200 {object} sysReturn
+// @Failure 403 :id is empty
+// @router /{{.Name}}  [{{.Method}}]
+func (c *{{$dataName}}Controller) {{CamelizeStr .Name true}}(ctx *gin.Context) {
+	//
+	db:=c.apiengine.BusinessOrmEngine[ctx.GetString("domain")]
+	partial.{{$dataName}}_{{CamelizeStr .Name true}}(&entitys.CtrlContext{c.apiengine, ctx, db, c.apiengine.PlatformOrmEngine})
+}
+{{end}}
+`
+
+func GenController(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(controllerTemplate, templateData, params)
+}
+
+func GenPartial(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(partialTemplate, templateData, params)
+}
+
+const partialTemplate = `
+package partial
+
+
+import (
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys"
+	sysmodel "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
+    sysutils "git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
+	"{{.app.ApplicationName}}/models"
+	//__import_packages__
+)
+
+{{$parentName := .data.Name}}
+{{$dataName := CamelizeStr .data.Name true}}
+{{range .data.Apis}}
+// _{{CamelizeStr .Name true}}
+// @Title _{{CamelizeStr .Name true}}
+// @Description {{.Desc}}         
+{{range .ParamList -}}
+// @Param	{{.Name}}    {{if ne .Type ""}}{{.Type}}{{else}}{{if Contains .Ref "$"}}models.{{CamelizeStr (TrimPrefix .Ref "$") true}}{{end}}{{end}}  {{.Must}}  "{{.Desc}}"
+{{end -}}
+// @Success 200 {object} Account
+// @Failure 403 :id is empty
+func {{$dataName}}_{{CamelizeStr .Name true}}(c *entitys.CtrlContext) {
+{{if eq .Function "add"}}
+	var bean models.{{$dataName}}
+	if err := c.Ctx.ShouldBindJSON(&bean); err != nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	userId := c.Ctx.GetString("user_id")
+
+	bean.CreateBy = userId
+	bean.CreateTime = sysmodel.NowLocal()
+	bean.LastUpdateBy = userId
+	bean.LastUpdateTime = sysmodel.NowLocal()
+	
+	bean.DelFlag = 0
+
+	_, err := c.Db.Insert(&bean)
+	if err == nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", bean.Id})
+	} else {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+	}
+{{else if eq .Function "update"}}
+	var bean models.{{$dataName}}
+	if err := c.Ctx.ShouldBindJSON(&bean); err != nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	userId := c.Ctx.GetString("user_id")
+
+	bean.LastUpdateBy = userId
+	bean.LastUpdateTime = sysmodel.NowLocal()
+
+	_, err := c.Db.ID(bean.Id).Update(&bean)
+	if err != nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		return
+	}
+
+	c.Ctx.JSON(200, sysmodel.SysReturn{200, "", bean.Id})
+{{else if eq .Function "delete"}}
+	var paramObj0 []models.Id 
+	c.Ctx.BindJSON(&paramObj0)
+
+	ret := __none_func_{{$parentName}}__(paramObj0)
+	if ret {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", nil})
+	}else{
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+	}
+{{else if eq .Function "page"}}
+	// 需要引用apiengine v1.1.8版本
+	params := sysutils.GetPageParams(c, []sysutils.PageParam{
+		{"page", "1"},
+		{"rows", "10"},
+	})
+	// 根据业务需求对params进行处理
+
+	if sysutils.CheckExport(c){
+		// 进入导出模式,需要引用apiengine v1.1.8版本
+		// 前端需要配合ExportButton插件
+		exporter := sysutils.NewExcelExporterExt(c, params, "{{$parentName}}", "page")
+		exporter.ExportExt()
+	}else{
+		// 查询模式
+		result, err := sysutils.PageSearch(c.Db,"{{$parentName}}","{{.Name}}", "{{$parentName}}", params)
+		if err == nil {
+			c.Ctx.JSON(200, sysmodel.SysReturn{200, "", result})
+		} else {
+			c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+		}
+	}
+{{else if eq .Function "tree"}}
+	paramMap_i_t := map[string]interface{}{"sort": "name"}
+	result, err := sysutils.TreeSearch(c.Db, "{{$parentName}}","{{.Name}}", "{{$parentName}}", paramMap_i_t)
+	
+	if err == nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", result})
+	} else {
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, err.Error(), nil})
+	}
+{{else}}
+{{- range .ParamList}}
+{{- if Contains .Type "[]"}}
+	var {{.Name}} {{.Type}} 
+	c.Ctx.BindJSON(&{{.Name}})
+{{- else if Contains .Ref "$"}}
+	var {{.Name}} models.{{CamelizeStr (TrimPrefix .Ref "$") true}} 
+	c.Ctx.BindJSON(&{{.Name}})
+{{else}}
+	{{.Name}} := c.Ctx.Query("{{.Name}}")
+{{- end}}
+{{- end}}
+
+	ret := __none_func_{{$parentName}}__({{AllParams .ParamList}})
+	if ret {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", nil})
+	}else{
+		c.Ctx.JSON(200, sysmodel.SysReturn{500, "", nil})
+	}
+{{end -}}
+}
+{{end}}
+
+func __none_func_{{$parentName}}__(params ... interface{}) bool{
+	return true
+}
+
+`

+ 79 - 0
code_gen/apigen/model_gen.go

@@ -0,0 +1,79 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+const modelTemplate = `
+package models
+import (
+	sysmodel "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
+	//__import_packages__
+)
+{{$structName := CamelizeStr .data.Name true}}
+//{{.data.Desc}}
+type {{$structName}} struct {
+
+    {{range .data.ColumnList -}}
+	//{{.Caption}}
+	{{CamelizeStr .Name true}}   {{XormTime .Type}}   {{Backquote}}{{Xorm . | Unescaped}}json:"{{.Name}}"{{Backquote}}
+    {{end}}
+}
+
+func (t *{{$structName}}) TableName() string {
+	return "{{.data.Name}}"
+}
+
+func init() {
+	AddTableName("{{.data.Name}}")
+	RegisterModel(new({{$structName}}))
+}
+`
+
+func GenModel(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(modelTemplate, templateData, params)
+}
+
+func GenModelGo(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	out := utils.Str2bytes(ModelGo)
+	return out, nil
+}
+
+const ModelGo = `
+package models
+
+import (
+	"fmt"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/config"
+	"github.com/xormplus/xorm"
+	"sync"
+)
+
+var beans []interface{}
+var ModelNameList []string
+var beansLock sync.Mutex
+
+func RegisterModel(models ...interface{}) {
+	beansLock.Lock()
+	defer beansLock.Unlock()
+
+	for _, model := range models {
+		beans = append(beans, model)
+	}
+}
+
+func AddTableName(tableName string) {
+	beansLock.Lock()
+	defer beansLock.Unlock()
+
+	ModelNameList = append(ModelNameList, tableName)
+}
+
+func SyncDb(db *xorm.Engine) {
+	if !config.AppConfig.SyncDb {
+		return
+	}
+	err := db.Sync2(beans...)
+	if err != nil {
+		fmt.Println(err)
+	}
+}
+`

+ 96 - 0
code_gen/apigen/router_gen.go

@@ -0,0 +1,96 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+const routerTemplate = `
+package routers
+
+import (
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/engine"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/middleware"
+	"{{.app.ApplicationName}}/controllers/gen"
+)
+
+func init(){
+	addRegisterHandler(register{{CamelizeStr .data.Name true}}Router)
+}
+
+func register{{CamelizeStr .data.Name true}}Router(e *engine.ApiEngine){
+	api:=e.GinEngine.Group("/api")
+	v1:=api.Group("/v1/{{.data.Name}}")
+	v1.Use(middleware.LoginWare())
+	if len(_router["{{.data.Name}}"]) >0 {
+		v1.Use(_router["{{.data.Name}}"]...)
+	}
+	ctrler := gen.New{{CamelizeStr .data.Name true}}Controller(e)
+
+
+{{range .data.Apis}}
+	{{if not (Contains .Method "get")}}//{{end}}v1.GET("/{{.Name}}",ctrler.{{CamelizeStr .Name true}})
+	{{if not (Contains .Method "post")}}//{{end}}v1.POST("/{{.Name}}",ctrler.{{CamelizeStr .Name true}})
+{{end}}
+}
+`
+
+func GenRouter(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(routerTemplate, templateData, params)
+}
+
+func GenRouterGenGo(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(RouterGenGo, templateData, params)
+}
+
+const RouterGenGo = `
+package routers
+
+import (
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/engine"
+    "git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys"
+	"github.com/gin-gonic/gin"
+	"{{.app.ApplicationName}}/models"
+	"sync"
+)
+
+var (
+	_registerHandlers []func(e *engine.ApiEngine) = nil
+	_registerHandlerMutex sync.Mutex
+    _router       map[string][]gin.HandlerFunc
+)
+
+func addRegisterHandler(handler func(e *engine.ApiEngine)){
+	_registerHandlerMutex.Lock()
+	defer _registerHandlerMutex.Unlock()
+	if _registerHandlers == nil{
+		_registerHandlers = make([]func(e *engine.ApiEngine), 0)
+	}
+	_registerHandlers = append(_registerHandlers, handler)
+}
+
+func UseMiddleware(name string, middle ...gin.HandlerFunc) {
+	if _router == nil {
+		_router = make(map[string][]gin.HandlerFunc)
+	}
+	_router[name] =  append(_router[name], middle...)
+}
+
+func Register(e *engine.ApiEngine){
+    e.AddAppMoudleInitFunc("{{.app.ApplicationName}}", DbInitFunc)
+	_registerHandlerMutex.Lock()
+	defer _registerHandlerMutex.Unlock()
+	for i := range _registerHandlers{
+		_registerHandlers[i](e)
+	}
+}
+
+func DbInitFunc(domain string, e entitys.ApiEngineInterface)  {
+	if domain == ""{
+		for _,db := range e.GetAllBusinessDb() {
+			models.SyncDb(db)
+		}
+	}else {
+		db := e.GetBusinessDb(domain)
+		models.SyncDb(db)
+	}
+}
+
+`

+ 38 - 0
code_gen/apigen/sql_gen.go

@@ -0,0 +1,38 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+const sqlTmpl = `
+<sqlMap>
+    <sql id="insert_{{.data.Name}}">
+        INSERT INTO {{.data.Name}}
+		({{SqlAllColumns .data.ColumnList false}})
+		VALUES
+		({{SqlAllColumns .data.ColumnList true}})
+    </sql>
+    <sql id="update_{{.data.Name}}">
+        UPDATE {{.data.Name}} SET
+		{{SqlNoPKUpdate .data.ColumnList}}
+		WHERE {{SqlPKWhere .data.ColumnList}}
+    </sql>
+    <sql id="deleteone_{{.data.Name}}">
+        DELETE FROM {{.data.Name}}
+		WHERE {{SqlPKWhere .data.ColumnList}}
+    </sql>
+    <sql id="selectone_{{.data.Name}}">
+        SELECT
+			{{SqlAllColumns .data.ColumnList false}}
+        FROM {{.data.Name}}
+		WHERE {{SqlPKWhere .data.ColumnList}}
+    </sql>
+    <sql id="selectall_{{.data.Name}}">
+        SELECT
+			{{SqlAllColumns .data.ColumnList false}}
+        FROM {{.data.Name}}
+    </sql>
+</sqlMap>
+`
+
+func GenSql(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(sqlTmpl, templateData, params)
+}

+ 30 - 0
code_gen/apigen/tpl_gen.go

@@ -0,0 +1,30 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+const countTmpl = `
+SELECT
+    count(*) records
+FROM
+    {{.data.Name}}
+WHERE
+    del_flag = 0
+`
+
+const selectTmpl = `
+SELECT
+    {{.data.Name}}.*
+FROM
+    {{.data.Name}}
+WHERE
+    del_flag = 0
+{{Unescaped "LIMIT {{.rows}} OFFSET {{.offset}}"}}
+`
+
+func GenCount(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(countTmpl, templateData, params)
+}
+
+func GenSelect(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(selectTmpl, templateData, params)
+}

+ 38 - 0
code_gen/apigen/vue_gen.go

@@ -0,0 +1,38 @@
+package apigen
+
+import "git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+
+const vueTemplate = `
+import axios from '../../axios'
+
+{{$dataName := .data.Name}}
+{{range .data.Apis}}
+{{if Contains .Method "get" -}}
+// @brief {{.Desc}}
+export const {{CamelizeStr .Name true}} = (data) => {
+	let url = 'api/v1/{{$dataName}}/{{.Name}}?'
+    for (var key in data) {
+		url += key + '=' + data[key] + '&'
+    }
+	return axios({
+		url: url,
+		method: 'get'
+    })
+}
+{{else if Contains .Method "post" -}}
+// @brief {{.Desc}}
+export const {{CamelizeStr .Name true}} = (data) => {
+	let url = 'api/v1/{{$dataName}}/{{.Name}}'
+	return axios({
+		url: url,
+		method: 'post',
+		data
+    })
+}
+{{end -}}
+{{- end}}
+`
+
+func GenVue(templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	return utils.GenTemplate(vueTemplate, templateData, params)
+}

+ 22 - 0
code_gen/cmd/main.go

@@ -0,0 +1,22 @@
+package main
+
+import (
+	"fmt"
+	"i2-erp-backend/code_gen"
+	"os"
+)
+
+func main() {
+	projName := "i2-erp-backend"
+
+	path := "D:\\dev\\Go\\go_path\\src\\i2-erp-backend\\"
+	projDir := fmt.Sprintf("%s%s.proj", path, projName)
+	projMainXmlFileTemp := projDir + "/" + projName + "_temp.xml"
+	_, err := os.Stat(projMainXmlFileTemp)
+	if os.IsNotExist(err) {
+		fmt.Println("-------------------------->remove project main file temp")
+		os.Remove(projMainXmlFileTemp) // remove
+	}
+
+	code_gen.DoGenerate(projMainXmlFileTemp, false)
+}

+ 202 - 0
code_gen/gen.go

@@ -0,0 +1,202 @@
+package code_gen
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/apigen"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine-client/code_gen/utils"
+	"io/ioutil"
+)
+
+/*type ResponeResult struct {
+	Code int32 `json:"code"`
+	//描述
+	Msg string `json:"msg"`
+	//数据
+	Data []GenerateResult `json:"data"`
+}
+type GenerateResult struct {
+	Name    string `json:"name"`
+	Content []byte `json:"content"`
+	Type    string `json:"type"`
+}*/
+
+func DoGenerate(xmlfile string, isCompress bool) []byte {
+
+	bs, _ := ioutil.ReadFile(xmlfile)
+
+	//body := &bytes.Buffer{}
+	//body.Write(bs)
+	app := utils.XmlApplication{}
+
+	err := xml.Unmarshal(bs, &app)
+	if err != nil {
+		fmt.Println(err.Error())
+		return nil
+	}
+
+	//fmt.Println(bs)
+
+	res := utils.ResponeResult{Code: 200, Msg: ""}
+	res.Data = []utils.GenerateResult{}
+
+	tData := map[string]interface{}{}
+	tData["app"] = app
+
+	var gr *utils.GenerateResult
+	for i := 0; i < len(app.Beans.BeanList); i++ {
+		bean := app.Beans.BeanList[i]
+		tData["data"] = bean
+
+		gr = utils.NewResult(
+			"model",
+			fmt.Sprintf("%s/models/%s_gen.go", app.ApplicationName, utils.CamelizeStr(bean.Name, true)),
+			apigen.GenBean,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+
+		//	var b bytes.Buffer
+		//	b.Write(result.Data[i].Content)
+		//	unzip := unzipbytes(&b)
+		//	result.Data[i].Content = unzip.Bytes()
+
+		//model.Content = utils.ZipBytes(res.Data[i].Content)
+	}
+	for i := 0; i < len(app.Controllers.ControllerList); i++ {
+		c := app.Controllers.ControllerList[i]
+		tData["data"] = c
+
+		gr = utils.NewResult(
+			"controllers",
+			fmt.Sprintf("%s/controllers/gen/%sController_gen.go", app.ApplicationName, utils.CamelizeStr(c.Name, true)),
+			apigen.GenController,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+
+		gr = utils.NewResult(
+			"controllers",
+			fmt.Sprintf("%s/controllers/partial/%s/%sController.go", app.ApplicationName, c.Dir, utils.CamelizeStr(c.Name, true)),
+			apigen.GenPartial,
+			tData,
+			isCompress)
+		//fmt.Println(string(gr.Content))
+		res.Data = append(res.Data, *gr)
+
+		gr = utils.NewResult(
+			"routers",
+			fmt.Sprintf("%s/routers/%s_gen.go", app.ApplicationName, c.Name),
+			apigen.GenRouter,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+
+		gr = utils.NewResult(
+			"vue",
+			fmt.Sprintf("%s/vue/api/modules/%s/index.js", app.ApplicationName, c.Name),
+			apigen.GenVue,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+	}
+
+	gr = utils.NewResult(
+		"routers",
+		fmt.Sprintf("%s/routers/router_gen.go", app.ApplicationName),
+		apigen.GenRouterGenGo,
+		tData,
+		isCompress)
+	res.Data = append(res.Data, *gr)
+
+	gr = utils.NewResult(
+		"models",
+		fmt.Sprintf("%s/models/model.go", app.ApplicationName),
+		apigen.GenModelGo,
+		tData,
+		isCompress)
+	res.Data = append(res.Data, *gr)
+
+	for i := 0; i < len(app.Tables.TableList); i++ {
+		table := app.Tables.TableList[i]
+		tData["data"] = table
+
+		gr = utils.NewResult(
+			"models",
+			fmt.Sprintf("%s/models/%s_gen.go", app.ApplicationName, utils.CamelizeStr(table.Name, true)),
+			apigen.GenModel,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+
+		gr = utils.NewResult(
+			"sql",
+			fmt.Sprintf("%s/sqlconfig/%s_controller/%s_page_count.tpl", app.ApplicationName, table.Name, table.Name),
+			apigen.GenCount,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+
+		gr = utils.NewResult(
+			"sql",
+			fmt.Sprintf("%s/sqlconfig/%s_controller/%s_page_select.tpl", app.ApplicationName, table.Name, table.Name),
+			apigen.GenSelect,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+
+		gr = utils.NewResult(
+			"sql",
+			fmt.Sprintf("%s/sqlconfig/%s/%s_gen.xml", app.ApplicationName, app.ApplicationName, table.Name),
+			apigen.GenSql,
+			tData,
+			isCompress)
+		res.Data = append(res.Data, *gr)
+	}
+
+	/*
+		main := utils.GenerateResult{}
+		main.Type = "main"
+		main.Name ="main.go"
+
+		apiTpl := utils.GenerateResult{}
+		apiTpl.Type = "doc"
+		apiTpl.Name ="doc/api.tpl"
+
+		docker := utils.GenerateResult{}
+		docker.Type = "ci"
+		docker.Name ="Dockerfile"
+
+		godep := utils.GenerateResult{}
+		godep.Type = "ci"
+		godep.Name ="godep.yaml"
+
+		gitignore := utils.GenerateResult{}
+		gitignore.Type = "ci"
+		gitignore.Name =".gitignore"
+
+		drone := utils.GenerateResult{}
+		drone.Type = "ci"
+		drone.Name =".drone.yml"
+
+		vue := utils.GenerateResult{}
+		vue.Type = "vue"
+		vue.Name ="vue/api/modules/%s/index.js"
+
+		charts := utils.GenerateResult{}
+		charts.Type = "charts"
+		charts.Name ="charts/values.yaml"
+
+		chartsTmpl := utils.GenerateResult{}
+		chartsTmpl.Type = "charts"
+		chartsTmpl.Name ="charts/templates/config.yaml"
+	*/
+
+	out, err := json.Marshal(res)
+	if err != nil {
+		fmt.Println(err.Error())
+		return nil
+	}
+	return out
+}

+ 37 - 0
code_gen/gen_test.go

@@ -0,0 +1,37 @@
+package code_gen
+
+import (
+	"fmt"
+	"os"
+	"testing"
+)
+
+func TestDoGenerate(t *testing.T) {
+	projName := "i2-erp-backend"
+
+	path := "D:\\dev\\Go\\go_path\\src\\i2-erp-backend\\"
+	projDir := fmt.Sprintf("%s%s.proj", path, projName)
+	projMainXmlFileTemp := projDir + "/" + projName + "_temp.xml"
+	_, err := os.Stat(projMainXmlFileTemp)
+	if os.IsNotExist(err) {
+		fmt.Println("-------------------------->remove project main file temp")
+		os.Remove(projMainXmlFileTemp) // remove
+	}
+
+	DoGenerate(projMainXmlFileTemp, false)
+}
+
+func main() {
+	projName := "i2-erp-backend"
+
+	path := "D:\\dev\\Go\\go_path\\src\\i2-erp-backend\\"
+	projDir := fmt.Sprintf("%s%s.proj", path, projName)
+	projMainXmlFileTemp := projDir + "/" + projName + "_temp.xml"
+	_, err := os.Stat(projMainXmlFileTemp)
+	if os.IsNotExist(err) {
+		fmt.Println("-------------------------->remove project main file temp")
+		os.Remove(projMainXmlFileTemp) // remove
+	}
+
+	DoGenerate(projMainXmlFileTemp, false)
+}

+ 124 - 0
code_gen/utils/struct.go

@@ -0,0 +1,124 @@
+package utils
+
+import(
+	"encoding/xml"
+)
+
+type ResponeResult struct {
+	Code int32 `json:"code"`
+	//描述
+	Msg string `json:"msg"`
+	//数据
+	Data []GenerateResult `json:"data"`
+}
+type GenerateResult struct {
+	Name    string `json:"name"`
+	Content []byte `json:"content"`
+	Type    string `json:"type"`
+}
+
+type XmlApplication struct {
+	XMLName xml.Name `xml:"application"`
+	ApplicationName string `xml:"name,attr"`
+	PackageName string `xml:"packagename,attr"`
+	Desc         string `xml:"desc,attr"`
+	Controllers XmlControllers `xml:"controllers"`
+	Tables      XmlTables      `xml:"tables"`
+	Beans 		XmlBeans       `xml:"beans"`
+}
+
+type XmlControllers struct {
+	ControllerList []XmlController `xml:"controller"`
+}
+
+type XmlController struct {
+	Name            string   `xml:"name,attr"`
+	Desc            string   `xml:"desc,attr"`
+	Dir             string   `xml:"dir,attr"`
+	SkipLogin       bool     `xml:"skip_login,attr"`
+	Apis            []XmlApi `xml:"api"`
+	ApplicationName string   `xml:"-"`
+	PackageName     string   `xml:"-"`
+}
+
+type XmlApi struct {
+	Name string `xml:"name,attr"`
+	Desc string `xml:"desc,attr"`
+	Method string `xml:"method,attr"`
+	Function string `xml:"function,attr"`//page,tree
+	Table string `xml:"table,attr"`
+	ParamList []XmlApiParam `xml:"param"`
+	Return XmlReturn `xml:"return"`
+}
+
+type XmlApiParam struct {
+	Name string `xml:"name,attr"`
+	TransType string `xml:"trans-type,attr"`
+	Type string `xml:"type,attr"`
+	Desc string `xml:"desc,attr"`
+	Ref string `xml:"ref,attr"`
+	Must bool `xml:"must,attr"`
+	DefaultValue string `xml:"default-value,attr"`
+}
+
+type XmlReturn struct {
+	Success XmlSuccess `xml:"success"`
+	Failure XmlFailure `xml:"failure"`
+}
+
+type XmlSuccess struct {
+	Ref string `xml:"ref,attr"`
+	Desc string `xml:"desc,attr"`
+}
+
+type XmlFailure struct {
+	Ref string `xml:"ref,attr"`
+	Desc string `xml:"desc,attr"`
+}
+
+//
+type XmlTables struct {
+	TableList []XmlTable `xml:"table"`
+}
+
+type XmlTable struct {
+	XMLName xml.Name `xml:"table"`
+	Name           string `xml:"name,attr"`
+	Desc           string `xml:"desc,attr"`
+	ImportDateTime bool `xml:"-"`
+	ColumnList        []XmlColumn `xml:"column"`
+}
+
+type XmlColumn struct {
+	Name         string `xml:"name,attr"`
+	Caption      string `xml:"caption,attr"`
+	IsNull       bool   `xml:"isNull,attr"`
+	IsPK         bool   `xml:"isPK,attr"`
+	IsIndex 	 bool 	`xml:"isIndex,attr"`
+	AutoIncrement     bool   `xml:"autoIncrement,attr"`
+	IsUnique     bool   `xml:"isUnique,attr"`
+	Size         int    `xml:"size,attr"`
+	Type         string `xml:"type,attr"`
+	DbType       string `xml:"dbtype,attr"`
+	DefaultValue string `xml:"default-value,attr"`
+}
+
+type XmlBeans struct {
+	BeanList []XmlBean `xml:"bean"`
+}
+
+type XmlBean struct {
+	XMLName xml.Name `xml:"bean"`
+	Name           string `xml:"name,attr"`
+	Desc           string `xml:"desc,attr"`
+	Inher		 string `xml:"inher,attr"`
+	ImportDateTime bool `xml:"-"`
+	PropList        []XmlProp `xml:"prop"`
+}
+
+type XmlProp struct {
+	Name         string `xml:"name,attr"`
+	Caption      string `xml:"caption,attr"`
+	Type         string `xml:"type,attr"`
+	DefaultValue string `xml:"default-value,attr"`
+}

+ 348 - 0
code_gen/utils/utils.go

@@ -0,0 +1,348 @@
+package utils
+
+import (
+	"bytes"
+	"compress/gzip"
+	"errors"
+	"fmt"
+	"go/format"
+	"html/template"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+	"unicode"
+	"unsafe"
+)
+
+var DSNError = errors.New("dsn string error")
+
+func FirstCharacter(name string) string {
+	return strings.ToLower(name)[:1]
+}
+
+func CamelizeStr(s string, upperCase bool) string {
+	if len(s) == 0 {
+		return s
+	}
+	s = replaceInvalidChars(s)
+	var result string
+	words := strings.Split(s, "_")
+	for i, word := range words {
+		//if upper := strings.ToUpper(word); commonInitialisms[upper] {
+		//	result += upper
+		//	continue
+		//}
+		if i > 0 || upperCase {
+			result += camelizeWord(word)
+		} else {
+			result += word
+		}
+	}
+	return result
+}
+
+func camelizeWord(word string) string {
+	runes := []rune(word)
+	for i, r := range runes {
+		if i == 0 {
+			runes[i] = unicode.ToUpper(r)
+		} else {
+			runes[i] = unicode.ToLower(r)
+		}
+	}
+	return string(runes)
+}
+
+func replaceInvalidChars(str string) string {
+	str = strings.ReplaceAll(str, "-", "_")
+	str = strings.ReplaceAll(str, " ", "_")
+	return strings.ReplaceAll(str, ".", "_")
+}
+
+// https://github.com/golang/lint/blob/206c0f020eba0f7fbcfbc467a5eb808037df2ed6/lint.go#L731
+var commonInitialisms = map[string]bool{
+	"ACL":   true,
+	"API":   true,
+	"ASCII": true,
+	"CPU":   true,
+	"CSS":   true,
+	"DNS":   true,
+	"EOF":   true,
+	"ETA":   true,
+	"GPU":   true,
+	"GUID":  true,
+	"HTML":  true,
+	"HTTP":  true,
+	"HTTPS": true,
+	"ID":    true,
+	"IP":    true,
+	"JSON":  true,
+	"LHS":   true,
+	"OS":    true,
+	"QPS":   true,
+	"RAM":   true,
+	"RHS":   true,
+	"RPC":   true,
+	"SLA":   true,
+	"SMTP":  true,
+	"SQL":   true,
+	"SSH":   true,
+	"TCP":   true,
+	"TLS":   true,
+	"TTL":   true,
+	"UDP":   true,
+	"UI":    true,
+	"UID":   true,
+	"UUID":  true,
+	"URI":   true,
+	"URL":   true,
+	"UTF8":  true,
+	"VM":    true,
+	"XML":   true,
+	"XMPP":  true,
+	"XSRF":  true,
+	"XSS":   true,
+	"OAuth": true,
+}
+
+func GetDbNameFromDSN(dsn string) (string, error) {
+	if len(strings.Split(dsn, " ")) > 1 {
+		return getDbNameFromDsn(dsn)
+	}
+	index := strings.LastIndex(dsn, "/")
+	if index <= 0 {
+		return getDbNameFromDsn(dsn)
+	}
+	str := dsn[index:]
+	urlStr, err := url.Parse(str)
+	if err != nil {
+		return "", err
+	}
+	return strings.Trim(urlStr.Path, "/"), nil
+}
+
+// host=127.0.0.1 dbname=test sslmode=disable Timezone=Asia/Shanghai
+const dbNamePrefix = "dbname="
+
+func getDbNameFromDsn(dsn string) (string, error) {
+	strArray := strings.Split(dsn, " ")
+	for _, item := range strArray {
+		if strings.HasPrefix(item, dbNamePrefix) {
+			return strings.TrimPrefix(item, dbNamePrefix), nil
+		}
+	}
+	return "", DSNError
+}
+
+func SaveFile(dirPath, fileName string, text []byte) error {
+	file, err := os.Create(filepath.Join(dirPath, fileName))
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+	p, err := format.Source(text)
+	if err != nil {
+		return err
+	}
+	_, err = file.Write(p)
+	return err
+}
+
+func MkdirPathIfNotExist(dirPath string) error {
+	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
+		return os.MkdirAll(dirPath, os.ModePerm)
+	}
+	return nil
+}
+
+func CleanUpGenFiles(dir string) error {
+	exist, err := FileExists(dir)
+	if err != nil {
+		return err
+	}
+	if exist {
+		return os.RemoveAll(dir)
+	}
+	return nil
+}
+
+// FileExists reports whether the named file or directory exists.
+func FileExists(name string) (bool, error) {
+	if _, err := os.Stat(name); err != nil {
+		if os.IsNotExist(err) {
+			return false, err
+		}
+	}
+	return true, nil
+}
+
+func ZipBytes(data []byte) []byte {
+
+	var out bytes.Buffer
+	w := gzip.NewWriter(&out)
+
+	defer w.Close()
+
+	w.Write(data)
+	w.Flush()
+
+	return out.Bytes()
+}
+
+func UnzipBytes(data []byte) []byte {
+	var in bytes.Buffer
+	in.Write(data)
+
+	r, _ := gzip.NewReader(&in)
+	var out bytes.Buffer
+
+	defer r.Close()
+
+	out.ReadFrom(r)
+
+	return out.Bytes()
+}
+
+func Str2bytes(s string) []byte {
+	x := (*[2]uintptr)(unsafe.Pointer(&s))
+	h := [3]uintptr{x[0], x[1], x[1]}
+	return *(*[]byte)(unsafe.Pointer(&h))
+}
+
+func Bytes2str(b []byte) string {
+	return *(*string)(unsafe.Pointer(&b))
+}
+
+func If(condition bool, trueVal, falseVal interface{}) interface{} {
+	if condition {
+		return trueVal
+	}
+	return falseVal
+}
+
+func NewResult(rType string, rName string, apigen func(templateData interface{}, params map[string]interface{}) ([]byte, error), templateData interface{}, isCompress bool) *GenerateResult {
+	gr := GenerateResult{}
+	gr.Type = rType
+	gr.Name = rName
+
+	genBytes, err := apigen(templateData, nil)
+	if err != nil {
+		fmt.Println(err.Error())
+		return nil
+	}
+	//fmt.Println(string(genBytes))
+	if isCompress {
+		gr.Content = ZipBytes(genBytes)
+	} else {
+		gr.Content = genBytes
+	}
+	return &gr
+}
+
+func GenTemplate(templateText string, templateData interface{}, params map[string]interface{}) ([]byte, error) {
+	t, err := template.New("template").Funcs(template.FuncMap{
+		"CamelizeStr":    CamelizeStr,
+		"FirstCharacter": FirstCharacter,
+		"Replace": func(old, new, src string) string {
+			return strings.ReplaceAll(src, old, new)
+		},
+		"Add": func(a, b int) int {
+			return a + b
+		},
+		"Now": func() string {
+			return time.Now().Format(time.RFC3339)
+		},
+		"Xorm": func(col XmlColumn) string {
+			str := fmt.Sprintf(`xorm:"%s %s %s %s %s %s" `,
+				"'"+col.Name+"'",
+				col.DbType,
+				If(col.IsPK, "pk", ""),
+				If(col.AutoIncrement, "autoincr", ""),
+				If(col.IsNull, "null", "notnull"),
+				If(col.IsUnique, "unique", If(col.IsIndex, "index", "")))
+			return str
+		},
+		"XormTime": func(time string) interface{} {
+			return If(time == "local_time", "sysmodel.LocalTime", time)
+		},
+		"Backquote": func() string {
+			return "`"
+		},
+		// 定义函数unescaped
+		"Unescaped": func(x string) interface{} {
+			return template.HTML(x)
+		},
+		"TrimPrefix": strings.TrimPrefix,
+		"TrimSuffix": strings.TrimSuffix,
+		"Contains": strings.Contains,
+		"AllParams": func(params []XmlApiParam) string {
+			str := ""
+			for i, v := range params {
+				if i > 0 {
+					str += ", "
+				}
+				str += v.Name
+			}
+			return str
+		},
+		"SqlAllColumns": func(cols []XmlColumn, isValues bool) string {
+			str := ""
+			for i, v := range cols {
+				if i > 0 {
+					str += ", "
+				}
+				if isValues {
+					str += "?" + v.Name
+				} else {
+					str += "`" + v.Name + "`"
+				}
+			}
+			return str
+		},
+		"SqlNoPKUpdate": func(cols []XmlColumn) string {
+			str := ""
+			for _, v := range cols {
+				if !v.IsPK {
+					str += "`" + v.Name + "` = ?" + v.Name
+					str += ", "
+				}
+			}
+
+			out := strings.TrimSuffix(str, ", ")
+			return out
+		},
+		"SqlPKWhere": func(cols []XmlColumn) string {
+			str := ""
+			for _, v := range cols {
+				if v.IsPK {
+					str += "`" + v.Name + "` = ?" + v.Name
+					str += " AND "
+				}
+			}
+
+			out := strings.TrimSuffix(str, " AND ")
+			return out
+		},
+		"Param": func(name string) interface{} {
+			if v, ok := params[name]; ok {
+				return v
+			}
+			return ""
+		},
+	}).Parse(templateText)
+
+	if err != nil {
+		fmt.Println(err.Error())
+		return nil, err
+	}
+	var buf bytes.Buffer
+
+	if err := t.Execute(&buf, templateData); err != nil {
+		fmt.Println(err.Error())
+		return nil, err
+	}
+
+	return buf.Bytes(), nil
+}

+ 59 - 0
code_gen/utils/utils_test.go

@@ -0,0 +1,59 @@
+package utils
+
+import "testing"
+
+func TestStrToJsonCamel(t *testing.T) {
+	str1 := "hello_WorLd_hey"
+	if CamelizeStr(str1, false) != "helloWorldHey" {
+		t.Error("string to json camel error")
+	}
+	if CamelizeStr(str1, true) != "HelloWorldHey" {
+		t.Error("string to json camel error")
+	}
+	str1 = "iD"
+	if CamelizeStr(str1, false) != "ID" {
+		t.Error("string to json camel error")
+	}
+	str1 = "my_TeSt_id"
+	if CamelizeStr(str1, false) != "myTestID" {
+		t.Error("string to json camel error")
+	}
+	if CamelizeStr(str1, true) != "MyTestID" {
+		t.Error("string to json camel error")
+	}
+	str1 = "a"
+	if CamelizeStr(str1, false) != "a" {
+		t.Error("string to json camel error")
+	}
+	if CamelizeStr(str1, true) != "A" {
+		t.Error("string to json camel error")
+	}
+}
+
+func TestGetDbNameFromDSN(t *testing.T) {
+	str1 := "postgres://:@127.0.0.1:5432/test?sslmode=disable"
+	dbName, err := GetDbNameFromDSN(str1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if dbName != "test" {
+		t.Fatal("error db name")
+	}
+	str1 = "root:123456@tcp(127.0.0.1:3306)/test?parseTime=true&charset=utf8&loc=Asia%2FShanghai"
+	dbName, err = GetDbNameFromDSN(str1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if dbName != "test" {
+		t.Fatal("error db name")
+	}
+
+	str1 = "host=127.0.0.1 dbname=test sslmode=disable Timezone=Asia/Shanghai"
+	dbName, err = GetDbNameFromDSN(str1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if dbName != "test" {
+		t.Fatal("error db name")
+	}
+}