From dac4e733fc0427270c31ab1f0b2e93a704ce0ca2 Mon Sep 17 00:00:00 2001 From: songzhibin97 <718428482@qq.com> Date: Sat, 10 Jul 2021 17:39:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=9B=9E=E6=BB=9A=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8C=96=E7=94=9F=E4=BA=A7=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/api/v1/sys_auto_code.go | 18 ++++++++ server/model/sys_auto_code.go | 6 ++- server/model/sys_autocode_history.go | 13 ++++++ server/router/sys_auto_code.go | 1 + server/service/sys_auto_code.go | 42 +++++++++++++++++-- server/service/sys_autocode_history.go | 58 ++++++++++++++++++++++++++ server/service/sys_initdb.go | 1 + server/utils/file_operations.go | 4 ++ server/utils/injectionCode.go | 41 +++++++++++++++++- 9 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 server/model/sys_autocode_history.go create mode 100644 server/service/sys_autocode_history.go diff --git a/server/api/v1/sys_auto_code.go b/server/api/v1/sys_auto_code.go index 09ac2418..6892ff4e 100644 --- a/server/api/v1/sys_auto_code.go +++ b/server/api/v1/sys_auto_code.go @@ -15,6 +15,24 @@ import ( "go.uber.org/zap" ) +// @Tags AutoCode +// @Summary 回滚 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body uint true "回滚自动生成代码" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"回滚成功"}" +// @Router /autoCode/preview [post] +func RollBack(c *gin.Context) { + var id model.AutoHistoryByID + _ = c.ShouldBindJSON(&id) + if err := service.RollBack(id.ID); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + response.OkWithMessage("回滚成功", c) +} + // @Tags AutoCode // @Summary 预览创建后的代码 // @Security ApiKeyAuth diff --git a/server/model/sys_auto_code.go b/server/model/sys_auto_code.go index 9e030f5d..5222a9fb 100644 --- a/server/model/sys_auto_code.go +++ b/server/model/sys_auto_code.go @@ -2,12 +2,16 @@ package model import "errors" +type AutoHistoryByID struct { + ID uint `json:"id"` +} + // 初始版本自动化代码工具 type AutoCodeStruct struct { StructName string `json:"structName"` // Struct名称 TableName string `json:"tableName"` // 表名 PackageName string `json:"packageName"` // 文件名称 - HumpPackageName string `json:"humpPackageName"` // go文件名称 + HumpPackageName string `json:"humpPackageName"` // go文件名称 Abbreviation string `json:"abbreviation"` // Struct简称 Description string `json:"description"` // Struct中文名称 AutoCreateApiToSql bool `json:"autoCreateApiToSql"` // 是否自动创建api diff --git a/server/model/sys_autocode_history.go b/server/model/sys_autocode_history.go new file mode 100644 index 00000000..3e65408b --- /dev/null +++ b/server/model/sys_autocode_history.go @@ -0,0 +1,13 @@ +package model + +import "gin-vue-admin/global" + +// 自动迁移代码记录,用于回滚,重放使用 + +type SysAutoCodeHistory struct { + global.GVA_MODEL + TableName string + AutoCodeMeta string `gorm:"type:text"` // 其他meta信息 path;path + InjectionMeta string `gorm:"type:text"` // 注入的内容 RouterPath@functionName@RouterString; + Flag int // 表示对应状态 0 代表创建, 1 代表回滚 ... +} diff --git a/server/router/sys_auto_code.go b/server/router/sys_auto_code.go index 723471d0..f81bd8f6 100644 --- a/server/router/sys_auto_code.go +++ b/server/router/sys_auto_code.go @@ -8,6 +8,7 @@ import ( func InitAutoCodeRouter(Router *gin.RouterGroup) { AutoCodeRouter := Router.Group("autoCode") { + AutoCodeRouter.POST("rollback", v1.RollBack) // 回滚 AutoCodeRouter.POST("preview", v1.PreviewTemp) // 获取自动创建代码预览 AutoCodeRouter.POST("createTemp", v1.CreateTemp) // 创建自动化代码 AutoCodeRouter.GET("getTables", v1.GetTables) // 获取对应数据库的表 diff --git a/server/service/sys_auto_code.go b/server/service/sys_auto_code.go index 679120af..0eb28ccf 100644 --- a/server/service/sys_auto_code.go +++ b/server/service/sys_auto_code.go @@ -2,6 +2,7 @@ package service import ( "errors" + "fmt" "gin-vue-admin/global" "gin-vue-admin/model" "gin-vue-admin/model/request" @@ -143,6 +144,35 @@ func CreateTemp(autoCode model.AutoCodeStruct) (err error) { return err } err = utils.AutoInjectionCode(initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)") + if err != nil { + return err + } + injectionCodeMeta := strings.Builder{} + injectionCodeMeta.WriteString(fmt.Sprintf("%s@%s@%s", initializeGormFilePath, "MysqlTables", "model."+autoCode.StructName+"{},")) + injectionCodeMeta.WriteString(";") + injectionCodeMeta.WriteString(fmt.Sprintf("%s@%s@%s", initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)")) + + // 保存生成信息 + bf := strings.Builder{} + for _, data := range dataList { + if len(data.autoMoveFilePath) != 0 { + bf.WriteString(data.autoMoveFilePath) + bf.WriteString(";") + } + } + + if autoCode.TableName != "" { + err = CreateAutoCodeHistory(bf.String(), + injectionCodeMeta.String(), + autoCode.TableName, + ) + } else { + err = CreateAutoCodeHistory(bf.String(), + injectionCodeMeta.String(), + autoCode.StructName, + ) + } + if err != nil { return err } @@ -215,6 +245,10 @@ func GetColumn(tableName string, dbName string) (err error, Columns []request.Co return err, Columns } +func DropTable(tableName string) error { + return global.GVA_DB.Exec("DROP TABLE " + tableName).Error +} + //@author: [SliverHorn](https://github.com/SliverHorn) //@author: [songzhibin97](https://github.com/songzhibin97) //@function: addAutoMoveFile @@ -361,10 +395,10 @@ func getNeedList(autoCode *model.AutoCodeStruct) (dataList []tplData, fileList [ firstDot := strings.Index(origFileName, ".") if firstDot != -1 { var fileName string - if origFileName[firstDot:] !=".go"{ - fileName = autoCode.PackageName+origFileName[firstDot:] - }else{ - fileName = autoCode.HumpPackageName+origFileName[firstDot:] + if origFileName[firstDot:] != ".go" { + fileName = autoCode.PackageName + origFileName[firstDot:] + } else { + fileName = autoCode.HumpPackageName + origFileName[firstDot:] } dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName, diff --git a/server/service/sys_autocode_history.go b/server/service/sys_autocode_history.go new file mode 100644 index 00000000..877b3e0d --- /dev/null +++ b/server/service/sys_autocode_history.go @@ -0,0 +1,58 @@ +package service + +import ( + "errors" + "gin-vue-admin/global" + "gin-vue-admin/model" + "gin-vue-admin/utils" + "strings" + + "go.uber.org/zap" +) + +// CreateAutoCodeHistory RouterPath : RouterPath@RouterString;RouterPath2@RouterString2 +func CreateAutoCodeHistory(autoCodeMeta string, injectionMeta string, tableName string) error { + return global.GVA_DB.Create(&model.SysAutoCodeHistory{ + AutoCodeMeta: autoCodeMeta, + InjectionMeta: injectionMeta, + TableName: tableName, + }).Error +} + +func RollBack(id uint) error { + md := model.SysAutoCodeHistory{} + if err := global.GVA_DB.First(&md, id).Error; err != nil { + return err + } + // 切分数据 + err, dbNames := GetTables(global.GVA_CONFIG.Mysql.Dbname) + if err != nil { + return err + } + // 删除表 + for _, name := range dbNames { + if strings.Contains(strings.ToUpper(strings.Replace(name.TableName, "_", "", -1)), strings.ToUpper(md.TableName)) { + // 删除表 + if err = DropTable(name.TableName); err != nil { + global.GVA_LOG.Error("ClearTag DropTable:", zap.Error(err)) + + } + } + } + // 删除文件 + + for _, path := range strings.Split(md.AutoCodeMeta, ";") { + _ = utils.DeLFile(path) + } + // 清除注入 + for _, v := range strings.Split(md.InjectionMeta, ";") { + // RouterPath@functionName@RouterString + meta := strings.Split(v, "@") + if len(meta) != 3 { + return errors.New("split InjectionMeta Err") + } + _ = utils.AutoClearCode(meta[0], meta[2]) + } + md.Flag = 1 + return global.GVA_DB.Save(&md).Error +} diff --git a/server/service/sys_initdb.go b/server/service/sys_initdb.go index b84a0868..22901099 100644 --- a/server/service/sys_initdb.go +++ b/server/service/sys_initdb.go @@ -131,6 +131,7 @@ func InitDB(conf request.InitDB) error { model.ExaSimpleUploader{}, model.ExaCustomer{}, model.SysOperationRecord{}, + model.SysAutoCodeHistory{}, ) if err != nil { global.GVA_DB = nil diff --git a/server/utils/file_operations.go b/server/utils/file_operations.go index 36115c69..0e747773 100644 --- a/server/utils/file_operations.go +++ b/server/utils/file_operations.go @@ -42,6 +42,10 @@ Redirect: return os.Rename(src, dst) } +func DeLFile(filePath string) error { + return os.RemoveAll(filePath) +} + //@author: [songzhibin97](https://github.com/songzhibin97) //@function: TrimSpace //@description: 去除结构体空格 diff --git a/server/utils/injectionCode.go b/server/utils/injectionCode.go index 5bc66c4f..5b12f11d 100644 --- a/server/utils/injectionCode.go +++ b/server/utils/injectionCode.go @@ -1,6 +1,7 @@ package utils import ( + "errors" "fmt" "go/ast" "go/parser" @@ -15,9 +16,18 @@ import ( //@param: filepath string, funcName string, codeData string //@return: error +const ( + startComment = "Code generated by gin-vue-admin Begin; DO NOT EDIT." + endComment = "Code generated by gin-vue-admin End; DO NOT EDIT." +) + +//@author: [LeonardWang](https://github.com/WangLeonard) +//@function: AutoInjectionCode +//@description: 向文件中固定注释位置写入代码 +//@param: filepath string, funcName string, codeData string +//@return: error + func AutoInjectionCode(filepath string, funcName string, codeData string) error { - startComment := "Code generated by gin-vue-admin Begin; DO NOT EDIT." - endComment := "Code generated by gin-vue-admin End; DO NOT EDIT." srcData, err := ioutil.ReadFile(filepath) if err != nil { return err @@ -141,3 +151,30 @@ func checkExist(srcData *[]byte, startPos int, endPos int, blockStmt *ast.BlockS } return false } + +func AutoClearCode(filepath string, codeData string) error { + srcData, err := ioutil.ReadFile(filepath) + if err != nil { + return err + } + srcData, err = cleanCode(codeData, string(srcData)) + if err != nil { + return err + } + return ioutil.WriteFile(filepath, srcData, 0600) +} + +func cleanCode(clearCode string, srcData string) ([]byte, error) { + bf := make([]rune, 0, 1024) + for i, v := range srcData { + if v == '\n' { + if strings.TrimSpace(string(bf)) == clearCode { + return append([]byte(srcData[:i-len(bf)]), []byte(srcData[i+1:])...), nil + } + bf = (bf)[:0] + continue + } + bf = append(bf, v) + } + return []byte(srcData), errors.New("未找到内容") +}