1 Star 0 Fork 1

zhouli1369/go2struct

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
main.go 9.35 KB
一键复制 编辑 原始数据 按行查看 历史
zhouli 提交于 4年前 . 调整参数
package main
import (
"bytes"
"fmt"
"gitee.com/nickchou/go2struct/dbms"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"html/template"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
"time"
)
//Dbo 数据库链接
var Dbo *gorm.DB
//go run main.go mysql "root:123456@(127.0.0.1:3306)/scriptdb?charset=utf8" ./tpl/gorm.tpl ./models
func main() {
driver := "" //Mysql驱动,目前只支持mysql
sqlconn := "" //数据库链接
tplPath := "" //模板文件位置 ./template/gorm.tpl
goPath := "" //生成出来的go代码存放位置,不传的话生成在当前文件夹下
dbname := "" //数据库名称,根据连接字符串自动算出来
dbInfo := &dbms.DbInfo{}
//curPath, _ := os.Getwd()
//fmt.Println(curPath)
//打印参数,第0个参数是exe的路径
if len(os.Args) < 4 {
fmt.Println("参数不全!!")
return
} else {
driver = os.Args[1]
sqlconn = os.Args[2]
tplPath = os.Args[3]
fmt.Println("driver :", driver)
fmt.Println("sqlconn:", sqlconn)
fmt.Println("tplPath:", tplPath)
}
if len(os.Args) > 4 {
goPath = os.Args[4]
fmt.Println("2models:", goPath)
}
//获取要生成模板的绝对路径
genDir, _ := filepath.Abs(goPath)
fmt.Println("curr_dir:", genDir)
//return
//获取实体类的命名空间,注意:path.Base不能解析windows下的“\”,需要替换为“/”
goNameSapce := path.Base(strings.Replace(genDir, "\\", "/", -1))
//fmt.Println("goNameSapce:", goNameSapce)
//setp 1、初始化数据库连接
initDB(driver, sqlconn)
//setp 2、获取数据库所有的表和列,并初始化好命名空间
dbname = getDBName(driver, sqlconn)
tables, err := getDataBaseInfo(goNameSapce, dbname)
if err != nil {
fmt.Println("Now there's an exception:")
fmt.Println(err.Error())
} else {
dbInfo.DbTables = tables
//dbInfo.DbColumns = columns
//fmt.Println(dbInfo.DbTables)
//fmt.Println("==================================")
//fmt.Println(dbInfo.DbColumns)
//读取模板生成模板
tplBytes, err := ioutil.ReadFile(tplPath)
if err != nil {
fmt.Println("读取模板文件错误:", err)
return
}
//模板文件字符串
tplStr := string(tplBytes)
//fmt.Println(tplStr)
//new 模板,命名temHtml
tplFile, _ := template.New("temHtml").Parse(tplStr)
//判断文件夹是否存在,不存在才创建
_, err = os.Stat(genDir)
if err != nil || os.IsNotExist(err) {
//创建多级目录
os.MkdirAll(genDir, os.ModePerm)
fmt.Println("> Folder does not exist, created!!")
} else {
fmt.Println("> The folder already exists.")
}
//生成之前先删除原来的文件
delDir, err := ioutil.ReadDir(genDir)
for _, d := range delDir {
os.RemoveAll(path.Join([]string{genDir, d.Name()}...))
}
//遍历表,生成实体
for i, table := range dbInfo.DbTables {
fmt.Println(i+1, "/", len(dbInfo.DbTables), table.TableName)
// if i > 0 {
// break
// }
//根据模板生成最终数据
buf := new(bytes.Buffer)
tplFile.Execute(buf, table)
//fmt.Println(buf.String())
//生成go文件路径
currFile := path.Join(genDir, fmt.Sprintf("%s%s", table.GoName, ".go"))
f, err := os.Create(currFile)
defer f.Close()
if err == nil {
//保存文件
f.Write([]byte(buf.String()))
} else {
fmt.Println(err)
}
}
formatGoFile(genDir)
}
}
//根据驱动和连接字符串获取数据库名
func getDBName(driver string, sqlconn string) string {
dbname := ""
if driver == "mysql" {
reg, err := regexp.Compile("/(\\w+)")
if err == nil {
dbname = reg.FindStringSubmatch(sqlconn)[1]
fmt.Println("database:", dbname)
}
}
return dbname
}
//formatGoFile 格式化go文件
func formatGoFile(gofilePath string) {
var stdout bytes.Buffer
var stderr bytes.Buffer
gofilePath = strings.Replace(gofilePath, "\\", "/", -1)
//命令不认识window下的"\"符号,需要转换成"/"
cmdStr := fmt.Sprintf("gofmt -l -w -s %s", gofilePath)
fmt.Println(cmdStr)
cmd := exec.Command("sh", "-c", cmdStr)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
fmt.Println("format go file failed!")
} else {
fmt.Println("format go file success!")
}
}
//initdb 初始化数据库连接池
func initDB(driver string, sqlconn string) {
var err error
//Dbo, err = gorm.Open(driver, sqlconn)
var gormConfig gorm.Config
gormConfig.Logger = logger.Default.LogMode(logger.Info)
Dbo, err = gorm.Open(mysql.Open(sqlconn), &gormConfig)
if err != nil {
panic(err)
} else {
sqlDB, err := Dbo.DB()
if err == nil && sqlDB != nil {
sqlDB.SetMaxIdleConns(10)
//设置最大的数据库连接数,默认值=0(没有限制)
//Dbo.DB().SetMaxOpenConns(10)
sqlDB.SetMaxOpenConns(20)
//设置连接可复用的最大时间
sqlDB.SetConnMaxLifetime(-1)
//ping数据库
//err = Dbo.DB().Ping()
err = sqlDB.Ping()
if err != nil {
panic(err)
} else {
ConsoleLog("system", fmt.Sprintf("%s database is connected.", driver))
}
}
}
}
func ConsoleLog(tag string, content string) {
fmt.Println(fmt.Sprintf("[%s] [%s] %s", time.Now().Format("2006-01-02 15:04:05.000"), tag, content))
}
//getDataBaseInfo 获取数据库的表、列名等
func getDataBaseInfo(spaceName string, dbname string) (tables []dbms.Tables, err error) {
//Dbo.Raw("SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=? ORDER BY TABLE_NAME ASC;", dbname).Scan(&tables)
Dbo.Table("information_schema.TABLES").Select("TABLE_SCHEMA,TABLE_NAME,TABLE_COMMENT").Where("TABLE_SCHEMA=?", dbname).Order("TABLE_NAME ASC").Scan(&tables)
//fmt.Println("================================chashjuj======================================")
//fmt.Println(tables)
//查所有列信息
var columns []dbms.Columns
//err = Dbo.Raw("SELECT TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,COLUMN_KEY,ORDINAL_POSITION,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_TYPE,EXTRA,COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME,ORDINAL_POSITION ASC;", dbname).Scan(&columns).Error
err = Dbo.Table("information_schema.COLUMNS").Select("TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,COLUMN_KEY,ORDINAL_POSITION,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_TYPE,EXTRA,COLUMN_COMMENT").Where("TABLE_SCHEMA=?", dbname).Order("TABLE_NAME,ORDINAL_POSITION ASC").Scan(&columns).Error
//fmt.Println("======================================================================")
//fmt.Println(columns)
//循环列信息,映射golang数据类型
for j := range columns {
columns[j].GoName = toUpperCamelCase(columns[j].ColumnName) //格式化列名
columns[j].JsonName = toLowerCamelCase(columns[j].ColumnName) //格式化列名
columns[j].GoType = objcTypeStr(columns[j].DataType) //数据库类型转golang类型
}
var k int = 0
//循环表信息,设置命名空间,并把表的列名都添加进去方便template使用
for i := range tables {
tables[i].PackageName = spaceName
tables[i].GoName = toUpperCamelCase(tables[i].TableName) //格式化表名
tables[i].Imports = make(map[string]string) //初始化当前表的包
//这里减少了重复循环,前提是表名、列名里的TABLE_NAME排过序的,否则会有问题
for ; k < len(columns); k++ {
if tables[i].TableName == columns[k].TableName {
//把列名添加到表的数据结构里
tables[i].TableColumns = append(tables[i].TableColumns, columns[k])
//====下面是添加包的逻辑
if _, ok := tables[i].Imports["time"]; !ok && columns[k].GoType == "time.Time" {
//判断表中的Packages是否已经存在time,不存在就添加time包
tables[i].Imports["time"] = "time"
}
} else {
break
}
}
}
return
}
func objcTypeStr(columnType string) string {
goType := ""
switch columnType {
case "bit", "tinyint", "smallint", "mediumint", "int", "integer", "serial":
goType = "int32"
break
case "bigint", "bigserial":
goType = "int64"
break
case "char", "varchar", "tinytext", "text", "mediumtext", "longtext", "json":
goType = "string"
break
case "date", "datetime", "time", "timestamp":
goType = "time.Time"
break
case "decimal", "numeric":
goType = "float64"
break
case "real", "float":
goType = "float64"
break
case "double":
goType = "float64"
break
case "tinyblob", "blob", "mediumblob", "longblob", "bytea":
goType = "string"
break
case "bool":
goType = "bool"
break
default:
goType = "string"
}
return goType
}
// 大驼峰式命名法,例如:FirstName、LastName
func toUpperCamelCase(name string) string {
newstr := make([]rune, 0)
upNextChar := true
name = strings.ToLower(name)
for _, chr := range name {
switch {
case upNextChar:
upNextChar = false
if 'a' <= chr && chr <= 'z' {
chr -= 'a' - 'A'
}
case chr == '_':
upNextChar = true
continue
}
newstr = append(newstr, chr)
}
newName := strings.Replace(string(newstr), ".", "_", -1)
return newName
}
// 小驼峰式命名法,例如:firstName、lastName
func toLowerCamelCase(s string) string {
data := make([]byte, 0, len(s))
j := false
k := false
num := len(s) - 1
for i := 0; i <= num; i++ {
d := s[i]
if k == false && d >= 'A' && d <= 'Z' {
k = true
}
if d >= 'a' && d <= 'z' && (j || k == false) {
if i != 0 {
d = d - 32
}
j = false
k = true
}
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
j = true
continue
}
data = append(data, d)
}
return string(data[:])
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zhouli1369/go2struct.git
git@gitee.com:zhouli1369/go2struct.git
zhouli1369
go2struct
go2struct
v1.4.0

搜索帮助