gorm逆向生成model类和json类

因为项目转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
)

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
引用和提到,gorm.ModelGORM内置的一个结构体,用于定义模型。它包含了ID、CreatedAt、UpdatedAt、DeletedAt这四个字段。具体的定义如下: ```go type Model struct { ID uint `gorm:"primary_key"` CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time } ``` 这个结构体可以作为其他模型的嵌入字段,以便在数据库中创建对应的数据表。引用给出了一个示例,展示了如何使用gorm.Model来定义一个用户模型: ```go type User struct { gorm.Model } ``` 通过嵌入gorm.Model,User模型将自动拥有ID、CreatedAt、UpdatedAt、DeletedAt这四个字段。 综上所述,gorm.ModelGORM提供的一个方便的结构体,用于定义模型并自动创建数据库表。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Gormgorm.Model详解](https://blog.csdn.net/weixin_52690231/article/details/124543708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [GORM模型(Model)定义](https://blog.csdn.net/jiangshanghe/article/details/124408109)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值