Files
go-ReverseEngine/reverse/Engine.go
T

266 lines
8.4 KiB
Go
Raw Normal View History

2020-04-26 11:01:26 +08:00
package reverse
import (
"ReverseEngine/entity"
"ReverseEngine/imp"
"ReverseEngine/static"
"ReverseEngine/support"
"ReverseEngine/util"
"bufio"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"gopkg.in/ini.v1"
"log"
"os"
"strings"
)
var (
//数据库到实体映射 可在config.ini中配置
tm = make(map[string]string)
//通用配置 可在config.ini中配置
def = "string" //默认的映射类型
tagKey = "xorm" //tag的key
suffix = ".go" //文件后缀
cover = true //存在文件是否进行覆盖,只有配置为false的时候不会覆盖,其他默认为true
//数据库配置 可在config.ini中配置 格式是:”用户名:密码@tcp(IP:端口)/数据库?charset=utf8”
username = "你的mysql连接账号"
password = "你的连接密码"
tcp = "@tcp"
ip = "你的地址"
port = "3306"
database = "你的数据库" //这个是我的数据库
charset = "utf8mb4&parseTime=True&loc=Local"
connMaxLifeTime = 100
maxIdleConns = 10
//校验、数据库连接实现类
cg imp.ContentGenerate
dbc imp.DbConnection
rc imp.ReverseCheck
)
//---------------------------------------初始化,策略配置,规则校验-----------------------------------------
type DataReverseEngine struct {
}
func NewEngine() *DataReverseEngine {
return &DataReverseEngine{}
}
//创建初始化 --加载配置信息等
func init() {
cfg := loadIniCfg() //获取ini配置文件的对象
if nil == cfg {
panic("配置文件 config.ini配置错误,请检查")
return
}
loadCommonConfig(cfg) //加载通用配置
loadDataBaseConfig(cfg) //加载数据库配置
loadTypeMappingConfig(cfg) //加载类型映射配置
rc = &support.CheckSupport{} //校验支持
dbc = &support.DbSupport{} //数据库支持
cg = &support.FileContentSupport{} //文本拼接支持
}
/*
重写自己的文件类型定义实现
*/
func (*DataReverseEngine) SetContentGenerate(face imp.ContentGenerate) {
cg = face
}
/*
重写自己的数据库连接工具
*/
func (*DataReverseEngine) SetDbConnection(face imp.DbConnection) {
dbc = face
}
/*
重写自己的校验规则
*/
func (*DataReverseEngine) SetReverseCheck(face imp.ReverseCheck) {
rc = face
}
func checkError(err error, s string) {
if err != nil {
panic(s + err.Error())
}
}
//----------------------------------逆向工程---------------------------------
/*
数据库逆向工程
tableName:表名
path:创建目录的相对路径(右键选中文件夹,点击relative path得到的路径)
*/
func (r *DataReverseEngine) SimpleEngineer(tableName string, path string) {
r.Engineer(database, tableName, path, cover)
}
/*
数据库逆向工程
tableName:表名
path:创建目录的相对路径(右键选中文件夹,点击relative path得到的路径)
cover:如果已经存在改文件是否进行覆盖
*/
func (r *DataReverseEngine) SimEngineer(tableName string, path string, cover bool) {
r.Engineer(database, tableName, path, cover)
}
/*
数据库逆向工程
dbName:数据库名称
tableName:表名
path:创建目录的相对路径(右键选中文件夹,点击relative path得到的路径)
cover:如果已经存在改文件是否进行覆盖
*/
func (*DataReverseEngine) Engineer(dbName string, tableName string, path string, cover bool) {
//tableName = strings.Title(tableName) //tableName进行首字母大写
if !rc.CheckFileDir(path, tableName, cover) { //进行通用校验
return
}
dbPath := strings.Join([]string{username, ":", password, tcp, "(", ip, ":", port, ")/", database, "?", "charset=", charset}, "")
db := dbc.CreateDbConnection(dbPath, maxIdleConns, connMaxLifeTime) //连接数据库--可配置连接不同的数据库
if db == nil {
log.Println("数据库连接失败,程序终止")
return
}
//校验对应的数据库表是否存在
if rc.CheckTableExist(dbName, tableName, db) {
dbReverse(path, tableName, dbName, db)
return
}
log.Println("数据库表不存在:", tableName) //不存在的话打印日志返回
}
func dbReverse(path string, tableName string, dbName string, db *sql.DB) {
file, result := util.CreateNeedOpenFile(util.GenerateFilePath(path, tableName, static.Splice, suffix))
if !result {
return
}
cms := util.FindColumnMessage(dbName, tableName, db) //查询数据库表字段信息
tableComment := util.FindTableComment(dbName, tableName, db) //查询数据库表字段信息
dErr := db.Close() //关闭数据库连接
2020-04-26 11:01:26 +08:00
checkError(dErr, "数据库关闭失败:")
if nil == cms {
log.Println("没有查到数据库字段信息略过")
}
fms, hasTime := buildFieldMessage(cms) //创建字段名和类型的映射
w := bufio.NewWriter(file) //进行文件的操作
content := cg.GenerateFileContent(path, tableName, fms, hasTime, tagKey, tableComment) //拼go文件
2020-04-26 11:01:26 +08:00
_, err := w.WriteString(content)
checkError(err, "写入出错了:")
fErr, cErr := w.Flush(), file.Close()
checkError(fErr, "文件写入出错了,flush错误:")
checkError(cErr, "文件写入出错了,close错误:")
}
func buildFieldMessage(cms []entity.ColumnMessage) ([]entity.FieldMessage, bool) {
var fms []entity.FieldMessage
hasTime := false
for _, cm := range cms {
fm := &entity.FieldMessage{
FiledName: cm.Field, //字段名称
FieldType: typeMapping(cm.Type, &hasTime), //字段类型,进行映射
OriginType: cm.Type, //数据库原始类型
IsKey: cm.IsKey(), //是否主键
TagKey: tagKey, //tag的key值,这边先写死,正常应该是可配
Comment: cm.GetComment(), //注释信息
Default: cm.GetDefault(), //默认值信息
CanNull: cm.CanNull(), //是否可以为空
}
fms = append(fms, *fm)
}
return fms, hasTime
}
func typeMapping(t string, has *bool) string {
rt := strings.Split(t, "(")[0] //需要把类型后面的([长度])去掉
value, ok := tm[rt]
if ok {
if value == static.TimeT {
*has = true
}
return value
}
return def
}
//-----------------------------------读取和属性设置-----------------------------
func loadIniCfg() *ini.File {
cfg, err := ini.Load(static.IniAddress)
if err != nil {
log.Println("读取失败使用原始配置", err)
os.Exit(1)
return nil
}
return cfg
}
func loadDataBaseConfig(cfg *ini.File) {
if len(cfg.Section(static.DataBase).Keys()) == 0 {
log.Println("配置区间为空,采用数据库配置通用配置")
return
}
util.GenerateConfig("username", username, cfg.Section(static.DataBase))
util.GenerateConfig("password", password, cfg.Section(static.DataBase))
util.GenerateConfig("tcp", tcp, cfg.Section(static.DataBase))
util.GenerateConfig("ip", ip, cfg.Section(static.DataBase))
util.GenerateConfig("port", port, cfg.Section(static.DataBase))
util.GenerateConfig("database", database, cfg.Section(static.DataBase))
util.GenerateConfig("charset", charset, cfg.Section(static.DataBase))
util.GenerateConfigInt("connMaxLifeTime", connMaxLifeTime, cfg.Section(static.DataBase))
util.GenerateConfigInt("maxIdleConns", maxIdleConns, cfg.Section(static.DataBase))
}
func loadCommonConfig(cfg *ini.File) {
if len(cfg.Section(static.Common).Keys()) == 0 {
log.Println("配置区间为空,采用通用配置")
return
}
util.GenerateConfig("def", def, cfg.Section(static.Common)) //默认的映射类型
util.GenerateConfig("tagKey", tagKey, cfg.Section(static.Common)) //tag的key
util.GenerateConfig("suffix", suffix, cfg.Section(static.Common)) //文件后缀
util.GenerateConfigBool("cover", &cover, cfg.Section(static.Common)) //存在文件是否进行覆盖,只有配置为false的时候不会覆盖,其他默认为true
}
func defaultTypeMappingConfig() {
tm["double"] = "float64"
tm["float"] = "float64"
tm["int"] = "int"
tm["tinyint"] = "int"
tm["bigint"] = "int"
tm["time"] = "time.Time"
tm["timestamp"] = "time.Time"
tm["date"] = "time.Time"
tm["dateTime"] = "time.Time"
}
func loadTypeMappingConfig(cfg *ini.File) {
if len(cfg.Section(static.MapType).Keys()) == 0 {
defaultTypeMappingConfig()
log.Println("配置区间为空,采用类型映射通用配置")
return
}
for _, k := range cfg.Section(static.MapType).Keys() {
if k.Name() != "" {
tm[k.Name()] = k.Value()
}
}
}