feat(ReverseEngine):初始化工程
This commit is contained in:
@@ -0,0 +1,101 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ReverseEngine/imp"
|
||||||
|
"ReverseEngine/reverse"
|
||||||
|
"ReverseEngine/support"
|
||||||
|
"ReverseEngine/util"
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var database string
|
||||||
|
var tableName string
|
||||||
|
var filepath string
|
||||||
|
var cover bool
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
//转换函数
|
||||||
|
reverseMain()
|
||||||
|
}
|
||||||
|
|
||||||
|
func reverseMain() {
|
||||||
|
//报错是否直接停止程序,有的时候就是说,我可能输错了,但是我不想停止程序,那就会尴尬,这边配置一个报错不停止的标识
|
||||||
|
panicStop := flag.Bool("panicStop", false, "错误是否进行停止")
|
||||||
|
flag.Parse()
|
||||||
|
conti := true
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Print("逆向工程生成中")
|
||||||
|
fmt.Print("请出入你需要操作的数据库:\n")
|
||||||
|
database, _ = reader.ReadString('\n')
|
||||||
|
database = strings.Trim(database, "\n")
|
||||||
|
e := reverse.NewEngine()
|
||||||
|
e.SetReverseCheck(&support.CheckPathSupport{})
|
||||||
|
|
||||||
|
fmt.Println(runOn(conti, reader, e, *panicStop))
|
||||||
|
}
|
||||||
|
|
||||||
|
func runOn(conti bool, reader *bufio.Reader, e *reverse.DataReverseEngine, panicStop bool) string {
|
||||||
|
defer func() {
|
||||||
|
if panicStop == false || conti == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
util.ColorPrint("程序出错,因为设置panicStop为不停止状态,所以程序继续\n请开始新一轮的反向工程参数设置\n\n\n\n........\n.........\n\n", util.FontColor.Red)
|
||||||
|
runOn(conti, reader, e, panicStop)
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
if conti == false {
|
||||||
|
return "程序运行结束"
|
||||||
|
}
|
||||||
|
fmt.Print("请出入你需要操作的表名,该名称不区分大小写,输出即为文件名:\n")
|
||||||
|
tableName, _ = reader.ReadString('\n')
|
||||||
|
tableName = strings.Trim(tableName, "\n")
|
||||||
|
fmt.Print("请出入结构体生成位置(绝对路径):\n")
|
||||||
|
filepath, _ = reader.ReadString('\n')
|
||||||
|
filepath = strings.Trim(filepath, "\n")
|
||||||
|
fmt.Print("如果文件存在是否覆盖(Y表示覆盖):\n")
|
||||||
|
coverS, _ := reader.ReadString('\n')
|
||||||
|
coverS = strings.Trim(coverS, "\n")
|
||||||
|
if coverS == "Y" || coverS == "y" {
|
||||||
|
cover = true
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Engineer(database, tableName, filepath, cover)
|
||||||
|
fmt.Print("是否停止程序,输入Y表示停止:\n")
|
||||||
|
stop, _ := reader.ReadString('\n')
|
||||||
|
stop = strings.Trim(stop, "\n")
|
||||||
|
if stop == "Y" || stop == "y" {
|
||||||
|
conti = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runOnce() {
|
||||||
|
e := reverse.NewEngine()
|
||||||
|
//e.SetContentGenerate(support.FileContentSUpport2{})
|
||||||
|
e.SetReverseCheck(&support.CheckPathSupport{})
|
||||||
|
e.Engineer("你的数据库", "你的表名", "F:/self_project/src/ReverseEngine/filepath", true)
|
||||||
|
//e.Engineer("你的数据库", "testreversing", "filepath", true)
|
||||||
|
//
|
||||||
|
//s := support.CheckSupport{}
|
||||||
|
//fmt.Println(&s)
|
||||||
|
|
||||||
|
tx := reflect.ValueOf(support.CheckSupport{}).Type()
|
||||||
|
fmt.Println(tx)
|
||||||
|
var ok imp.ReverseCheck = (*support.CheckSupport)(nil)
|
||||||
|
fmt.Println(ok)
|
||||||
|
//t := reflect.ValueOf(Test{}).Type()
|
||||||
|
//fmt.Println(t)
|
||||||
|
//v := reflect.New(t).Elem()
|
||||||
|
//fmt.Println(v)
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
|
||||||
|
## 查询命令记录
|
||||||
|
```
|
||||||
|
查询数据库表的信息sql,这边主要是用来查询表的信息:
|
||||||
|
select * from information_schema.TABLES where TABLE_SCHEMA='[数据库名]'
|
||||||
|
|
||||||
|
查询数据库表的字段元数据信息sql:
|
||||||
|
show full columns from [数据库名].[表名]
|
||||||
|
查询结果:
|
||||||
|
Field(字段名) Type(字段类型) Collation NULL(能否为空) Key(是否主键) Default(默认值) Extra Privilege Comment(注释)
|
||||||
|
```
|
||||||
|
## 使用ini配置文件读取工具
|
||||||
|
```
|
||||||
|
读取ini配置文件的工具:https://ini.unknwon.io/docs/intro/getting_started
|
||||||
|
|
||||||
|
配置信息保存路径:reverse/config.ini
|
||||||
|
支持三类配置:
|
||||||
|
[database] //数据库配置
|
||||||
|
[common] //通用配置
|
||||||
|
[type_mapping] //类型映射
|
||||||
|
按照对应格式进行配置,如果没有找到对应配置则使用数据库通用配置
|
||||||
|
```
|
||||||
|
|
||||||
|
## 可拓展支持
|
||||||
|
```
|
||||||
|
可拓展支持三个接口
|
||||||
|
ContentGenerate:文件内容拼接
|
||||||
|
DbConnection: 数据库支持
|
||||||
|
ReverseCheck: 校验支持
|
||||||
|
|
||||||
|
在Engine中通过以下三个方法实现配置
|
||||||
|
func SetContentGenerate
|
||||||
|
func SetDbConnection
|
||||||
|
func SetReverseCheck
|
||||||
|
```
|
||||||
|
|
||||||
|
## 方法调用说明
|
||||||
|
```
|
||||||
|
/**
|
||||||
|
* 传入表名和生成路径,数据库名和是否覆盖按照配置文件获取
|
||||||
|
*/
|
||||||
|
SimpleEngineer(tableName string, path string)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入表名、生成路径和是否覆盖,数据库名读取配置
|
||||||
|
*/
|
||||||
|
func (r *DataReverseEngine) SimEngineer(tableName string, path string, cover bool)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入表名、生成路径和是否覆盖、数据库名
|
||||||
|
*/
|
||||||
|
func (*DataReverseEngine) Engineer(dbName string, tableName string, path string, cover bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置文件例子
|
||||||
|
```
|
||||||
|
[database] //数据库配置
|
||||||
|
username = 我的数据库账号
|
||||||
|
password = 我的数据库密码
|
||||||
|
tcp = @tcp
|
||||||
|
ip = 我的数据库机器Ip
|
||||||
|
port = 3306
|
||||||
|
database = 我的数据库名
|
||||||
|
charset = utf8mb4&parseTime=True&loc=Local
|
||||||
|
connMaxLifeTime = 100
|
||||||
|
maxIdleConns = 10
|
||||||
|
|
||||||
|
[common] //通用配置
|
||||||
|
def = string //默认的映射类型
|
||||||
|
tagKey = xorm //tag的key
|
||||||
|
suffix = .go //文件后缀
|
||||||
|
cover = true //存在文件是否进行覆盖,只有配置为false的时候不会覆盖,其他默认为true
|
||||||
|
|
||||||
|
|
||||||
|
[type_mapping] //类型映射
|
||||||
|
double = float64
|
||||||
|
float = float64
|
||||||
|
int = int
|
||||||
|
tinyint = int
|
||||||
|
bigint = int
|
||||||
|
time = time.Time
|
||||||
|
timestamp = time.Time
|
||||||
|
date = time.Time
|
||||||
|
dateTime = time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
## 方法调用例子
|
||||||
|
```
|
||||||
|
//使用相对路径
|
||||||
|
e := reverse.NewEngine()
|
||||||
|
e.Engineer("数据库名字", "表名", "filepath", true)
|
||||||
|
|
||||||
|
//使用绝对路径
|
||||||
|
e := reverse.NewEngine()
|
||||||
|
e.SetReverseCheck(&support.CheckPathSupport{})
|
||||||
|
e.Engineer("数据库名字", "表名", "F:/self_project/src/ReverseEngine/filepath", true)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
```
|
||||||
|
1.数据库连接是通过最原始的方式进行,这边后期可以修改成xorm或者其他的orm框架方式
|
||||||
|
2.读写文件的方法可以做相应的修改,这边也是采用最原生的方式
|
||||||
|
```
|
||||||
|
|
||||||
|
## 重复使用
|
||||||
|
直接运行Main.go方法,在控制台根据提示输入对应的数据库名、表名、生成位置、文件存在是否覆盖等参数来达到直接调用函数使用生成的目的
|
||||||
|
一次生成结束提示输入Y即可结束程序
|
||||||
|
|
||||||
|
启动时通过`panicStop`参数输入,控制程序报错不停止,除非在提示结束的时候输入Y.
|
||||||
|
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
在config.ini中配置你的数据库信息,最好修改Engine中默认的数据库信息,因为这边的数据库信息都是我乱写的
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import "database/sql"
|
||||||
|
|
||||||
|
type ColumnMessage struct {
|
||||||
|
Field string //字段名称
|
||||||
|
Type string //字段类型
|
||||||
|
Collation sql.NullString //编码信息
|
||||||
|
Null sql.NullString //是否允许为空
|
||||||
|
Key sql.NullString //是否是主键
|
||||||
|
Default sql.NullString //默认值
|
||||||
|
Extra sql.NullString //不懂
|
||||||
|
Privileges sql.NullString //执行权限
|
||||||
|
Comment sql.NullString //注释信息
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
返回结果判断是不是主键
|
||||||
|
*/
|
||||||
|
func (c *ColumnMessage) IsKey() bool {
|
||||||
|
if c.Key.Valid && c.Key.String == "PRI" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
返回结果是否为空信息
|
||||||
|
*/
|
||||||
|
func (c *ColumnMessage) CanNull() bool {
|
||||||
|
if c.Null.Valid && c.Null.String == "NO" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
返回注释信息,没有注释信息返回空字符串
|
||||||
|
*/
|
||||||
|
func (c *ColumnMessage) GetComment() string {
|
||||||
|
if c.Comment.Valid {
|
||||||
|
return c.Comment.String
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
返回默认值信息
|
||||||
|
*/
|
||||||
|
func (c *ColumnMessage) GetDefault() string {
|
||||||
|
if c.Default.Valid {
|
||||||
|
return c.Default.String
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
type FieldMessage struct {
|
||||||
|
FiledName string //类型名称
|
||||||
|
FieldType string //类型
|
||||||
|
OriginType string //数据库原始类型
|
||||||
|
/*
|
||||||
|
正常情况下tag的组合是 `TagKey:"pk/ not null/ FieldType"`
|
||||||
|
*/
|
||||||
|
TagKey string //tag的key
|
||||||
|
IsKey bool //是否主键
|
||||||
|
Comment string //注释内容
|
||||||
|
Default string //默认值信息
|
||||||
|
CanNull bool //是否可以为空
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
type TableMessage struct {
|
||||||
|
TableName string //数据库表名
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package filepath
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param
|
||||||
|
* @return
|
||||||
|
* @description 这个是生成的文件,没有格式化
|
||||||
|
*/
|
||||||
|
type Testreversing struct {
|
||||||
|
t1 int `xorm:"pk not null bigint(20)"` //你好
|
||||||
|
t2 string `xorm:"not null binary(255)"` //你不好
|
||||||
|
t3 string `xorm:"bit(64)"` //你是不是啥
|
||||||
|
t4 string `xorm:"blob"` //是的
|
||||||
|
t5 string `xorm:"char(255)"` //
|
||||||
|
t6 time.Time `xorm:"date"` //
|
||||||
|
t7 string `xorm:"datetime"` //hello
|
||||||
|
t8 float64 `xorm:"double(255,0)"` //
|
||||||
|
t9 float64 `xorm:"float(255,0)"` //
|
||||||
|
t10 int `xorm:"int(255)"` //
|
||||||
|
t11 time.Time `xorm:"pk not null time"` //
|
||||||
|
t12 time.Time `xorm:"not null timestamp"` //
|
||||||
|
t13 string `xorm:"varchar(255)"` //
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
module ReverseEngine
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/DATA-DOG/go-txdb v0.1.2 // indirect
|
||||||
|
github.com/aceld/zinx v0.0.0-20190612015555-26a73a3ddf2e // indirect
|
||||||
|
github.com/ahmetb/go-linq v3.0.0+incompatible // indirect
|
||||||
|
github.com/gin-contrib/sse v0.0.0-20190125020943-a7658810eb74 // indirect
|
||||||
|
github.com/gin-gonic/gin v1.3.0 // indirect
|
||||||
|
github.com/go-ini/ini v1.51.1 //read init property
|
||||||
|
github.com/go-redis/redis v6.15.2+incompatible // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
|
github.com/go-xorm/cmd v0.0.0-20190426080617-f87981e709a1 // indirect
|
||||||
|
github.com/go-xorm/xorm v0.7.9 // indirect
|
||||||
|
github.com/golang/mock v1.3.0 // indirect
|
||||||
|
github.com/google/go-cmp v0.3.0 // indirect
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.6 // indirect
|
||||||
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/muesli/cache2go v0.0.0-20180419202730-5a1839810579 // indirect
|
||||||
|
github.com/nochso/tocenize v0.4.0 // indirect
|
||||||
|
github.com/oschwald/geoip2-golang v1.2.1 // indirect
|
||||||
|
github.com/oschwald/maxminddb-golang v1.3.0 // indirect
|
||||||
|
github.com/panjf2000/ants v1.0.1 // indirect
|
||||||
|
github.com/panjf2000/ants/v2 v2.2.2 // indirect
|
||||||
|
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 // indirect
|
||||||
|
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec // indirect
|
||||||
|
github.com/satori/go.uuid v1.2.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
|
||||||
|
github.com/tealeg/xlsx v1.0.3 // indirect
|
||||||
|
github.com/tidwall/gjson v1.2.1 // indirect
|
||||||
|
github.com/valyala/fasthttp v1.1.0 // indirect
|
||||||
|
go.etcd.io/etcd v3.3.13+incompatible // indirect
|
||||||
|
go.uber.org/zap v1.10.0 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 // indirect
|
||||||
|
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||||
|
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.51.1
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.13
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package imp
|
||||||
|
|
||||||
|
import "ReverseEngine/entity"
|
||||||
|
|
||||||
|
type ContentGenerate interface {
|
||||||
|
/*
|
||||||
|
内容制造接口
|
||||||
|
*/
|
||||||
|
GenerateFileContent(filePath string, fileName string, fms []entity.FieldMessage, hasTime bool, tagKey string) string
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package imp
|
||||||
|
|
||||||
|
import "database/sql"
|
||||||
|
|
||||||
|
type DbConnection interface {
|
||||||
|
/*
|
||||||
|
数据库连接接口
|
||||||
|
*/
|
||||||
|
CreateDbConnection(dbPath string, maxIdleConns int, connMaxLifeTime int) *sql.DB
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package imp
|
||||||
|
|
||||||
|
import "database/sql"
|
||||||
|
|
||||||
|
type ReverseCheck interface {
|
||||||
|
/*
|
||||||
|
关于文件和文件夹的一致校验接口
|
||||||
|
dirPath 文件夹路径
|
||||||
|
tableName 数据库表名
|
||||||
|
cover 是否覆盖已有文件
|
||||||
|
*/
|
||||||
|
CheckFileDir(dirPath string, tableName string, cover bool) bool
|
||||||
|
|
||||||
|
/*
|
||||||
|
校验数据库表是否存在
|
||||||
|
*/
|
||||||
|
CheckTableExist(dbName string, tableName string, db *sql.DB) bool
|
||||||
|
}
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
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) //查询数据库表字段信息
|
||||||
|
dErr := db.Close() //关闭数据库连接
|
||||||
|
checkError(dErr, "数据库关闭失败:")
|
||||||
|
if nil == cms {
|
||||||
|
log.Println("没有查到数据库字段信息略过")
|
||||||
|
}
|
||||||
|
fms, hasTime := buildFieldMessage(cms) //创建字段名和类型的映射
|
||||||
|
w := bufio.NewWriter(file) //进行文件的操作
|
||||||
|
content := cg.GenerateFileContent(path, tableName, fms, hasTime, tagKey) //拼go文件
|
||||||
|
_, 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
[database] //数据库配置
|
||||||
|
username = 你的mysql连接账号
|
||||||
|
password = 你的连接密码
|
||||||
|
tcp = @tcp
|
||||||
|
ip = 你的地址
|
||||||
|
port = 3306
|
||||||
|
database = 你的数据库名
|
||||||
|
charset = utf8mb4&parseTime=True&loc=Local
|
||||||
|
connMaxLifeTime = 100
|
||||||
|
maxIdleConns = 10
|
||||||
|
|
||||||
|
[common] //通用配置
|
||||||
|
def = string //默认的映射类型
|
||||||
|
tagKey = xorm //tag的key
|
||||||
|
suffix = .go //文件后缀
|
||||||
|
cover = true //存在文件是否进行覆盖,只有配置为false的时候不会覆盖,其他默认为true
|
||||||
|
|
||||||
|
|
||||||
|
[type_mapping] //类型映射
|
||||||
|
double = float64
|
||||||
|
float = float64
|
||||||
|
int = int
|
||||||
|
tinyint = int
|
||||||
|
bigint = int
|
||||||
|
time = time.Time
|
||||||
|
timestamp = time.Time
|
||||||
|
date = time.Time
|
||||||
|
datetime = time.Time
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package static
|
||||||
|
|
||||||
|
const (
|
||||||
|
Splice = "/" //文件分割符
|
||||||
|
LineFeed = "\n" //换行符
|
||||||
|
LeftBrace = "{" //左大括号
|
||||||
|
RightBrace = "}" //右大括号
|
||||||
|
DoubleInclinedRod = "//" //创斜杆
|
||||||
|
Colon = ":" //冒号
|
||||||
|
TimeT = "time.Time" //时间类型
|
||||||
|
|
||||||
|
IniAddress = "reverse/config.ini" //ini文件地址
|
||||||
|
Common = "common" //ini文件通用配置的section名
|
||||||
|
DataBase = "database" //ini文件数据库配置的section名
|
||||||
|
MapType = "type_mapping" //ini文件类型映射的section名
|
||||||
|
)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package support
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ReverseEngine/entity"
|
||||||
|
"ReverseEngine/static"
|
||||||
|
"ReverseEngine/util"
|
||||||
|
"database/sql"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckPathSupport struct{}
|
||||||
|
|
||||||
|
func (*CheckPathSupport) CheckFileDir(path string, tableName string, cover bool) bool {
|
||||||
|
//先查询一下路径是否为文件夹
|
||||||
|
if b := util.IsDirExist(path); !b {
|
||||||
|
log.Println("文件夹路径不存在略过")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//如果是不覆盖的情况,判断是否有这个文件,如果有的话直接返回
|
||||||
|
if !cover && util.IsFileExist(strings.Join([]string{path, static.Splice, tableName}, "")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断读写权限
|
||||||
|
if !util.HasReadWritePermission(path) {
|
||||||
|
log.Println("没有该文件夹的读写权限:", path)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CheckPathSupport) CheckTableExist(dbName string, tableName string, db *sql.DB) bool {
|
||||||
|
var tm entity.TableMessage
|
||||||
|
err := db.QueryRow(strings.Join([]string{"select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=? and TABLE_NAME=?"}, ""), dbName, tableName).Scan(&tm.TableName)
|
||||||
|
//查询失败
|
||||||
|
if err != nil {
|
||||||
|
panic("数据库查询失败:" + err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//查询没有数据
|
||||||
|
if !reflect.ValueOf(tm).IsValid() || tm.TableName == "" {
|
||||||
|
panic("没有表数据信息:" + tableName)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package support
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ReverseEngine/entity"
|
||||||
|
"ReverseEngine/static"
|
||||||
|
"ReverseEngine/util"
|
||||||
|
"database/sql"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckSupport struct{}
|
||||||
|
|
||||||
|
func (*CheckSupport) CheckFileDir(path string, tableName string, cover bool) bool {
|
||||||
|
b, realPath := pathExist(path)
|
||||||
|
//先查询一下路径是否为文件夹
|
||||||
|
if !b {
|
||||||
|
log.Println("文件夹路径不存在略过")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//如果是不覆盖的情况,判断是否有这个文件,如果有的话直接返回
|
||||||
|
if !cover && util.IsFileExist(strings.Join([]string{path, static.Splice, tableName}, "")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断读写权限
|
||||||
|
if !util.HasReadWritePermission(realPath) {
|
||||||
|
log.Println("没有该文件夹的读写权限:", realPath)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CheckSupport) CheckTableExist(dbName string, tableName string, db *sql.DB) bool {
|
||||||
|
var tm entity.TableMessage
|
||||||
|
err := db.QueryRow(strings.Join([]string{"select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=? and TABLE_NAME=?"}, ""), dbName, tableName).Scan(&tm.TableName)
|
||||||
|
//查询失败
|
||||||
|
if err != nil {
|
||||||
|
panic("数据库查询失败:" + err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//查询没有数据
|
||||||
|
if !reflect.ValueOf(tm).IsValid() || tm.TableName == "" {
|
||||||
|
panic("没有表数据信息:" + tableName)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func pathExist(path string) (bool, string) {
|
||||||
|
pp := util.GetCurrentPath()
|
||||||
|
realPath := strings.Join([]string{pp, static.Splice, path}, "")
|
||||||
|
return util.IsDirExist(strings.Join([]string{pp, static.Splice, path}, "")), realPath
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package support
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DbSupport struct{}
|
||||||
|
|
||||||
|
func (dbc *DbSupport) CreateDbConnection(dbPath string, maxIdleConns int, connMaxLifeTime int) *sql.DB {
|
||||||
|
var db *sql.DB
|
||||||
|
db, _ = sql.Open("mysql", dbPath)
|
||||||
|
|
||||||
|
//设置数据库最大连接数
|
||||||
|
db.SetConnMaxLifetime(time.Duration(connMaxLifeTime))
|
||||||
|
//设置上数据库最大闲置连接数
|
||||||
|
db.SetMaxIdleConns(maxIdleConns)
|
||||||
|
|
||||||
|
if err := db.Ping(); err != nil {
|
||||||
|
panic("数据库连接失败")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("数据库连接成功")
|
||||||
|
return db
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package support
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ReverseEngine/entity"
|
||||||
|
"ReverseEngine/static"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileContentSupport struct{}
|
||||||
|
|
||||||
|
func (FileContentSupport) GenerateFileContent(filePath string, fileName string, fms []entity.FieldMessage, hasTime bool, tagKey string) string {
|
||||||
|
var build strings.Builder
|
||||||
|
pName := splitLast(filePath, static.Splice)
|
||||||
|
|
||||||
|
writePackage(&build, pName) //写文件的引用包
|
||||||
|
writeImportIfTime(&build, hasTime) //如果有time.Time类型的需要写入import
|
||||||
|
buildStructHead(&build, fileName) //写入结构体头
|
||||||
|
|
||||||
|
//对于没有字段的返回空定义的文件
|
||||||
|
if len(fms) == 0 {
|
||||||
|
build.WriteString(static.RightBrace)
|
||||||
|
return build.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
//写中间字段的操作
|
||||||
|
for _, fm := range fms {
|
||||||
|
build.WriteString(" ")
|
||||||
|
build.WriteString(fm.FiledName)
|
||||||
|
build.WriteString(" ")
|
||||||
|
build.WriteString(fm.FieldType)
|
||||||
|
build.WriteString(" ")
|
||||||
|
build.WriteString(generateTag(fm, tagKey))
|
||||||
|
build.WriteString(" ")
|
||||||
|
build.WriteString(static.DoubleInclinedRod)
|
||||||
|
build.WriteString(fm.Comment)
|
||||||
|
build.WriteString(static.LineFeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
build.WriteString(static.RightBrace)
|
||||||
|
|
||||||
|
return build.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateTag(message entity.FieldMessage, tagKey string) string {
|
||||||
|
var build strings.Builder
|
||||||
|
build.WriteString("`")
|
||||||
|
build.WriteString(tagKey)
|
||||||
|
build.WriteString(static.Colon)
|
||||||
|
generateTagValue(message, &build)
|
||||||
|
build.WriteString("`")
|
||||||
|
return build.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateTagValue(message entity.FieldMessage, builder *strings.Builder) {
|
||||||
|
builder.WriteString("\"")
|
||||||
|
if message.IsKey {
|
||||||
|
builder.WriteString("pk ")
|
||||||
|
}
|
||||||
|
if !message.CanNull {
|
||||||
|
builder.WriteString("not null ")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(message.OriginType)
|
||||||
|
builder.WriteString("\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildStructHead(build *strings.Builder, fileName string) {
|
||||||
|
build.WriteString("type ")
|
||||||
|
build.WriteString(fileName)
|
||||||
|
build.WriteString(" struct")
|
||||||
|
build.WriteString(static.LeftBrace)
|
||||||
|
build.WriteString(static.LineFeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeImportIfTime(build *strings.Builder, hasTime bool) {
|
||||||
|
//如果有类型匹配上时间,那么需要在头部加上import
|
||||||
|
if hasTime {
|
||||||
|
build.WriteString("import (")
|
||||||
|
build.WriteString("\n ")
|
||||||
|
build.WriteString("\"time\"")
|
||||||
|
build.WriteString("\n")
|
||||||
|
build.WriteString(")")
|
||||||
|
build.WriteString(static.LineFeed)
|
||||||
|
build.WriteString(static.LineFeed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writePackage(build *strings.Builder, pName string) {
|
||||||
|
build.WriteString("package ")
|
||||||
|
build.WriteString(pName)
|
||||||
|
build.WriteString(static.LineFeed)
|
||||||
|
build.WriteString(static.LineFeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
返回按照规则切割的最后一个字符串
|
||||||
|
*/
|
||||||
|
func splitLast(filePath string, split string) string {
|
||||||
|
ss := strings.Split(filePath, split)
|
||||||
|
return ss[len(ss)-1]
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package support
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ReverseEngine/entity"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileContentSUpport2 struct{}
|
||||||
|
|
||||||
|
func (FileContentSUpport2) GenerateFileContent(filePath string, fileName string, fms []entity.FieldMessage, hasTime bool, tagKey string) string {
|
||||||
|
fmt.Println("12321321")
|
||||||
|
return " "
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* @Author : huangzj
|
||||||
|
* @Time : 2020/4/17 14:04
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 *syscall.LazyDLL = syscall.NewLazyDLL(`kernel32.dll`)
|
||||||
|
proc *syscall.LazyProc = kernel32.NewProc(`SetConsoleTextAttribute`)
|
||||||
|
CloseHandle *syscall.LazyProc = kernel32.NewProc(`CloseHandle`)
|
||||||
|
|
||||||
|
// 给字体颜色对象赋值
|
||||||
|
FontColor Color = Color{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Color struct {
|
||||||
|
black int // 黑色
|
||||||
|
blue int // 蓝色
|
||||||
|
green int // 绿色
|
||||||
|
cyan int // 青色
|
||||||
|
Red int // 红色
|
||||||
|
purple int // 紫色
|
||||||
|
yellow int // 黄色
|
||||||
|
light_gray int // 淡灰色(系统默认值)
|
||||||
|
gray int // 灰色
|
||||||
|
light_blue int // 亮蓝色
|
||||||
|
light_green int // 亮绿色
|
||||||
|
light_cyan int // 亮青色
|
||||||
|
light_red int // 亮红色
|
||||||
|
light_purple int // 亮紫色
|
||||||
|
light_yellow int // 亮黄色
|
||||||
|
white int // 白色
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出有颜色的字体
|
||||||
|
func ColorPrint(s string, i int) {
|
||||||
|
handle, _, _ := proc.Call(uintptr(syscall.Stdout), uintptr(i))
|
||||||
|
print(s)
|
||||||
|
CloseHandle.Call(handle)
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ReverseEngine/entity"
|
||||||
|
"database/sql"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DbUtil struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindColumnMessage(dbName string, tableName string, db *sql.DB) []entity.ColumnMessage {
|
||||||
|
var cms []entity.ColumnMessage
|
||||||
|
|
||||||
|
row, err := db.Query(strings.Join([]string{"show full columns from ", dbName, ".", tableName}, ""))
|
||||||
|
if err != nil {
|
||||||
|
panic("数据库查询出错:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for row.Next() {
|
||||||
|
var cm entity.ColumnMessage
|
||||||
|
err := row.Scan(&cm.Field, &cm.Type, &cm.Collation, &cm.Null, &cm.Key, &cm.Default, &cm.Extra, &cm.Privileges, &cm.Comment)
|
||||||
|
if err != nil {
|
||||||
|
panic("字段赋值错误了" + err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cms = append(cms, cm)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cms
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取当前项目的路径
|
||||||
|
*/
|
||||||
|
func GetCurrentPath() string {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return strings.Replace(dir, "\\", "/", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断路径是否存在并且为文件夹
|
||||||
|
*/
|
||||||
|
func IsDirExist(dirPath string) bool {
|
||||||
|
fi, err := os.Stat(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if fi.IsDir() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断路径是否存在并且为文件
|
||||||
|
*/
|
||||||
|
func IsFileExist(filePath string) bool {
|
||||||
|
fi, err := os.Stat(filePath)
|
||||||
|
//文件不存在或者是文件夹的直接返回false
|
||||||
|
if err != nil || fi.IsDir() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断是否有读权限
|
||||||
|
*/
|
||||||
|
func HasReadPermission(filePath string) bool {
|
||||||
|
_, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsPermission(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断是否有写权限
|
||||||
|
*/
|
||||||
|
func HasWritePermission(filePath string) bool {
|
||||||
|
_, err := os.OpenFile(filePath, os.O_WRONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsPermission(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断是否有读+写权限
|
||||||
|
*/
|
||||||
|
func HasReadWritePermission(filePath string) bool {
|
||||||
|
return HasReadPermission(filePath) && HasWritePermission(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
创建文件
|
||||||
|
*/
|
||||||
|
func CreateFile(filePath string) (*os.File, bool) {
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("创建文件失败" + err.Error())
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
返回拼接的文件路径,这边类的首字母需要大写
|
||||||
|
dirPath 文件夹路径
|
||||||
|
filePath 文件路径
|
||||||
|
splice 路径分隔符
|
||||||
|
suffix 后缀
|
||||||
|
*/
|
||||||
|
func GenerateFilePath(dirPath string, filePath string, splice string, suffix string) string {
|
||||||
|
return strings.Join([]string{dirPath, splice, strings.Title(filePath), suffix}, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
创建(如果需要)并已读写权限打开文件
|
||||||
|
os.O_RDONLY // 只读
|
||||||
|
os.O_WRONLY // 只写
|
||||||
|
os.O_RDWR // 读写
|
||||||
|
os.O_APPEND // 往文件中添建(Append)
|
||||||
|
os.O_CREATE // 如果文件不存在则先创建
|
||||||
|
os.O_TRUNC // 文件打开时裁剪文件
|
||||||
|
os.O_EXCL // 和O_CREATE一起使用,文件不能存在
|
||||||
|
os.O_SYNC // 以同步I/O的方式打开
|
||||||
|
*/
|
||||||
|
func CreateNeedOpenFile(filePath string) (*os.File, bool) {
|
||||||
|
//先删除再创建
|
||||||
|
if IsFileExist(filePath) {
|
||||||
|
err := os.Remove(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("文件删除失败:" + err.Error())
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_RDWR, 0666)
|
||||||
|
if err != nil {
|
||||||
|
panic("打开文件失败:" + err.Error())
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return file, true
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* @Author : huangzj
|
||||||
|
* @Time : 2020/4/17 14:41
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateConfigBool(key string, real *bool, section *ini.Section) {
|
||||||
|
if section.Key(key).String() != "false" {
|
||||||
|
*real = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*real = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateConfig(key string, real string, section *ini.Section) {
|
||||||
|
if section.Key(key).String() != "" {
|
||||||
|
real = section.Key(key).String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateConfigInt(key string, real int, section *ini.Section) {
|
||||||
|
if section.Key(key).String() != "" {
|
||||||
|
value, err := strconv.Atoi(section.Key(key).String())
|
||||||
|
if err == nil {
|
||||||
|
real = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user