使用到的库
gorm
go get -u gorm.io/gorm
Code
gen2Struct.go
func connectMysql() *gorm.DB {
//配置MySQL连接参数
username := "root" //账号
password := "root" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3309 //数据库端口
Dbname := "ginproject" //数据库名
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", username, password, host, port, Dbname)
fmt.Println(dsn)
var err error
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
return db
}
// Result 结构体代表一个字段及其类型的信息。
// Field 表示字段的名称。
// Type 表示字段的类型。
type Result struct {
Field string
Type string
}
// StructResult 结构体封装了一个结构体的名称以及其包含的所有字段和类型的列表。
// StructName 表示结构体的名称。
// Result 是一个Result类型的指针数组,包含了该结构体的所有字段及其类型。
type StructResult struct {
StructName string
Result []*Result
}
// MessageResult 结构体封装了一个消息的名称以及其包含的所有字段和类型的列表。
// MessageName 表示消息的名称。
// Result 是一个Result类型的指针数组,包含了该消息的所有字段及其类型。
type MessageResult struct {
MessageName string
Result []*Result
}
// GenStruct 根据数据库表生成相应的结构体定义。
// table: 数据库表名。
// structName: 生成的结构体名称。
func GenStruct(table string, structName string) {
// 连接MySQL数据库。
db := connectMysql()
// 查询表的结构信息。
var results []*Result
db.Raw(fmt.Sprintf("describe %s", table)).Scan(&results)
// 处理结构信息,将字段名和类型转换为Go语言风格。
for _, v := range results {
v.Field = Name(v.Field)
v.Type = getType(v.Type)
}
// 加载模板文件。
tmpl, err := template.ParseFiles("./struct.tpl")
log.Println(err)
// 根据查询结果和结构体名生成最终的结构体定义结果。
sr := StructResult{StructName: structName, Result: results}
// 使用模板生成结构体定义代码,并输出到标准输出。
tmpl.Execute(os.Stdout, sr)
}
func GenProtoMessage(table string, messageName string) {
db := connectMysql()
var results []*Result
db.Raw(fmt.Sprintf("describe %s", table)).Scan(&results)
for _, v := range results {
v.Field = Name(v.Field)
v.Type = getMessageType(v.Type)
}
var fm template.FuncMap = make(map[string]any)
fm["Add"] = func(v int, add int) int {
return v + add
}
t := template.New("message.tpl")
t.Funcs(fm)
tmpl, err := t.ParseFiles("./message.tpl")
log.Println(err)
sr := MessageResult{MessageName: messageName, Result: results}
err = tmpl.Execute(os.Stdout, sr)
log.Println(err)
}
func getMessageType(t string) string {
if strings.Contains(t, "bigint") {
return "int64"
}
if strings.Contains(t, "varchar") {
return "string"
}
if strings.Contains(t, "text") {
return "string"
}
if strings.Contains(t, "tinyint") {
return "int32"
}
if strings.Contains(t, "int") &&
!strings.Contains(t, "tinyint") &&
!strings.Contains(t, "bigint") {
return "int32"
}
if strings.Contains(t, "double") {
return "double"
}
return ""
}
// getType 根据数据库字段类型字符串返回相应的Go数据类型字符串。
// t: 数据库字段类型的字符串描述。
// 返回值: 对应的Go数据类型字符串,如果无法匹配则返回空字符串。
func getType(t string) string {
// 检查是否包含"bigint"关键词,对应Go中的int64类型
if strings.Contains(t, "bigint") {
return "int64"
}
// 检查是否包含"varchar"或"text"关键词,对应Go中的string类型
if strings.Contains(t, "varchar") || strings.Contains(t, "text") {
return "string"
}
// 检查是否包含"tinyint"关键词,对应Go中的int类型
if strings.Contains(t, "tinyint") {
return "int"
}
// 检查是否为未指定大小的"int"类型,且不是"tinyint"或"bigint",对应Go中的int类型
if strings.Contains(t, "int") && !strings.Contains(t, "tinyint") && !strings.Contains(t, "bigint") {
return "int"
}
// 检查是否包含"double"关键词,对应Go中的float64类型
if strings.Contains(t, "double") {
return "float64"
}
// 如果无法匹配任何已知类型,则返回空字符串
return ""
}
// Name 对给定的姓名字符串进行处理,返回首字母大写且下划线后的单词首字母大写的格式。
// 例如,输入 "hello_world",返回 "HelloWorld"。
func Name(name string) string {
// 创建一个切片,复制name的内容,以便在循环中修改原字符串。
var names = name[:]
// 用于标记当前字符是否应该被跳过。
isSkip := false
// 使用strings.Builder高效地构建最终字符串。
var sb strings.Builder
// 遍历name中的每个字符。
for index, value := range names {
// 处理字符串的第一个字符,将其转换为大写并添加到sb中。
if index == 0 {
s := names[:index+1]
s = strings.ToUpper(s)
sb.WriteString(s)
continue
}
// 如果上一个字符是下划线,则跳过当前字符。
if isSkip {
isSkip = false
continue
}
// 如果当前字符是下划线,则将下一个字符转换为大写并添加到sb中,同时标记下一个字符应该被跳过。
if value == 95 {
s := names[index+1 : index+2]
s = strings.ToUpper(s)
sb.WriteString(s)
isSkip = true
continue
} else {
// 如果当前字符不是下划线,直接将其添加到sb中。
s := names[index : index+1]
sb.WriteString(s)
}
}
// 返回构建好的字符串。
return sb.String()
}
struct.tpl
type {{.StructName}} struct {
{{range $index,$value := .Result}}
{{$value.Field}} {{$value.Type}}
{{end}}
}
gen2struct_test.go
import "testing"
func TestGenStruct(t *testing.T) {
GenStruct("project", "Project") //project表名 Project结构体名
}
运行test后,程序会输出对应结构体,直接复制即可使用
输出示例:
type Project struct {
Id int64
Cover string
Name string
Description string
AccessControlType int
WhiteList string
Order int
Deleted int
TemplateCode string
Schedule float64
CreateTime string
OrganizationCode int64
DeletedTime string
Private int
Prefix string
OpenPrefix int
Archive int
ArchiveTime int64
OpenBeginTime int
OpenTaskPrivate int
TaskBoardTheme string
BeginTime int64
EndTime int64
AutoUpdateSchedule int
}
func TestGenProtoMessage(t *testing.T) {
GenProtoMessage("project", "Project")
}
message.tpl
message {{.MessageName}} {
{{range $index,$value := .Result}}
{{$value.Type}} {{$value.Field}} = {{Add $index 1}}
{{end}}
}
示例:
message Project {
int64 Id = 1
string Cover = 2
string Name = 3
string Description = 4
int32 AccessControlType = 5
string WhiteList = 6
int32 Order = 7
int32 Deleted = 8
string TemplateCode = 9
double Schedule = 10
string CreateTime = 11
int64 OrganizationCode = 12
string DeletedTime = 13
int32 Private = 14
string Prefix = 15
int32 OpenPrefix = 16
int32 Archive = 17
int64 ArchiveTime = 18
int32 OpenBeginTime = 19
int32 OpenTaskPrivate = 20
string TaskBoardTheme = 21
int64 BeginTime = 22
int64 EndTime = 23
int32 AutoUpdateSchedule = 24
}