From f75d8997ef00433c8591cdc8d6c5042408e6068e Mon Sep 17 00:00:00 2001 From: Liujian Date: Tue, 14 Oct 2014 21:30:32 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=9F=BA=E4=BA=8E=E6=95=B0=E6=8D=AE=E5=BA=93=E7=9A=84Hprose?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E6=9C=8D=E5=8A=A1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bee.go | 1 + g_appcode.go | 8 +- g_hproseappcode.go | 685 +++++++++++++++++++++++++++++++++++++++++++++ hproseapp.go | 655 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1348 insertions(+), 1 deletion(-) create mode 100644 g_hproseappcode.go create mode 100644 hproseapp.go diff --git a/bee.go b/bee.go index e8fc482..74dc476 100644 --- a/bee.go +++ b/bee.go @@ -77,6 +77,7 @@ var commands = []*Command{ cmdRun, cmdPack, cmdApiapp, + cmdHproseapp, //cmdRouter, //cmdTest, cmdBale, diff --git a/g_appcode.go b/g_appcode.go index aca7023..8c99375 100644 --- a/g_appcode.go +++ b/g_appcode.go @@ -499,7 +499,13 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin // getGoDataType maps an SQL data type to Golang data type func (*MysqlDB) GetGoDataType(sqlType string) (goType string) { - if v, ok := typeMappingMysql[sqlType]; ok { + var typeMapping = map[string]string{} + if isCreateHproseApp { + typeMapping = typeMappingMysqlOfRpc + } else { + typeMapping = typeMappingMysql + } + if v, ok := typeMapping[sqlType]; ok { return v } else { ColorLog("[ERRO] data type (%s) not found!\n", sqlType) diff --git a/g_hproseappcode.go b/g_hproseappcode.go new file mode 100644 index 0000000..1bd498f --- /dev/null +++ b/g_hproseappcode.go @@ -0,0 +1,685 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * Build rpc application use Hprose base on beego * + * * + * LastModified: Oct 13, 2014 * + * Author: Liu jian * + * * +\**********************************************************/ + +package main + +import ( + "database/sql" + "os" + "path" + "strings" + + _ "github.com/go-sql-driver/mysql" + _ "github.com/lib/pq" +) + +// typeMapping maps SQL data type to corresponding Go data type +var typeMappingMysqlOfRpc = map[string]string{ + "int": "int", // int signed + "integer": "int", + "tinyint": "int8", + "smallint": "int16", + "mediumint": "int32", + "bigint": "int64", + "int unsigned": "uint", // int unsigned + "integer unsigned": "uint", + "tinyint unsigned": "uint8", + "smallint unsigned": "uint16", + "mediumint unsigned": "uint32", + "bigint unsigned": "uint64", + "bit": "uint64", + "bool": "bool", // boolean + "enum": "string", // enum + "set": "string", // set + "varchar": "string", // string & text + "char": "string", + "tinytext": "string", + "mediumtext": "string", + "text": "string", + "longtext": "string", + "blob": "byte", // blob as byte + "tinyblob": "byte", + "mediumblob": "byte", + "longblob": "byte", + "date": "time.Time", // time + "datetime": "time.Time", + "timestamp": "time.Time", + "time": "time.Time", + "float": "float32", // float & decimal + "double": "float64", + "decimal": "float64", + "binary": "string", // binary + "varbinary": "string", +} + +// typeMappingPostgres maps SQL data type to corresponding Go data type +var typeMappingPostgresOfRpc = map[string]string{ + "serial": "int", // serial + "big serial": "int64", + "smallint": "int16", // int + "integer": "int", + "bigint": "int64", + "boolean": "bool", // bool + "char": "string", // string + "character": "string", + "character varying": "string", + "varchar": "string", + "text": "string", + "date": "time.Time", // time + "time": "time.Time", + "timestamp": "time.Time", + "timestamp without time zone": "time.Time", + "interval": "string", // time interval, string for now + "real": "float32", // float & decimal + "double precision": "float64", + "decimal": "float64", + "numeric": "float64", + "money": "float64", // money + "bytea": "byte", // binary + "tsvector": "string", // fulltext + "ARRAY": "string", // array + "USER-DEFINED": "string", // user defined + "uuid": "string", // uuid + "json": "string", // json +} + +func generateHproseAppcode(driver, connStr, level, tables, currpath string) { + var mode byte + switch level { + case "1": + mode = O_MODEL + case "2": + mode = O_MODEL | O_CONTROLLER + case "3": + mode = O_MODEL | O_CONTROLLER | O_ROUTER + default: + ColorLog("[ERRO] Invalid 'level' option: %s\n", level) + ColorLog("[HINT] Level must be either 1, 2 or 3\n") + os.Exit(2) + } + var selectedTables map[string]bool + if tables != "" { + selectedTables = make(map[string]bool) + for _, v := range strings.Split(tables, ",") { + selectedTables[v] = true + } + } + switch driver { + case "mysql": + case "postgres": + case "sqlite": + ColorLog("[ERRO] Generating app code from SQLite database is not supported yet.\n") + os.Exit(2) + default: + ColorLog("[ERRO] Unknown database driver: %s\n", driver) + ColorLog("[HINT] Driver must be one of mysql, postgres or sqlite\n") + os.Exit(2) + } + genHprose(driver, connStr, mode, selectedTables, currpath) +} + +// Generate takes table, column and foreign key information from database connection +// and generate corresponding golang source files +func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bool, currpath string) { + db, err := sql.Open(dbms, connStr) + if err != nil { + ColorLog("[ERRO] Could not connect to %s database: %s, %s\n", dbms, connStr, err) + os.Exit(2) + } + defer db.Close() + if trans, ok := dbDriver[dbms]; ok { + ColorLog("[INFO] Analyzing database tables...\n") + tableNames := trans.GetTableNames(db) + // 添加 Hprose Function + for _, tb := range tableNames { + hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb), -1)) + } + // 添加结束 + tables := getTableObjects(tableNames, db, trans) + mvcPath := new(MvcPath) + mvcPath.ModelPath = path.Join(currpath, "models") + mvcPath.ControllerPath = path.Join(currpath, "controllers") + mvcPath.RouterPath = path.Join(currpath, "routers") + createPaths(mode, mvcPath) + pkgPath := getPackagePath(currpath) + writeHproseSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames) + } else { + ColorLog("[ERRO] Generating app code from %s database is not supported yet.\n", dbms) + os.Exit(2) + } +} + +// writeHproseSourceFiles generates source files for model/controller/router +// It will wipe the following directories and recreate them:./models, ./controllers, ./routers +// Newly geneated files will be inside these folders. +func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) { + if (O_MODEL & mode) == O_MODEL { + ColorLog("[INFO] Creating model files...\n") + writeHproseModelFiles(tables, paths.ModelPath, selectedTables) + } + if (O_CONTROLLER & mode) == O_CONTROLLER { + ColorLog("[INFO] Creating controller files...\n") + writeHproseControllerFiles(tables, paths.ControllerPath, selectedTables, pkgPath) + } + if (O_ROUTER & mode) == O_ROUTER { + ColorLog("[INFO] Creating router files...\n") + writeHproseRouterFile(tables, paths.RouterPath, selectedTables, pkgPath) + } +} + +// writeHproseModelFiles generates model files +func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) { + for _, tb := range tables { + // if selectedTables map is not nil and this table is not selected, ignore it + if selectedTables != nil { + if _, selected := selectedTables[tb.Name]; !selected { + continue + } + } + filename := getFileName(tb.Name) + fpath := path.Join(mPath, filename+".go") + var f *os.File + var err error + if isExist(fpath) { + ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath) + if askForConfirmation() { + f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) + if err != nil { + ColorLog("[WARN] %v\n", err) + continue + } + } else { + ColorLog("[WARN] skip create file\n") + continue + } + } else { + f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) + if err != nil { + ColorLog("[WARN] %v\n", err) + continue + } + } + template := "" + if tb.Pk == "" { + template = HPROSE_STRUCT_MODEL_TPL + } else { + template = HPROSE_MODEL_TPL + } + fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1) + fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1) + // if table contains time field, import time.Time package + timePkg := "" + importTimePkg := "" + if tb.ImportTimePkg { + timePkg = "\"time\"\n" + importTimePkg = "import \"time\"\n" + } + fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1) + fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1) + if _, err := f.WriteString(fileStr); err != nil { + ColorLog("[ERRO] Could not write model file to %s\n", fpath) + os.Exit(2) + } + f.Close() + ColorLog("[INFO] model => %s\n", fpath) + formatSourceCode(fpath) + } +} + +// writeHproseControllerFiles generates controller files +func writeHproseControllerFiles(tables []*Table, cPath string, selectedTables map[string]bool, pkgPath string) { + for _, tb := range tables { + // if selectedTables map is not nil and this table is not selected, ignore it + if selectedTables != nil { + if _, selected := selectedTables[tb.Name]; !selected { + continue + } + } + if tb.Pk == "" { + continue + } + filename := getFileName(tb.Name) + fpath := path.Join(cPath, filename+".go") + var f *os.File + var err error + if isExist(fpath) { + ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath) + if askForConfirmation() { + f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) + if err != nil { + ColorLog("[WARN] %v\n", err) + continue + } + } else { + ColorLog("[WARN] skip create file\n") + continue + } + } else { + f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) + if err != nil { + ColorLog("[WARN] %v\n", err) + continue + } + } + fileStr := strings.Replace(HPROSE_CTRL_TPL, "{{ctrlName}}", camelCase(tb.Name), -1) + fileStr = strings.Replace(fileStr, "{{pkgPath}}", pkgPath, -1) + if _, err := f.WriteString(fileStr); err != nil { + ColorLog("[ERRO] Could not write controller file to %s\n", fpath) + os.Exit(2) + } + f.Close() + ColorLog("[INFO] controller => %s\n", fpath) + formatSourceCode(fpath) + } +} + +// writeHproseRouterFile generates router file +func writeHproseRouterFile(tables []*Table, rPath string, selectedTables map[string]bool, pkgPath string) { + var nameSpaces []string + for _, tb := range tables { + // if selectedTables map is not nil and this table is not selected, ignore it + if selectedTables != nil { + if _, selected := selectedTables[tb.Name]; !selected { + continue + } + } + if tb.Pk == "" { + continue + } + // add name spaces + nameSpace := strings.Replace(HPROSE_NAMESPACE_TPL, "{{nameSpace}}", tb.Name, -1) + nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1) + nameSpaces = append(nameSpaces, nameSpace) + } + // add export controller + fpath := path.Join(rPath, "router.go") + routerStr := strings.Replace(HPROSE_ROUTER_TPL, "{{nameSpaces}}", strings.Join(nameSpaces, ""), 1) + routerStr = strings.Replace(routerStr, "{{pkgPath}}", pkgPath, 1) + var f *os.File + var err error + if isExist(fpath) { + ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath) + if askForConfirmation() { + f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) + if err != nil { + ColorLog("[WARN] %v\n", err) + return + } + } else { + ColorLog("[WARN] skip create file\n") + return + } + } else { + f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) + if err != nil { + ColorLog("[WARN] %v\n", err) + return + } + } + if _, err := f.WriteString(routerStr); err != nil { + ColorLog("[ERRO] Could not write router file to %s\n", fpath) + os.Exit(2) + } + f.Close() + ColorLog("[INFO] router => %s\n", fpath) + formatSourceCode(fpath) +} + +const ( + HPROSE_ADDFUNCTION = ` + // publish about {{modelName}} function + service.AddFunction("Add{{modelName}}", models.Add{{modelName}}) + service.AddFunction("Get{{modelName}}ById", models.Get{{modelName}}ById) + service.AddFunction("GetAll{{modelName}}", models.GetAll{{modelName}}) + service.AddFunction("Update{{modelName}}ById", models.Update{{modelName}}ById) + service.AddFunction("Delete{{modelName}}", models.Delete{{modelName}}) + +` + HPROSE_STRUCT_MODEL_TPL = `package models +{{importTimePkg}} +{{modelStruct}} +` + + HPROSE_MODEL_TPL = `package models + +import ( + "errors" + "fmt" + "reflect" + "strings" + {{timePkg}} + "github.com/astaxie/beego/orm" +) + +{{modelStruct}} + +func init() { + orm.RegisterModel(new({{modelName}})) +} + +// Add{{modelName}} insert a new {{modelName}} into database and returns +// last inserted Id on success. +func Add{{modelName}}(m *{{modelName}}) (id int64, err error) { + o := orm.NewOrm() + id, err = o.Insert(m) + return +} + +// Get{{modelName}}ById retrieves {{modelName}} by Id. Returns error if +// Id doesn't exist +func Get{{modelName}}ById(id int) (v *{{modelName}}, err error) { + o := orm.NewOrm() + v = &{{modelName}}{Id: id} + if err = o.Read(v); err == nil { + return v, nil + } + return nil, err +} + +// GetAll{{modelName}} retrieves all {{modelName}} matches certain condition. Returns empty list if +// no records exist +func GetAll{{modelName}}(query map[string]string, fields []string, sortby []string, order []string, + offset int64, limit int64) (ml []interface{}, err error) { + o := orm.NewOrm() + qs := o.QueryTable(new({{modelName}})) + // query k=v + for k, v := range query { + // rewrite dot-notation to Object__Attribute + k = strings.Replace(k, ".", "__", -1) + qs = qs.Filter(k, v) + } + // order by: + var sortFields []string + if len(sortby) != 0 { + if len(sortby) == len(order) { + // 1) for each sort field, there is an associated order + for i, v := range sortby { + orderby := "" + if order[i] == "desc" { + orderby = "-" + v + } else if order[i] == "asc" { + orderby = v + } else { + return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") + } + sortFields = append(sortFields, orderby) + } + qs = qs.OrderBy(sortFields...) + } else if len(sortby) != len(order) && len(order) == 1 { + // 2) there is exactly one order, all the sorted fields will be sorted by this order + for _, v := range sortby { + orderby := "" + if order[0] == "desc" { + orderby = "-" + v + } else if order[0] == "asc" { + orderby = v + } else { + return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") + } + sortFields = append(sortFields, orderby) + } + } else if len(sortby) != len(order) && len(order) != 1 { + return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") + } + } else { + if len(order) != 0 { + return nil, errors.New("Error: unused 'order' fields") + } + } + + var l []{{modelName}} + qs = qs.OrderBy(sortFields...) + if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil { + if len(fields) == 0 { + for _, v := range l { + ml = append(ml, v) + } + } else { + // trim unused fields + for _, v := range l { + m := make(map[string]interface{}) + val := reflect.ValueOf(v) + for _, fname := range fields { + m[fname] = val.FieldByName(fname).Interface() + } + ml = append(ml, m) + } + } + return ml, nil + } + return nil, err +} + +// Update{{modelName}} updates {{modelName}} by Id and returns error if +// the record to be updated doesn't exist +func Update{{modelName}}ById(m *{{modelName}}) (err error) { + o := orm.NewOrm() + v := {{modelName}}{Id: m.Id} + // ascertain id exists in the database + if err = o.Read(&v); err == nil { + var num int64 + if num, err = o.Update(m); err == nil { + fmt.Println("Number of records updated in database:", num) + } + } + return +} + +// Delete{{modelName}} deletes {{modelName}} by Id and returns error if +// the record to be deleted doesn't exist +func Delete{{modelName}}(id int) (err error) { + o := orm.NewOrm() + v := {{modelName}}{Id: id} + // ascertain id exists in the database + if err = o.Read(&v); err == nil { + var num int64 + if num, err = o.Delete(&{{modelName}}{Id: id}); err == nil { + fmt.Println("Number of records deleted in database:", num) + } + } + return +} +` + HPROSE_CTRL_TPL = `package controllers + +import ( + "{{pkgPath}}/models" + "encoding/json" + "errors" + "strconv" + "strings" + + "github.com/astaxie/beego" +) + +// oprations for {{ctrlName}} +type {{ctrlName}}Controller struct { + beego.Controller +} + +func (this *{{ctrlName}}Controller) URLMapping() { + this.Mapping("Post", this.Post) + this.Mapping("GetOne", this.GetOne) + this.Mapping("GetAll", this.GetAll) + this.Mapping("Put", this.Put) + this.Mapping("Delete", this.Delete) +} + +// @Title Post +// @Description create {{ctrlName}} +// @Param body body models.{{ctrlName}} true "body for {{ctrlName}} content" +// @Success 200 {int} models.{{ctrlName}}.Id +// @Failure 403 body is empty +// @router / [post] +func (this *{{ctrlName}}Controller) Post() { + var v models.{{ctrlName}} + json.Unmarshal(this.Ctx.Input.RequestBody, &v) + if id, err := models.Add{{ctrlName}}(&v); err == nil { + this.Data["json"] = map[string]int64{"id": id} + } else { + this.Data["json"] = err.Error() + } + this.ServeJson() +} + +// @Title Get +// @Description get {{ctrlName}} by id +// @Param id path string true "The key for staticblock" +// @Success 200 {object} models.{{ctrlName}} +// @Failure 403 :id is empty +// @router /:id [get] +func (this *{{ctrlName}}Controller) GetOne() { + idStr := this.Ctx.Input.Params[":id"] + id, _ := strconv.Atoi(idStr) + v, err := models.Get{{ctrlName}}ById(id) + if err != nil { + this.Data["json"] = err.Error() + } else { + this.Data["json"] = v + } + this.ServeJson() +} + +// @Title Get All +// @Description get {{ctrlName}} +// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." +// @Param fields query string false "Fields returned. e.g. col1,col2 ..." +// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." +// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." +// @Param limit query string false "Limit the size of result set. Must be an integer" +// @Param offset query string false "Start position of result set. Must be an integer" +// @Success 200 {object} models.{{ctrlName}} +// @Failure 403 +// @router / [get] +func (this *{{ctrlName}}Controller) GetAll() { + var fields []string + var sortby []string + var order []string + var query map[string]string = make(map[string]string) + var limit int64 = 10 + var offset int64 = 0 + + // fields: col1,col2,entity.col3 + if v := this.GetString("fields"); v != "" { + fields = strings.Split(v, ",") + } + // limit: 10 (default is 10) + if v, err := this.GetInt("limit"); err == nil { + limit = v + } + // offset: 0 (default is 0) + if v, err := this.GetInt("offset"); err == nil { + offset = v + } + // sortby: col1,col2 + if v := this.GetString("sortby"); v != "" { + sortby = strings.Split(v, ",") + } + // order: desc,asc + if v := this.GetString("order"); v != "" { + order = strings.Split(v, ",") + } + // query: k:v,k:v + if v := this.GetString("query"); v != "" { + for _, cond := range strings.Split(v, ",") { + kv := strings.Split(cond, ":") + if len(kv) != 2 { + this.Data["json"] = errors.New("Error: invalid query key/value pair") + this.ServeJson() + return + } + k, v := kv[0], kv[1] + query[k] = v + } + } + + l, err := models.GetAll{{ctrlName}}(query, fields, sortby, order, offset, limit) + if err != nil { + this.Data["json"] = err.Error() + } else { + this.Data["json"] = l + } + this.ServeJson() +} + +// @Title Update +// @Description update the {{ctrlName}} +// @Param id path string true "The id you want to update" +// @Param body body models.{{ctrlName}} true "body for {{ctrlName}} content" +// @Success 200 {object} models.{{ctrlName}} +// @Failure 403 :id is not int +// @router /:id [put] +func (this *{{ctrlName}}Controller) Put() { + idStr := this.Ctx.Input.Params[":id"] + id, _ := strconv.Atoi(idStr) + v := models.{{ctrlName}}{Id: id} + json.Unmarshal(this.Ctx.Input.RequestBody, &v) + if err := models.Update{{ctrlName}}ById(&v); err == nil { + this.Data["json"] = "OK" + } else { + this.Data["json"] = err.Error() + } + this.ServeJson() +} + +// @Title Delete +// @Description delete the {{ctrlName}} +// @Param id path string true "The id you want to delete" +// @Success 200 {string} delete success! +// @Failure 403 id is empty +// @router /:id [delete] +func (this *{{ctrlName}}Controller) Delete() { + idStr := this.Ctx.Input.Params[":id"] + id, _ := strconv.Atoi(idStr) + if err := models.Delete{{ctrlName}}(id); err == nil { + this.Data["json"] = "OK" + } else { + this.Data["json"] = err.Error() + } + this.ServeJson() +} +` + HPROSE_ROUTER_TPL = `// @APIVersion 1.0.0 +// @Title beego Test API +// @Description beego has a very cool tools to autogenerate documents for your API +// @Contact astaxie@gmail.com +// @TermsOfServiceUrl http://beego.me/ +// @License Apache 2.0 +// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html +package routers + +import ( + "{{pkgPath}}/controllers" + + "github.com/astaxie/beego" +) + +func init() { + ns := beego.NewNamespace("/v1", + {{nameSpaces}} + ) + beego.AddNamespace(ns) +} +` + HPROSE_NAMESPACE_TPL = ` + beego.NSNamespace("/{{nameSpace}}", + beego.NSInclude( + &controllers.{{ctrlName}}Controller{}, + ), + ), +` +) diff --git a/hproseapp.go b/hproseapp.go new file mode 100644 index 0000000..f49899a --- /dev/null +++ b/hproseapp.go @@ -0,0 +1,655 @@ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * Build rpc application use Hprose base on beego * + * * + * LastModified: Oct 13, 2014 * + * Author: Liu jian * + * * +\**********************************************************/ + +package main + +import ( + "fmt" + "os" + path "path/filepath" + "strings" +) + +var isCreateHproseApp = false + +var cmdHproseapp = &Command{ + // CustomFlags: true, + UsageLine: "hprose [appname]", + Short: "create an rpc application use hprose base on beego framework", + Long: ` +create an rpc application use hprose base on beego framework + +bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test] + -tables: a list of table names separated by ',', default is empty, indicating all tables + -driver: [mysql | postgres | sqlite], the default is mysql + -conn: the connection string used by the driver, the default is '' + e.g. for mysql: root:@tcp(127.0.0.1:3306)/test + e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres + +if conn is empty will create a example rpc application. otherwise generate rpc application use hprose based on an existing database. + +In the current path, will create a folder named [appname] + +In the appname folder has the follow struct: + + ├── conf + │ └── app.conf + ├── controllers + │ └── object.go + │ └── user.go + ├── routers + │ └── router.go + ├── tests + │ └── default_test.go + ├── main.go + └── models + └── object.go + └── user.go + +## For hprose client URL : http://127.0.0.1:8080/hprose +`, +} + +var hproseconf = `appname = {{.Appname}} +httpport = 8080 +runmode = dev +autorender = false +copyrequestbody = true +EnableDocs = true +` +var hproseMaingo = `package main + +import ( + _ "{{.Appname}}/docs" + "{{.Appname}}/models" + _ "{{.Appname}}/routers" + "github.com/hprose/hprose-go/hprose" + + "github.com/astaxie/beego" +) + +func main() { + if beego.RunMode == "dev" { + beego.DirectoryIndex = true + beego.StaticDir["/swagger"] = "swagger" + } + service := hprose.NewHttpService() + service.AddFunction("AddOne", models.AddOne) + service.AddFunction("GetOne", models.GetOne) + beego.Handler("/hprose", service) + beego.Run() +} +` + +var hproseMainconngo = `package main + +import ( + _ "{{.Appname}}/docs" + "{{.Appname}}/models" + _ "{{.Appname}}/routers" + "github.com/hprose/hprose-go/hprose" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/orm" + {{.DriverPkg}} +) + +func init() { + orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}") +} + +func main() { + if beego.RunMode == "dev" { + beego.DirectoryIndex = true + beego.StaticDir["/swagger"] = "swagger" + } + service := hprose.NewHttpService() + {{HproseFunctionList}} + beego.Handler("/hprose", service) + beego.Run() +} + +` + +var hproserouter = `// @APIVersion 1.0.0 +// @Title beego Test API +// @Description beego has a very cool tools to autogenerate documents for your API +// @Contact astaxie@gmail.com +// @TermsOfServiceUrl http://beego.me/ +// @License Apache 2.0 +// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html +package routers + +import ( + "{{.Appname}}/controllers" + + "github.com/astaxie/beego" +) + +func init() { + ns := beego.NewNamespace("/v1", + beego.NSNamespace("/object", + beego.NSInclude( + &controllers.ObjectController{}, + ), + ), + beego.NSNamespace("/user", + beego.NSInclude( + &controllers.UserController{}, + ), + ), + ) + beego.AddNamespace(ns) +} +` + +var hproseModels = `package models + +import ( + "errors" + "strconv" + "time" +) + +var ( + Objects map[string]*Object +) + +type Object struct { + ObjectId string + Score int64 + PlayerName string +} + +func init() { + Objects = make(map[string]*Object) + Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} + Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} +} + +func AddOne(object Object) (ObjectId string) { + object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) + Objects[object.ObjectId] = &object + return object.ObjectId +} + +func GetOne(ObjectId string) (object *Object, err error) { + if v, ok := Objects[ObjectId]; ok { + return v, nil + } + return nil, errors.New("ObjectId Not Exist") +} + +func GetAll() map[string]*Object { + return Objects +} + +func Update(ObjectId string, Score int64) (err error) { + if v, ok := Objects[ObjectId]; ok { + v.Score = Score + return nil + } + return errors.New("ObjectId Not Exist") +} + +func Delete(ObjectId string) { + delete(Objects, ObjectId) +} + +` + +var hproseModels2 = `package models + +import ( + "errors" + "strconv" + "time" +) + +var ( + UserList map[string]*User +) + +func init() { + UserList = make(map[string]*User) + u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}} + UserList["user_11111"] = &u +} + +type User struct { + Id string + Username string + Password string + Profile Profile +} + +type Profile struct { + Gender string + Age int + Address string + Email string +} + +func AddUser(u User) string { + u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10) + UserList[u.Id] = &u + return u.Id +} + +func GetUser(uid string) (u *User, err error) { + if u, ok := UserList[uid]; ok { + return u, nil + } + return nil, errors.New("User not exists") +} + +func GetAllUsers() map[string]*User { + return UserList +} + +func UpdateUser(uid string, uu *User) (a *User, err error) { + if u, ok := UserList[uid]; ok { + if uu.Username != "" { + u.Username = uu.Username + } + if uu.Password != "" { + u.Password = uu.Password + } + if uu.Profile.Age != 0 { + u.Profile.Age = uu.Profile.Age + } + if uu.Profile.Address != "" { + u.Profile.Address = uu.Profile.Address + } + if uu.Profile.Gender != "" { + u.Profile.Gender = uu.Profile.Gender + } + if uu.Profile.Email != "" { + u.Profile.Email = uu.Profile.Email + } + return u, nil + } + return nil, errors.New("User Not Exist") +} + +func Login(username, password string) bool { + for _, u := range UserList { + if u.Username == username && u.Password == password { + return true + } + } + return false +} + +func DeleteUser(uid string) { + delete(UserList, uid) +} +` + +var hproseControllers = `package controllers + +import ( + "{{.Appname}}/models" + "encoding/json" + + "github.com/astaxie/beego" +) + +// Operations about object +type ObjectController struct { + beego.Controller +} + +// @Title create +// @Description create object +// @Param body body models.Object true "The object content" +// @Success 200 {string} models.Object.Id +// @Failure 403 body is empty +// @router / [post] +func (this *ObjectController) Post() { + var ob models.Object + json.Unmarshal(this.Ctx.Input.RequestBody, &ob) + objectid := models.AddOne(ob) + this.Data["json"] = map[string]string{"ObjectId": objectid} + this.ServeJson() +} + +// @Title Get +// @Description find object by objectid +// @Param objectId path string true "the objectid you want to get" +// @Success 200 {object} models.Object +// @Failure 403 :objectId is empty +// @router /:objectId [get] +func (this *ObjectController) Get() { + objectId := this.Ctx.Input.Params[":objectId"] + if objectId != "" { + ob, err := models.GetOne(objectId) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = ob + } + } + this.ServeJson() +} + +// @Title GetAll +// @Description get all objects +// @Success 200 {object} models.Object +// @Failure 403 :objectId is empty +// @router / [get] +func (this *ObjectController) GetAll() { + obs := models.GetAll() + this.Data["json"] = obs + this.ServeJson() +} + +// @Title update +// @Description update the object +// @Param objectId path string true "The objectid you want to update" +// @Param body body models.Object true "The body" +// @Success 200 {object} models.Object +// @Failure 403 :objectId is empty +// @router /:objectId [put] +func (this *ObjectController) Put() { + objectId := this.Ctx.Input.Params[":objectId"] + var ob models.Object + json.Unmarshal(this.Ctx.Input.RequestBody, &ob) + + err := models.Update(objectId, ob.Score) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = "update success!" + } + this.ServeJson() +} + +// @Title delete +// @Description delete the object +// @Param objectId path string true "The objectId you want to delete" +// @Success 200 {string} delete success! +// @Failure 403 objectId is empty +// @router /:objectId [delete] +func (this *ObjectController) Delete() { + objectId := this.Ctx.Input.Params[":objectId"] + models.Delete(objectId) + this.Data["json"] = "delete success!" + this.ServeJson() +} + +` +var hproseControllers2 = `package controllers + +import ( + "{{.Appname}}/models" + "encoding/json" + + "github.com/astaxie/beego" +) + +// Operations about Users +type UserController struct { + beego.Controller +} + +// @Title createUser +// @Description create users +// @Param body body models.User true "body for user content" +// @Success 200 {int} models.User.Id +// @Failure 403 body is empty +// @router / [post] +func (u *UserController) Post() { + var user models.User + json.Unmarshal(u.Ctx.Input.RequestBody, &user) + uid := models.AddUser(user) + u.Data["json"] = map[string]string{"uid": uid} + u.ServeJson() +} + +// @Title Get +// @Description get all Users +// @Success 200 {object} models.User +// @router / [get] +func (u *UserController) GetAll() { + users := models.GetAllUsers() + u.Data["json"] = users + u.ServeJson() +} + +// @Title Get +// @Description get user by uid +// @Param uid path string true "The key for staticblock" +// @Success 200 {object} models.User +// @Failure 403 :uid is empty +// @router /:uid [get] +func (u *UserController) Get() { + uid := u.GetString(":uid") + if uid != "" { + user, err := models.GetUser(uid) + if err != nil { + u.Data["json"] = err + } else { + u.Data["json"] = user + } + } + u.ServeJson() +} + +// @Title update +// @Description update the user +// @Param uid path string true "The uid you want to update" +// @Param body body models.User true "body for user content" +// @Success 200 {object} models.User +// @Failure 403 :uid is not int +// @router /:uid [put] +func (u *UserController) Put() { + uid := u.GetString(":uid") + if uid != "" { + var user models.User + json.Unmarshal(u.Ctx.Input.RequestBody, &user) + uu, err := models.UpdateUser(uid, &user) + if err != nil { + u.Data["json"] = err + } else { + u.Data["json"] = uu + } + } + u.ServeJson() +} + +// @Title delete +// @Description delete the user +// @Param uid path string true "The uid you want to delete" +// @Success 200 {string} delete success! +// @Failure 403 uid is empty +// @router /:uid [delete] +func (u *UserController) Delete() { + uid := u.GetString(":uid") + models.DeleteUser(uid) + u.Data["json"] = "delete success!" + u.ServeJson() +} + +// @Title login +// @Description Logs user into the system +// @Param username query string true "The username for login" +// @Param password query string true "The password for login" +// @Success 200 {string} lonin success +// @Failure 403 user not exist +// @router /login [get] +func (u *UserController) Login() { + username := u.GetString("username") + password := u.GetString("password") + if models.Login(username, password) { + u.Data["json"] = "login success" + } else { + u.Data["json"] = "user not exist" + } + u.ServeJson() +} + +// @Title logout +// @Description Logs out current logged in user session +// @Success 200 {string} logout success +// @router /logout [get] +func (u *UserController) Logout() { + u.Data["json"] = "logout success" + u.ServeJson() +} + +` + +var hproseTests = `package test + +import ( + "net/http" + "net/http/httptest" + "testing" + "runtime" + "path/filepath" + _ "{{.Appname}}/routers" + + "github.com/astaxie/beego" + . "github.com/smartystreets/goconvey/convey" +) + +func init() { + _, file, _, _ := runtime.Caller(1) + apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator)))) + beego.TestBeegoInit(apppath) +} + +// TestGet is a sample to run an endpoint test +func TestGet(t *testing.T) { + r, _ := http.NewRequest("GET", "/v1/object", nil) + w := httptest.NewRecorder() + beego.BeeApp.Handlers.ServeHTTP(w, r) + + beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String()) + + Convey("Subject: Test Station Endpoint\n", t, func() { + Convey("Status Code Should Be 200", func() { + So(w.Code, ShouldEqual, 200) + }) + Convey("The Result Should Not Be Empty", func() { + So(w.Body.Len(), ShouldBeGreaterThan, 0) + }) + }) +} + +` + +var hproseAddFunctions = []string{} + +func init() { + cmdHproseapp.Run = createhprose + cmdHproseapp.Flag.Var(&tables, "tables", "specify tables to generate model") + cmdHproseapp.Flag.Var(&driver, "driver", "database driver: mysql, postgresql, etc.") + cmdHproseapp.Flag.Var(&conn, "conn", "connection string used by the driver to connect to a database instance") +} + +func createhprose(cmd *Command, args []string) int { + isCreateHproseApp = true + curpath, _ := os.Getwd() + if len(args) > 1 { + cmd.Flag.Parse(args[1:]) + } + apppath, packpath, err := checkEnv(args[0]) + if err != nil { + fmt.Println(err) + os.Exit(2) + } + if driver == "" { + driver = "mysql" + } + if conn == "" { + } + os.MkdirAll(apppath, 0755) + fmt.Println("create app folder:", apppath) + os.Mkdir(path.Join(apppath, "conf"), 0755) + fmt.Println("create conf:", path.Join(apppath, "conf")) + os.Mkdir(path.Join(apppath, "controllers"), 0755) + fmt.Println("create controllers:", path.Join(apppath, "controllers")) + os.Mkdir(path.Join(apppath, "docs"), 0755) + fmt.Println("create docs:", path.Join(apppath, "docs")) + os.Mkdir(path.Join(apppath, "tests"), 0755) + fmt.Println("create tests:", path.Join(apppath, "tests")) + + fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf")) + writetofile(path.Join(apppath, "conf", "app.conf"), + strings.Replace(hproseconf, "{{.Appname}}", args[0], -1)) + + if conn != "" { + ColorLog("[INFO] Using '%s' as 'driver'\n", driver) + ColorLog("[INFO] Using '%s' as 'conn'\n", conn) + ColorLog("[INFO] Using '%s' as 'tables'\n", tables) + generateHproseAppcode(string(driver), string(conn), "3", string(tables), path.Join(curpath, args[0])) + fmt.Println("create main.go:", path.Join(apppath, "main.go")) + maingoContent := strings.Replace(hproseMainconngo, "{{.Appname}}", packpath, -1) + maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1) + maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(hproseAddFunctions, ""), -1) + if driver == "mysql" { + maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1) + } else if driver == "postgres" { + maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1) + } + writetofile(path.Join(apppath, "main.go"), + strings.Replace( + maingoContent, + "{{.conn}}", + conn.String(), + -1, + ), + ) + } else { + os.Mkdir(path.Join(apppath, "models"), 0755) + fmt.Println("create models:", path.Join(apppath, "models")) + os.Mkdir(path.Join(apppath, "routers"), 0755) + fmt.Println(path.Join(apppath, "routers") + string(path.Separator)) + + fmt.Println("create controllers object.go:", path.Join(apppath, "controllers", "object.go")) + writetofile(path.Join(apppath, "controllers", "object.go"), + strings.Replace(hproseControllers, "{{.Appname}}", packpath, -1)) + + fmt.Println("create controllers user.go:", path.Join(apppath, "controllers", "user.go")) + writetofile(path.Join(apppath, "controllers", "user.go"), + strings.Replace(hproseControllers2, "{{.Appname}}", packpath, -1)) + + fmt.Println("create tests default.go:", path.Join(apppath, "tests", "default_test.go")) + writetofile(path.Join(apppath, "tests", "default_test.go"), + strings.Replace(hproseTests, "{{.Appname}}", packpath, -1)) + + fmt.Println("create routers router.go:", path.Join(apppath, "routers", "router.go")) + writetofile(path.Join(apppath, "routers", "router.go"), + strings.Replace(hproserouter, "{{.Appname}}", packpath, -1)) + + fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go")) + writetofile(path.Join(apppath, "models", "object.go"), apiModels) + + fmt.Println("create models user.go:", path.Join(apppath, "models", "user.go")) + writetofile(path.Join(apppath, "models", "user.go"), apiModels2) + + fmt.Println("create docs doc.go:", path.Join(apppath, "docs", "doc.go")) + writetofile(path.Join(apppath, "docs", "doc.go"), "package docs") + + fmt.Println("create main.go:", path.Join(apppath, "main.go")) + writetofile(path.Join(apppath, "main.go"), + strings.Replace(hproseMaingo, "{{.Appname}}", packpath, -1)) + } + return 0 +} From 3dce57e7938d22d87d78fac2cce08e28f2c4abb3 Mon Sep 17 00:00:00 2001 From: Liujian Date: Wed, 15 Oct 2014 10:48:50 +0800 Subject: [PATCH 02/10] Modified mysql blob type. --- g_hproseappcode.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/g_hproseappcode.go b/g_hproseappcode.go index 1bd498f..d1e369e 100644 --- a/g_hproseappcode.go +++ b/g_hproseappcode.go @@ -51,10 +51,10 @@ var typeMappingMysqlOfRpc = map[string]string{ "mediumtext": "string", "text": "string", "longtext": "string", - "blob": "byte", // blob as byte - "tinyblob": "byte", - "mediumblob": "byte", - "longblob": "byte", + "blob": "[]byte", // blob as byte + "tinyblob": "[]byte", + "mediumblob": "[]byte", + "longblob": "[]byte", "date": "time.Time", // time "datetime": "time.Time", "timestamp": "time.Time", @@ -89,7 +89,7 @@ var typeMappingPostgresOfRpc = map[string]string{ "decimal": "float64", "numeric": "float64", "money": "float64", // money - "bytea": "byte", // binary + "bytea": "[]byte", // binary "tsvector": "string", // fulltext "ARRAY": "string", // array "USER-DEFINED": "string", // user defined From eaae7694b883eeabc34520293b17d8298bf082f5 Mon Sep 17 00:00:00 2001 From: Liujian Date: Wed, 15 Oct 2014 13:59:05 +0800 Subject: [PATCH 03/10] Modified bug of use -tables arguments. --- g_hproseappcode.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/g_hproseappcode.go b/g_hproseappcode.go index d1e369e..fc2830d 100644 --- a/g_hproseappcode.go +++ b/g_hproseappcode.go @@ -145,8 +145,16 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo ColorLog("[INFO] Analyzing database tables...\n") tableNames := trans.GetTableNames(db) // 添加 Hprose Function - for _, tb := range tableNames { - hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb), -1)) + if selectedTableNames == nil { + for _, tb := range tableNames { + hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb), -1)) + } + } else { + for tb, v := range selectedTableNames { + if v { + hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb), -1)) + } + } } // 添加结束 tables := getTableObjects(tableNames, db, trans) From adf84eb0602f4b374d7765b273d14d900c6a7aa9 Mon Sep 17 00:00:00 2001 From: Liujian Date: Thu, 16 Oct 2014 21:10:22 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E4=BF=AE=E6=94=B9bee=20hprose=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=8C=E5=8F=AA=E5=8F=91=E5=B8=83hprose?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=EF=BC=8C=E4=B8=8D=E5=8C=85=E5=90=ABRESTful?= =?UTF-8?q?=20Api=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 77 ++++++---- g_hproseappcode.go | 297 --------------------------------------- hproseapp.go | 339 +-------------------------------------------- 3 files changed, 51 insertions(+), 662 deletions(-) diff --git a/README.md b/README.md index 63b793a..6b1d6fb 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,34 @@ bee Bee is a command line tool facilitating development with beego framework. + +## 新增采用 Hprose 发布RPC服务 + + go get github.com/Lao-liu/bee + + bee hprose DbApi -conn=root:@tcp\(127.0.0.1:3306\)/test + OR + bee hprose DbApi -conn=root:@tcp\(127.0.0.1:3306\)/test -tables=tablename + + cd DbApi + + bee run + +#### 浏览器打开 http://127.0.0.1:8080 + + + + ## Requirements - Go version >= 1.1. + ## Installation Begin by installing `bee` using `go get` command. - go get github.com/beego/bee + go get github.com/beego/bee Then you can add `bee` binary to PATH environment variable in your `~/.bashrc` or `~/.bash_profile` file: @@ -23,20 +42,20 @@ export PATH=$PATH:/bin/bee > If you already have `bee` installed, updating `bee` is simple: - go get -u github.com/beego/bee + go get -u github.com/beego/bee ## Basic commands Bee provides a variety of commands which can be helpful at various stage of development. The top level commands include: - new create an application base on beego framework - run run the app which can hot compile - pack compress an beego project - api create an api application base on beego framework - bale packs non-Go files to Go source files - version show the bee & beego version - generate source code generator - migrate run database migrations + new create an application base on beego framework + run run the app which can hot compile + pack compress an beego project + api create an api application base on beego framework + bale packs non-Go files to Go source files + version show the bee & beego version + generate source code generator + migrate run database migrations ## bee version @@ -121,26 +140,26 @@ bee api [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/ -conn: the connection string used by the driver, the default is '' e.g. for mysql: root:@tcp(127.0.0.1:3306)/test e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres - + if conn is empty will create a example api application. otherwise generate api application based on an existing database. In the current path, will create a folder named [appname] In the appname folder has the follow struct: - ├── conf - │ └── app.conf - ├── controllers - │ └── object.go - │ └── user.go - ├── routers - │ └── router.go - ├── tests - │ └── default_test.go - ├── main.go - └── models - └── object.go - └── user.go + ├── conf + │ └── app.conf + ├── controllers + │ └── object.go + │ └── user.go + ├── routers + │ └── router.go + ├── tests + │ └── default_test.go + ├── main.go + └── models + └── object.go + └── user.go ``` ## bee bale @@ -211,7 +230,7 @@ bee generate view [viewpath] bee generate migration [migrationfile] [-fields=""] generate migration file for making database schema update -fields: a list of table fields. Format: field:type, ... - + bee generate docs generate swagger doc file @@ -258,13 +277,13 @@ usage: bee run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] start the appname throw exec.Command then start a inotify watch for current dir - + when the file has changed bee will auto go build and restart the app - file changed - | + file changed + | check if it's go file - | + | yes no | | go build do nothing diff --git a/g_hproseappcode.go b/g_hproseappcode.go index fc2830d..095c139 100644 --- a/g_hproseappcode.go +++ b/g_hproseappcode.go @@ -160,8 +160,6 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo tables := getTableObjects(tableNames, db, trans) mvcPath := new(MvcPath) mvcPath.ModelPath = path.Join(currpath, "models") - mvcPath.ControllerPath = path.Join(currpath, "controllers") - mvcPath.RouterPath = path.Join(currpath, "routers") createPaths(mode, mvcPath) pkgPath := getPackagePath(currpath) writeHproseSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames) @@ -179,14 +177,6 @@ func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *M ColorLog("[INFO] Creating model files...\n") writeHproseModelFiles(tables, paths.ModelPath, selectedTables) } - if (O_CONTROLLER & mode) == O_CONTROLLER { - ColorLog("[INFO] Creating controller files...\n") - writeHproseControllerFiles(tables, paths.ControllerPath, selectedTables, pkgPath) - } - if (O_ROUTER & mode) == O_ROUTER { - ColorLog("[INFO] Creating router files...\n") - writeHproseRouterFile(tables, paths.RouterPath, selectedTables, pkgPath) - } } // writeHproseModelFiles generates model files @@ -248,105 +238,6 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str } } -// writeHproseControllerFiles generates controller files -func writeHproseControllerFiles(tables []*Table, cPath string, selectedTables map[string]bool, pkgPath string) { - for _, tb := range tables { - // if selectedTables map is not nil and this table is not selected, ignore it - if selectedTables != nil { - if _, selected := selectedTables[tb.Name]; !selected { - continue - } - } - if tb.Pk == "" { - continue - } - filename := getFileName(tb.Name) - fpath := path.Join(cPath, filename+".go") - var f *os.File - var err error - if isExist(fpath) { - ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath) - if askForConfirmation() { - f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) - if err != nil { - ColorLog("[WARN] %v\n", err) - continue - } - } else { - ColorLog("[WARN] skip create file\n") - continue - } - } else { - f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) - if err != nil { - ColorLog("[WARN] %v\n", err) - continue - } - } - fileStr := strings.Replace(HPROSE_CTRL_TPL, "{{ctrlName}}", camelCase(tb.Name), -1) - fileStr = strings.Replace(fileStr, "{{pkgPath}}", pkgPath, -1) - if _, err := f.WriteString(fileStr); err != nil { - ColorLog("[ERRO] Could not write controller file to %s\n", fpath) - os.Exit(2) - } - f.Close() - ColorLog("[INFO] controller => %s\n", fpath) - formatSourceCode(fpath) - } -} - -// writeHproseRouterFile generates router file -func writeHproseRouterFile(tables []*Table, rPath string, selectedTables map[string]bool, pkgPath string) { - var nameSpaces []string - for _, tb := range tables { - // if selectedTables map is not nil and this table is not selected, ignore it - if selectedTables != nil { - if _, selected := selectedTables[tb.Name]; !selected { - continue - } - } - if tb.Pk == "" { - continue - } - // add name spaces - nameSpace := strings.Replace(HPROSE_NAMESPACE_TPL, "{{nameSpace}}", tb.Name, -1) - nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1) - nameSpaces = append(nameSpaces, nameSpace) - } - // add export controller - fpath := path.Join(rPath, "router.go") - routerStr := strings.Replace(HPROSE_ROUTER_TPL, "{{nameSpaces}}", strings.Join(nameSpaces, ""), 1) - routerStr = strings.Replace(routerStr, "{{pkgPath}}", pkgPath, 1) - var f *os.File - var err error - if isExist(fpath) { - ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath) - if askForConfirmation() { - f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) - if err != nil { - ColorLog("[WARN] %v\n", err) - return - } - } else { - ColorLog("[WARN] skip create file\n") - return - } - } else { - f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) - if err != nil { - ColorLog("[WARN] %v\n", err) - return - } - } - if _, err := f.WriteString(routerStr); err != nil { - ColorLog("[ERRO] Could not write router file to %s\n", fpath) - os.Exit(2) - } - f.Close() - ColorLog("[INFO] router => %s\n", fpath) - formatSourceCode(fpath) -} - const ( HPROSE_ADDFUNCTION = ` // publish about {{modelName}} function @@ -501,193 +392,5 @@ func Delete{{modelName}}(id int) (err error) { } return } -` - HPROSE_CTRL_TPL = `package controllers - -import ( - "{{pkgPath}}/models" - "encoding/json" - "errors" - "strconv" - "strings" - - "github.com/astaxie/beego" -) - -// oprations for {{ctrlName}} -type {{ctrlName}}Controller struct { - beego.Controller -} - -func (this *{{ctrlName}}Controller) URLMapping() { - this.Mapping("Post", this.Post) - this.Mapping("GetOne", this.GetOne) - this.Mapping("GetAll", this.GetAll) - this.Mapping("Put", this.Put) - this.Mapping("Delete", this.Delete) -} - -// @Title Post -// @Description create {{ctrlName}} -// @Param body body models.{{ctrlName}} true "body for {{ctrlName}} content" -// @Success 200 {int} models.{{ctrlName}}.Id -// @Failure 403 body is empty -// @router / [post] -func (this *{{ctrlName}}Controller) Post() { - var v models.{{ctrlName}} - json.Unmarshal(this.Ctx.Input.RequestBody, &v) - if id, err := models.Add{{ctrlName}}(&v); err == nil { - this.Data["json"] = map[string]int64{"id": id} - } else { - this.Data["json"] = err.Error() - } - this.ServeJson() -} - -// @Title Get -// @Description get {{ctrlName}} by id -// @Param id path string true "The key for staticblock" -// @Success 200 {object} models.{{ctrlName}} -// @Failure 403 :id is empty -// @router /:id [get] -func (this *{{ctrlName}}Controller) GetOne() { - idStr := this.Ctx.Input.Params[":id"] - id, _ := strconv.Atoi(idStr) - v, err := models.Get{{ctrlName}}ById(id) - if err != nil { - this.Data["json"] = err.Error() - } else { - this.Data["json"] = v - } - this.ServeJson() -} - -// @Title Get All -// @Description get {{ctrlName}} -// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." -// @Param fields query string false "Fields returned. e.g. col1,col2 ..." -// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." -// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." -// @Param limit query string false "Limit the size of result set. Must be an integer" -// @Param offset query string false "Start position of result set. Must be an integer" -// @Success 200 {object} models.{{ctrlName}} -// @Failure 403 -// @router / [get] -func (this *{{ctrlName}}Controller) GetAll() { - var fields []string - var sortby []string - var order []string - var query map[string]string = make(map[string]string) - var limit int64 = 10 - var offset int64 = 0 - - // fields: col1,col2,entity.col3 - if v := this.GetString("fields"); v != "" { - fields = strings.Split(v, ",") - } - // limit: 10 (default is 10) - if v, err := this.GetInt("limit"); err == nil { - limit = v - } - // offset: 0 (default is 0) - if v, err := this.GetInt("offset"); err == nil { - offset = v - } - // sortby: col1,col2 - if v := this.GetString("sortby"); v != "" { - sortby = strings.Split(v, ",") - } - // order: desc,asc - if v := this.GetString("order"); v != "" { - order = strings.Split(v, ",") - } - // query: k:v,k:v - if v := this.GetString("query"); v != "" { - for _, cond := range strings.Split(v, ",") { - kv := strings.Split(cond, ":") - if len(kv) != 2 { - this.Data["json"] = errors.New("Error: invalid query key/value pair") - this.ServeJson() - return - } - k, v := kv[0], kv[1] - query[k] = v - } - } - - l, err := models.GetAll{{ctrlName}}(query, fields, sortby, order, offset, limit) - if err != nil { - this.Data["json"] = err.Error() - } else { - this.Data["json"] = l - } - this.ServeJson() -} - -// @Title Update -// @Description update the {{ctrlName}} -// @Param id path string true "The id you want to update" -// @Param body body models.{{ctrlName}} true "body for {{ctrlName}} content" -// @Success 200 {object} models.{{ctrlName}} -// @Failure 403 :id is not int -// @router /:id [put] -func (this *{{ctrlName}}Controller) Put() { - idStr := this.Ctx.Input.Params[":id"] - id, _ := strconv.Atoi(idStr) - v := models.{{ctrlName}}{Id: id} - json.Unmarshal(this.Ctx.Input.RequestBody, &v) - if err := models.Update{{ctrlName}}ById(&v); err == nil { - this.Data["json"] = "OK" - } else { - this.Data["json"] = err.Error() - } - this.ServeJson() -} - -// @Title Delete -// @Description delete the {{ctrlName}} -// @Param id path string true "The id you want to delete" -// @Success 200 {string} delete success! -// @Failure 403 id is empty -// @router /:id [delete] -func (this *{{ctrlName}}Controller) Delete() { - idStr := this.Ctx.Input.Params[":id"] - id, _ := strconv.Atoi(idStr) - if err := models.Delete{{ctrlName}}(id); err == nil { - this.Data["json"] = "OK" - } else { - this.Data["json"] = err.Error() - } - this.ServeJson() -} -` - HPROSE_ROUTER_TPL = `// @APIVersion 1.0.0 -// @Title beego Test API -// @Description beego has a very cool tools to autogenerate documents for your API -// @Contact astaxie@gmail.com -// @TermsOfServiceUrl http://beego.me/ -// @License Apache 2.0 -// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html -package routers - -import ( - "{{pkgPath}}/controllers" - - "github.com/astaxie/beego" -) - -func init() { - ns := beego.NewNamespace("/v1", - {{nameSpaces}} - ) - beego.AddNamespace(ns) -} -` - HPROSE_NAMESPACE_TPL = ` - beego.NSNamespace("/{{nameSpace}}", - beego.NSInclude( - &controllers.{{ctrlName}}Controller{}, - ), - ), ` ) diff --git a/hproseapp.go b/hproseapp.go index f49899a..399208e 100644 --- a/hproseapp.go +++ b/hproseapp.go @@ -48,13 +48,6 @@ In the appname folder has the follow struct: ├── conf │ └── app.conf - ├── controllers - │ └── object.go - │ └── user.go - ├── routers - │ └── router.go - ├── tests - │ └── default_test.go ├── main.go └── models └── object.go @@ -74,23 +67,17 @@ EnableDocs = true var hproseMaingo = `package main import ( - _ "{{.Appname}}/docs" "{{.Appname}}/models" - _ "{{.Appname}}/routers" "github.com/hprose/hprose-go/hprose" "github.com/astaxie/beego" ) func main() { - if beego.RunMode == "dev" { - beego.DirectoryIndex = true - beego.StaticDir["/swagger"] = "swagger" - } service := hprose.NewHttpService() service.AddFunction("AddOne", models.AddOne) service.AddFunction("GetOne", models.GetOne) - beego.Handler("/hprose", service) + beego.Handler("/", service) beego.Run() } ` @@ -98,9 +85,7 @@ func main() { var hproseMainconngo = `package main import ( - _ "{{.Appname}}/docs" "{{.Appname}}/models" - _ "{{.Appname}}/routers" "github.com/hprose/hprose-go/hprose" "github.com/astaxie/beego" @@ -113,50 +98,14 @@ func init() { } func main() { - if beego.RunMode == "dev" { - beego.DirectoryIndex = true - beego.StaticDir["/swagger"] = "swagger" - } service := hprose.NewHttpService() {{HproseFunctionList}} - beego.Handler("/hprose", service) + beego.Handler("/", service) beego.Run() } ` -var hproserouter = `// @APIVersion 1.0.0 -// @Title beego Test API -// @Description beego has a very cool tools to autogenerate documents for your API -// @Contact astaxie@gmail.com -// @TermsOfServiceUrl http://beego.me/ -// @License Apache 2.0 -// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html -package routers - -import ( - "{{.Appname}}/controllers" - - "github.com/astaxie/beego" -) - -func init() { - ns := beego.NewNamespace("/v1", - beego.NSNamespace("/object", - beego.NSInclude( - &controllers.ObjectController{}, - ), - ), - beego.NSNamespace("/user", - beego.NSInclude( - &controllers.UserController{}, - ), - ), - ) - beego.AddNamespace(ns) -} -` - var hproseModels = `package models import ( @@ -300,260 +249,6 @@ func DeleteUser(uid string) { } ` -var hproseControllers = `package controllers - -import ( - "{{.Appname}}/models" - "encoding/json" - - "github.com/astaxie/beego" -) - -// Operations about object -type ObjectController struct { - beego.Controller -} - -// @Title create -// @Description create object -// @Param body body models.Object true "The object content" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router / [post] -func (this *ObjectController) Post() { - var ob models.Object - json.Unmarshal(this.Ctx.Input.RequestBody, &ob) - objectid := models.AddOne(ob) - this.Data["json"] = map[string]string{"ObjectId": objectid} - this.ServeJson() -} - -// @Title Get -// @Description find object by objectid -// @Param objectId path string true "the objectid you want to get" -// @Success 200 {object} models.Object -// @Failure 403 :objectId is empty -// @router /:objectId [get] -func (this *ObjectController) Get() { - objectId := this.Ctx.Input.Params[":objectId"] - if objectId != "" { - ob, err := models.GetOne(objectId) - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = ob - } - } - this.ServeJson() -} - -// @Title GetAll -// @Description get all objects -// @Success 200 {object} models.Object -// @Failure 403 :objectId is empty -// @router / [get] -func (this *ObjectController) GetAll() { - obs := models.GetAll() - this.Data["json"] = obs - this.ServeJson() -} - -// @Title update -// @Description update the object -// @Param objectId path string true "The objectid you want to update" -// @Param body body models.Object true "The body" -// @Success 200 {object} models.Object -// @Failure 403 :objectId is empty -// @router /:objectId [put] -func (this *ObjectController) Put() { - objectId := this.Ctx.Input.Params[":objectId"] - var ob models.Object - json.Unmarshal(this.Ctx.Input.RequestBody, &ob) - - err := models.Update(objectId, ob.Score) - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = "update success!" - } - this.ServeJson() -} - -// @Title delete -// @Description delete the object -// @Param objectId path string true "The objectId you want to delete" -// @Success 200 {string} delete success! -// @Failure 403 objectId is empty -// @router /:objectId [delete] -func (this *ObjectController) Delete() { - objectId := this.Ctx.Input.Params[":objectId"] - models.Delete(objectId) - this.Data["json"] = "delete success!" - this.ServeJson() -} - -` -var hproseControllers2 = `package controllers - -import ( - "{{.Appname}}/models" - "encoding/json" - - "github.com/astaxie/beego" -) - -// Operations about Users -type UserController struct { - beego.Controller -} - -// @Title createUser -// @Description create users -// @Param body body models.User true "body for user content" -// @Success 200 {int} models.User.Id -// @Failure 403 body is empty -// @router / [post] -func (u *UserController) Post() { - var user models.User - json.Unmarshal(u.Ctx.Input.RequestBody, &user) - uid := models.AddUser(user) - u.Data["json"] = map[string]string{"uid": uid} - u.ServeJson() -} - -// @Title Get -// @Description get all Users -// @Success 200 {object} models.User -// @router / [get] -func (u *UserController) GetAll() { - users := models.GetAllUsers() - u.Data["json"] = users - u.ServeJson() -} - -// @Title Get -// @Description get user by uid -// @Param uid path string true "The key for staticblock" -// @Success 200 {object} models.User -// @Failure 403 :uid is empty -// @router /:uid [get] -func (u *UserController) Get() { - uid := u.GetString(":uid") - if uid != "" { - user, err := models.GetUser(uid) - if err != nil { - u.Data["json"] = err - } else { - u.Data["json"] = user - } - } - u.ServeJson() -} - -// @Title update -// @Description update the user -// @Param uid path string true "The uid you want to update" -// @Param body body models.User true "body for user content" -// @Success 200 {object} models.User -// @Failure 403 :uid is not int -// @router /:uid [put] -func (u *UserController) Put() { - uid := u.GetString(":uid") - if uid != "" { - var user models.User - json.Unmarshal(u.Ctx.Input.RequestBody, &user) - uu, err := models.UpdateUser(uid, &user) - if err != nil { - u.Data["json"] = err - } else { - u.Data["json"] = uu - } - } - u.ServeJson() -} - -// @Title delete -// @Description delete the user -// @Param uid path string true "The uid you want to delete" -// @Success 200 {string} delete success! -// @Failure 403 uid is empty -// @router /:uid [delete] -func (u *UserController) Delete() { - uid := u.GetString(":uid") - models.DeleteUser(uid) - u.Data["json"] = "delete success!" - u.ServeJson() -} - -// @Title login -// @Description Logs user into the system -// @Param username query string true "The username for login" -// @Param password query string true "The password for login" -// @Success 200 {string} lonin success -// @Failure 403 user not exist -// @router /login [get] -func (u *UserController) Login() { - username := u.GetString("username") - password := u.GetString("password") - if models.Login(username, password) { - u.Data["json"] = "login success" - } else { - u.Data["json"] = "user not exist" - } - u.ServeJson() -} - -// @Title logout -// @Description Logs out current logged in user session -// @Success 200 {string} logout success -// @router /logout [get] -func (u *UserController) Logout() { - u.Data["json"] = "logout success" - u.ServeJson() -} - -` - -var hproseTests = `package test - -import ( - "net/http" - "net/http/httptest" - "testing" - "runtime" - "path/filepath" - _ "{{.Appname}}/routers" - - "github.com/astaxie/beego" - . "github.com/smartystreets/goconvey/convey" -) - -func init() { - _, file, _, _ := runtime.Caller(1) - apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator)))) - beego.TestBeegoInit(apppath) -} - -// TestGet is a sample to run an endpoint test -func TestGet(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/object", nil) - w := httptest.NewRecorder() - beego.BeeApp.Handlers.ServeHTTP(w, r) - - beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String()) - - Convey("Subject: Test Station Endpoint\n", t, func() { - Convey("Status Code Should Be 200", func() { - So(w.Code, ShouldEqual, 200) - }) - Convey("The Result Should Not Be Empty", func() { - So(w.Body.Len(), ShouldBeGreaterThan, 0) - }) - }) -} - -` - var hproseAddFunctions = []string{} func init() { @@ -583,13 +278,6 @@ func createhprose(cmd *Command, args []string) int { fmt.Println("create app folder:", apppath) os.Mkdir(path.Join(apppath, "conf"), 0755) fmt.Println("create conf:", path.Join(apppath, "conf")) - os.Mkdir(path.Join(apppath, "controllers"), 0755) - fmt.Println("create controllers:", path.Join(apppath, "controllers")) - os.Mkdir(path.Join(apppath, "docs"), 0755) - fmt.Println("create docs:", path.Join(apppath, "docs")) - os.Mkdir(path.Join(apppath, "tests"), 0755) - fmt.Println("create tests:", path.Join(apppath, "tests")) - fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf")) writetofile(path.Join(apppath, "conf", "app.conf"), strings.Replace(hproseconf, "{{.Appname}}", args[0], -1)) @@ -598,7 +286,7 @@ func createhprose(cmd *Command, args []string) int { ColorLog("[INFO] Using '%s' as 'driver'\n", driver) ColorLog("[INFO] Using '%s' as 'conn'\n", conn) ColorLog("[INFO] Using '%s' as 'tables'\n", tables) - generateHproseAppcode(string(driver), string(conn), "3", string(tables), path.Join(curpath, args[0])) + generateHproseAppcode(string(driver), string(conn), "1", string(tables), path.Join(curpath, args[0])) fmt.Println("create main.go:", path.Join(apppath, "main.go")) maingoContent := strings.Replace(hproseMainconngo, "{{.Appname}}", packpath, -1) maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1) @@ -619,24 +307,6 @@ func createhprose(cmd *Command, args []string) int { } else { os.Mkdir(path.Join(apppath, "models"), 0755) fmt.Println("create models:", path.Join(apppath, "models")) - os.Mkdir(path.Join(apppath, "routers"), 0755) - fmt.Println(path.Join(apppath, "routers") + string(path.Separator)) - - fmt.Println("create controllers object.go:", path.Join(apppath, "controllers", "object.go")) - writetofile(path.Join(apppath, "controllers", "object.go"), - strings.Replace(hproseControllers, "{{.Appname}}", packpath, -1)) - - fmt.Println("create controllers user.go:", path.Join(apppath, "controllers", "user.go")) - writetofile(path.Join(apppath, "controllers", "user.go"), - strings.Replace(hproseControllers2, "{{.Appname}}", packpath, -1)) - - fmt.Println("create tests default.go:", path.Join(apppath, "tests", "default_test.go")) - writetofile(path.Join(apppath, "tests", "default_test.go"), - strings.Replace(hproseTests, "{{.Appname}}", packpath, -1)) - - fmt.Println("create routers router.go:", path.Join(apppath, "routers", "router.go")) - writetofile(path.Join(apppath, "routers", "router.go"), - strings.Replace(hproserouter, "{{.Appname}}", packpath, -1)) fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go")) writetofile(path.Join(apppath, "models", "object.go"), apiModels) @@ -644,9 +314,6 @@ func createhprose(cmd *Command, args []string) int { fmt.Println("create models user.go:", path.Join(apppath, "models", "user.go")) writetofile(path.Join(apppath, "models", "user.go"), apiModels2) - fmt.Println("create docs doc.go:", path.Join(apppath, "docs", "doc.go")) - writetofile(path.Join(apppath, "docs", "doc.go"), "package docs") - fmt.Println("create main.go:", path.Join(apppath, "main.go")) writetofile(path.Join(apppath, "main.go"), strings.Replace(hproseMaingo, "{{.Appname}}", packpath, -1)) From 40f2451ca4c0d972d46d7f7c2ee3bdd6ce652ced Mon Sep 17 00:00:00 2001 From: Liujian Date: Thu, 16 Oct 2014 21:13:00 +0800 Subject: [PATCH 05/10] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6b1d6fb..3ffcbaa 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Bee is a command line tool facilitating development with beego framework. ## 新增采用 Hprose 发布RPC服务 +```bash go get github.com/Lao-liu/bee bee hprose DbApi -conn=root:@tcp\(127.0.0.1:3306\)/test @@ -17,6 +18,7 @@ Bee is a command line tool facilitating development with beego framework. cd DbApi bee run +``` #### 浏览器打开 http://127.0.0.1:8080 From 6c40f1a62996420a1af3373111e180e3977d59d4 Mon Sep 17 00:00:00 2001 From: Liujian Date: Thu, 16 Oct 2014 21:36:38 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=BD=93=E8=A1=A8?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E4=B8=BB=E9=94=AE=E6=97=B6bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g_hproseappcode.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/g_hproseappcode.go b/g_hproseappcode.go index 095c139..548e19c 100644 --- a/g_hproseappcode.go +++ b/g_hproseappcode.go @@ -144,19 +144,6 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo if trans, ok := dbDriver[dbms]; ok { ColorLog("[INFO] Analyzing database tables...\n") tableNames := trans.GetTableNames(db) - // 添加 Hprose Function - if selectedTableNames == nil { - for _, tb := range tableNames { - hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb), -1)) - } - } else { - for tb, v := range selectedTableNames { - if v { - hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb), -1)) - } - } - } - // 添加结束 tables := getTableObjects(tableNames, db, trans) mvcPath := new(MvcPath) mvcPath.ModelPath = path.Join(currpath, "models") @@ -216,6 +203,7 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str template = HPROSE_STRUCT_MODEL_TPL } else { template = HPROSE_MODEL_TPL + hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb.Name), -1)) } fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1) fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1) From 7dfe63055e7852fb5ed5a6764d947b52ba954165 Mon Sep 17 00:00:00 2001 From: Liujian Date: Thu, 16 Oct 2014 21:41:25 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E6=9B=B4=E6=96=B0Help=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hproseapp.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/hproseapp.go b/hproseapp.go index 399208e..4a7479d 100644 --- a/hproseapp.go +++ b/hproseapp.go @@ -52,8 +52,6 @@ In the appname folder has the follow struct: └── models └── object.go └── user.go - -## For hprose client URL : http://127.0.0.1:8080/hprose `, } From 2e7cd9b414ce2b4df90ac468df07548b15651dca Mon Sep 17 00:00:00 2001 From: Liujian Date: Thu, 23 Oct 2014 13:09:22 +0800 Subject: [PATCH 08/10] 1. remove unused typeMappingMysqlOfRpc type. 2. update README.md --- README.md | 49 ++++++++++++++++++------------- g_appcode.go | 6 +--- g_hproseappcode.go | 72 +--------------------------------------------- hproseapp.go | 3 -- 4 files changed, 31 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 3ffcbaa..d7033d5 100644 --- a/README.md +++ b/README.md @@ -5,26 +5,6 @@ bee Bee is a command line tool facilitating development with beego framework. - -## 新增采用 Hprose 发布RPC服务 - -```bash - go get github.com/Lao-liu/bee - - bee hprose DbApi -conn=root:@tcp\(127.0.0.1:3306\)/test - OR - bee hprose DbApi -conn=root:@tcp\(127.0.0.1:3306\)/test -tables=tablename - - cd DbApi - - bee run -``` - -#### 浏览器打开 http://127.0.0.1:8080 - - - - ## Requirements - Go version >= 1.1. @@ -164,6 +144,35 @@ In the appname folder has the follow struct: └── user.go ``` +## bee hprose + +```bash +usage: bee hprose [appname] + +create an rpc application use hprose base on beego framework + +bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test] + -tables: a list of table names separated by ',', default is empty, indicating all tables + -driver: [mysql | postgres | sqlite], the default is mysql + -conn: the connection string used by the driver, the default is '' + e.g. for mysql: root:@tcp(127.0.0.1:3306)/test + e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres + +if conn is empty will create a example rpc application. otherwise generate rpc application use hprose based on an existing database. + +In the current path, will create a folder named [appname] + +In the appname folder has the follow struct: + + ├── conf + │ └── app.conf + ├── main.go + └── models + └── object.go + └── user.go + +``` + ## bee bale ```bash diff --git a/g_appcode.go b/g_appcode.go index 8c99375..5517014 100644 --- a/g_appcode.go +++ b/g_appcode.go @@ -500,11 +500,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin // getGoDataType maps an SQL data type to Golang data type func (*MysqlDB) GetGoDataType(sqlType string) (goType string) { var typeMapping = map[string]string{} - if isCreateHproseApp { - typeMapping = typeMappingMysqlOfRpc - } else { - typeMapping = typeMappingMysql - } + typeMapping = typeMappingMysql if v, ok := typeMapping[sqlType]; ok { return v } else { diff --git a/g_hproseappcode.go b/g_hproseappcode.go index 548e19c..86e3d02 100644 --- a/g_hproseappcode.go +++ b/g_hproseappcode.go @@ -10,7 +10,7 @@ * * * Build rpc application use Hprose base on beego * * * - * LastModified: Oct 13, 2014 * + * LastModified: Oct 23, 2014 * * Author: Liu jian * * * \**********************************************************/ @@ -27,76 +27,6 @@ import ( _ "github.com/lib/pq" ) -// typeMapping maps SQL data type to corresponding Go data type -var typeMappingMysqlOfRpc = map[string]string{ - "int": "int", // int signed - "integer": "int", - "tinyint": "int8", - "smallint": "int16", - "mediumint": "int32", - "bigint": "int64", - "int unsigned": "uint", // int unsigned - "integer unsigned": "uint", - "tinyint unsigned": "uint8", - "smallint unsigned": "uint16", - "mediumint unsigned": "uint32", - "bigint unsigned": "uint64", - "bit": "uint64", - "bool": "bool", // boolean - "enum": "string", // enum - "set": "string", // set - "varchar": "string", // string & text - "char": "string", - "tinytext": "string", - "mediumtext": "string", - "text": "string", - "longtext": "string", - "blob": "[]byte", // blob as byte - "tinyblob": "[]byte", - "mediumblob": "[]byte", - "longblob": "[]byte", - "date": "time.Time", // time - "datetime": "time.Time", - "timestamp": "time.Time", - "time": "time.Time", - "float": "float32", // float & decimal - "double": "float64", - "decimal": "float64", - "binary": "string", // binary - "varbinary": "string", -} - -// typeMappingPostgres maps SQL data type to corresponding Go data type -var typeMappingPostgresOfRpc = map[string]string{ - "serial": "int", // serial - "big serial": "int64", - "smallint": "int16", // int - "integer": "int", - "bigint": "int64", - "boolean": "bool", // bool - "char": "string", // string - "character": "string", - "character varying": "string", - "varchar": "string", - "text": "string", - "date": "time.Time", // time - "time": "time.Time", - "timestamp": "time.Time", - "timestamp without time zone": "time.Time", - "interval": "string", // time interval, string for now - "real": "float32", // float & decimal - "double precision": "float64", - "decimal": "float64", - "numeric": "float64", - "money": "float64", // money - "bytea": "[]byte", // binary - "tsvector": "string", // fulltext - "ARRAY": "string", // array - "USER-DEFINED": "string", // user defined - "uuid": "string", // uuid - "json": "string", // json -} - func generateHproseAppcode(driver, connStr, level, tables, currpath string) { var mode byte switch level { diff --git a/hproseapp.go b/hproseapp.go index 4a7479d..5167c31 100644 --- a/hproseapp.go +++ b/hproseapp.go @@ -24,8 +24,6 @@ import ( "strings" ) -var isCreateHproseApp = false - var cmdHproseapp = &Command{ // CustomFlags: true, UsageLine: "hprose [appname]", @@ -257,7 +255,6 @@ func init() { } func createhprose(cmd *Command, args []string) int { - isCreateHproseApp = true curpath, _ := os.Getwd() if len(args) > 1 { cmd.Flag.Parse(args[1:]) From 76cbc8a3cc97deda3627f71c9210b2fa69196a2c Mon Sep 17 00:00:00 2001 From: Liujian Date: Fri, 31 Oct 2014 13:50:11 +0800 Subject: [PATCH 09/10] update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7033d5..76cfa2b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,9 @@ Bee is a command line tool facilitating development with beego framework. Begin by installing `bee` using `go get` command. - go get github.com/beego/bee +```bash +go get github.com/beego/bee +``` Then you can add `bee` binary to PATH environment variable in your `~/.bashrc` or `~/.bash_profile` file: @@ -24,7 +26,9 @@ export PATH=$PATH:/bin/bee > If you already have `bee` installed, updating `bee` is simple: - go get -u github.com/beego/bee +```bash +go get -u github.com/beego/bee +``` ## Basic commands @@ -38,6 +42,7 @@ Bee provides a variety of commands which can be helpful at various stage of deve version show the bee & beego version generate source code generator migrate run database migrations + hprose create an rpc application use hprose base on beego framework ## bee version From 7c2c95b325776f1876e350c715d36d2d1a5ec410 Mon Sep 17 00:00:00 2001 From: Liujian Date: Fri, 31 Oct 2014 13:53:48 +0800 Subject: [PATCH 10/10] update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 76cfa2b..cd0d18a 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ go get -u github.com/beego/bee ## Basic commands Bee provides a variety of commands which can be helpful at various stage of development. The top level commands include: - +```base new create an application base on beego framework run run the app which can hot compile pack compress an beego project @@ -43,7 +43,7 @@ Bee provides a variety of commands which can be helpful at various stage of deve generate source code generator migrate run database migrations hprose create an rpc application use hprose base on beego framework - +``` ## bee version The first command is the easiest: displaying which version of `bee`, `beego` and `go` is installed on your machine: