因为项目转go,觉得写model和json很重复,所以简单写了个工具类
项目全局
先定义数据库类和数据库链接
package conf
// model保存路径
const ModelPath = "./models/"
// json保存路径
const JsonPath = "./reply/"
type DbConf struct {
Host string
Port string
User string
Pwd string
DbName string
}
// 数据库链接配置
var MasterDbConfig DbConf = DbConf{
Host: "127.0.0.1",
Port: "3306",
User: "ss",
Pwd: "ss",
DbName: "ss",
}
gorm的数据库链接
package db
import (
"cn.saas/charge-xxx/conf"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var Instance *gorm.DB
func Init() {
dsn := fmt.Sprintf(
"%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
conf.MasterDbConfig.User,
conf.MasterDbConfig.Pwd,
conf.MasterDbConfig.Host,
conf.MasterDbConfig.DbName,
)
var err error
Instance, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
}
项目下创建两个文件夹,models和reply
定义查询语句的model类
package generate
type Field struct {
Field string `gorm:"column:Field"`
Type string `gorm:"column:Type"`
Null string `gorm:"column:Null"`
Key string `gorm:"column:Key"`
Default string `gorm:"column:Default"`
Extra string `gorm:"column:Extra"`
Privileges string `gorm:"column:Privileges"`
Comment string `gorm:"column:Comment"`
}
package generate
type Table struct {
Name string `gorm:"column:Name"`
Comment string `gorm:"column:Comment"`
}
最后就是生成方法了
package generate
import (
"cn.saas/charge-xxx/conf"
"cn.saas/charge-xxx/db"
"fmt"
"github.com/golang/protobuf/protoc-gen-go/generator"
"io"
"os"
"strings"
"unicode"
)
func Generate(tableNames ...string) {
tableNamesStr := ""
for _, name := range tableNames {
if tableNamesStr != "" {
tableNamesStr += ","
}
tableNamesStr += "'" + name + "'"
}
tables := getTables(tableNamesStr) //生成所有表信息
ch := make(chan int)
for _, table := range tables {
fields := getFields(table.Name)
go generateModel(table, fields)
go generateJSON(table, fields, ch)
}
fmt.Println(<-ch)
}
//获取表信息
func getTables(tableNames string) []Table {
query := db.Instance.Debug()
var tables []Table
if tableNames == "" {
query.Raw("SELECT TABLE_NAME as Name,TABLE_COMMENT as Comment FROM information_schema.TABLES WHERE table_schema='" + conf.MasterDbConfig.DbName + "';").Find(&tables)
}
return tables
}
//获取所有字段信息
func getFields(tableName string) []Field {
query := db.Instance.Debug()
var fields []Field
query.Raw("show FULL COLUMNS from " + tableName + ";").Find(&fields)
return fields
}
//生成Model
func generateModel(table Table, fields []Field) {
content := "package models\n\n"
//表注释
if len(table.Comment) > 0 {
content += "// " + table.Comment + "\n"
}
content += "type " + generator.CamelCase(table.Name) + " struct {\n"
//生成字段
for _, field := range fields {
fieldName := generator.CamelCase(field.Field)
//fieldJson := getFieldJson(field)
fieldGorm := getFieldGorm(field)
fieldType := getFiledType(field)
fieldComment := getFieldComment(field)
content += " " + fieldName + " " + fieldType + " `" + fieldGorm + "` " + fieldComment + "\n"
}
content += "}\n"
content += "func (entity *" + generator.CamelCase(table.Name) + ") TableName() string {\n"
content += " " + `return "` + table.Name + `"`
content += "\n}"
filename := conf.ModelPath + table.Name + ".go"
var f *os.File
var err error
if checkFileIsExist(filename) {
fmt.Println(table.Name + " 已存在,需删除才能重新生成...")
f, err = os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, 0666) //打开文件
if err != nil {
panic(err)
}
}
f, err = os.Create(filename)
if err != nil {
panic(err)
}
defer f.Close()
_, err = io.WriteString(f, content)
if err != nil {
panic(err)
} else {
fmt.Println(generator.CamelCase(table.Name) + " 已生成...")
}
}
//获取字段类型
func getFiledType(field Field) string {
typeArr := strings.Split(field.Type, "(")
typeArr1 := strings.Split(field.Type, ")")
switch typeArr[0] {
case "int":
if typeArr1[1] == " unsigned" {
return "*uint32"
} else {
return "*int32"
}
case "integer":
if typeArr1[1] == " unsigned" {
return "*uint32"
} else {
return "*int32"
}
case "mediumint":
if typeArr1[1] == " unsigned" {
return "*uint32"
} else {
return "*int32"
}
case "bit":
if typeArr1[1] == " unsigned" {
return "*uint32"
} else {
return "*int32"
}
case "year":
if typeArr1[1] == " unsigned" {
return "*uint32"
} else {
return "*int32"
}
case "smallint":
if typeArr1[1] == " unsigned" {
return "*uint16"
} else {
return "*int16"
}
case "tinyint":
if typeArr1[1] == " unsigned" {
return "*uint8"
} else {
return "*int8"
}
case "bigint":
if typeArr1[1] == " unsigned" {
return "*uint64"
} else {
return "*int64"
}
case "decimal":
return "*float64"
case "double":
return "*float32"
case "float":
return "*float32"
case "real":
return "*float32"
case "numeric":
return "*float32"
case "timestamp":
return "*time.Time"
case "datetime":
return "*jsontime.JsonTime"
case "time":
return "*time.Time"
case "date":
return "*time.Time"
default:
return "*string"
}
}
//获取字段json描述
func getFieldJson(field Field) string {
return `json:"` + Lcfirst(generator.CamelCase(field.Field)) + `"`
}
// 首字母小写
func Lcfirst(str string) string {
for i, v := range str {
return string(unicode.ToLower(v)) + str[i+1:]
}
return ""
}
//获取字段gorm描述
func getFieldGorm(field Field) string {
fieldContext := `gorm:"column:` + field.Field
if field.Key == "PRI" {
fieldContext = fieldContext + `;primaryKey`
}
if field.Key == "UNI" {
fieldContext = fieldContext + `;unique`
}
if field.Extra == "auto_increment" {
fieldContext = fieldContext + `;autoIncrement`
}
if field.Null == "NO" {
fieldContext = fieldContext + `;not null`
}
return fieldContext + `"`
}
//获取字段说明
func getFieldComment(field Field) string {
if len(field.Comment) > 0 {
//return "// " + field.Comment
return "//" + strings.Replace(strings.Replace(field.Comment, "\r", "\\r", -1), "\n", "\\n", -1)
}
return ""
}
//检查文件是否存在
func checkFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
//生成JSON
func generateJSON(table Table, fields []Field, ch chan int) {
content := "package reply\n\n"
content += "type " + generator.CamelCase(table.Name) + "Reply struct {\n"
//生成字段
for _, field := range fields {
fieldName := generator.CamelCase(field.Field)
fieldJson := getFieldJson(field)
fieldType := getFiledType(field)
content += " " + fieldName + " " + fieldType + " `" + fieldJson + "` " + "\n"
}
content += "}\n"
filename := conf.JsonPath + table.Name + "_reply.go"
if checkFileIsExist(filename) {
fmt.Println(generator.CamelCase(table.Name) + " 已存在,需删除才能重新生成...")
return
}
f, err := os.Create(filename)
if err != nil {
panic(err)
}
_, err = io.WriteString(f, content)
if err != nil {
panic(err)
} else {
fmt.Println(table.Name + "_reply.go 已生成...")
}
defer f.Close()
ch <- 0
close(ch)
}
写的比较粗俗简单,生成那里用到通道,是因为用了go协程,防止main方法先跑完导致生成不完全
如果想加快,可以把switchcase那里改造成map也会更快
不过就只在本地跑就无所谓了
最后是main方法
func main() {
//初始化数据库
db.Init()
//生成所有表信息
generate.Generate()
}
把go.mod我也放上来
直接go mod download即可
require (
github.com/golang/protobuf v1.4.3 // indirect
gorm.io/driver/mysql v1.0.4 // indirect
gorm.io/gorm v1.21.3 // indirect
)