提交 dcba0898 编写于 作者: Mr.奇淼('s avatar Mr.奇淼(

Merge remote-tracking branch 'origin/gva_gormv2_dev' into gva_gormv2_dev

......@@ -5,6 +5,7 @@ import (
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
......@@ -15,6 +16,49 @@ import (
"go.uber.org/zap"
)
// @Tags AutoCode
// @Summary 查询回滚记录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SysAutoHistory true "查询回滚记录"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /autoCode/preview [post]
func GetSysHistory(c *gin.Context) {
var search request.SysAutoHistory
_ = c.ShouldBindJSON(&search)
err, list, total := service.GetSysHistoryPage(search.PageInfo)
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Any("err", err))
response.FailWithMessage("获取失败", c)
} else {
response.OkWithDetailed(response.PageResult{
List: list,
Total: total,
Page: search.Page,
PageSize: search.PageSize,
}, "获取成功", c)
}
}
// @Tags AutoCode
// @Summary 回滚
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.AutoHistoryByID true "回滚自动生成代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"回滚成功"}"
// @Router /autoCode/preview [post]
func RollBack(c *gin.Context) {
var id request.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
......@@ -54,15 +98,18 @@ func CreateTemp(c *gin.Context) {
response.FailWithMessage(err.Error(), c)
return
}
var apiIds []uint
if a.AutoCreateApiToSql {
if err := service.AutoCreateApi(&a); err != nil {
if ids, err := service.AutoCreateApi(&a); err != nil {
global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Any("err", err))
c.Writer.Header().Add("success", "false")
c.Writer.Header().Add("msg", url.QueryEscape("自动化创建失败!请自行清空垃圾数据!"))
return
} else {
apiIds = ids
}
}
err := service.CreateTemp(a)
err := service.CreateTemp(a, apiIds...)
if err != nil {
if errors.Is(err, model.AutoMoveErr) {
c.Writer.Header().Add("success", "false")
......
package request
type SysAutoHistory struct {
PageInfo
}
type AutoHistoryByID struct {
ID uint `json:"id"`
}
type DBReq struct {
Database string `json:"database" gorm:"column:database"`
}
......
......@@ -7,7 +7,7 @@ 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
......
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;
ApiIDs string // api表注册内容
Flag int // 表示对应状态 0 代表创建, 1 代表回滚 ...
}
......@@ -8,6 +8,8 @@ import (
func InitAutoCodeRouter(Router *gin.RouterGroup) {
AutoCodeRouter := Router.Group("autoCode")
{
AutoCodeRouter.POST("getSysHistory", v1.GetSysHistory) // 获取回滚记录分页
AutoCodeRouter.POST("rollback", v1.RollBack) // 回滚
AutoCodeRouter.POST("preview", v1.PreviewTemp) // 获取自动创建代码预览
AutoCodeRouter.POST("createTemp", v1.CreateTemp) // 创建自动化代码
AutoCodeRouter.GET("getTables", v1.GetTables) // 获取对应数据库的表
......
......@@ -141,3 +141,7 @@ func DeleteApisByIds(ids request.IdsReq) (err error) {
err = global.GVA_DB.Delete(&[]model.SysApi{}, "id in ?", ids.Ids).Error
return err
}
func DeleteApiByIds(ids []string) (err error) {
return global.GVA_DB.Delete(model.SysApi{}, ids).Error
}
......@@ -2,6 +2,7 @@ package service
import (
"errors"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
......@@ -9,6 +10,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"text/template"
......@@ -98,7 +100,7 @@ func PreviewTemp(autoCode model.AutoCodeStruct) (map[string]string, error) {
//@param: model.AutoCodeStruct
//@return: err error
func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
func CreateTemp(autoCode model.AutoCodeStruct, ids ...uint) (err error) {
dataList, fileList, needMkdir, err := getNeedList(&autoCode)
if err != nil {
return err
......@@ -125,6 +127,13 @@ func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
return
}
}()
bf := strings.Builder{}
idBf := strings.Builder{}
injectionCodeMeta := strings.Builder{}
for _, id := range ids {
idBf.WriteString(strconv.Itoa(int(id)))
idBf.WriteString(";")
}
if autoCode.AutoMoveFile { // 判断是否需要自动转移
for index, _ := range dataList {
addAutoMoveFile(&dataList[index])
......@@ -146,18 +155,51 @@ func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
if err != nil {
return err
}
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)"))
// 保存生成信息
for _, data := range dataList {
if len(data.autoMoveFilePath) != 0 {
bf.WriteString(data.autoMoveFilePath)
bf.WriteString(";")
}
}
if global.GVA_CONFIG.AutoCode.TransferRestart {
go func() {
_ = utils.Reload()
}()
}
return errors.New("创建代码成功并移动文件成功")
//return errors.New("创建代码成功并移动文件成功")
} else { // 打包
if err := utils.ZipFiles("./ginvueadmin.zip", fileList, ".", "."); err != nil {
if err = utils.ZipFiles("./ginvueadmin.zip", fileList, ".", "."); err != nil {
return err
}
}
if autoCode.TableName != "" {
err = CreateAutoCodeHistory(bf.String(),
injectionCodeMeta.String(),
autoCode.TableName,
idBf.String(),
)
} else {
err = CreateAutoCodeHistory(bf.String(),
injectionCodeMeta.String(),
autoCode.StructName,
idBf.String(),
)
}
if err != nil {
return err
}
if autoCode.AutoMoveFile {
return errors.New("创建代码成功并移动文件成功")
}
return nil
}
//@author: [piexlmax](https://github.com/piexlmax)
......@@ -215,6 +257,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
......@@ -267,7 +313,7 @@ func addAutoMoveFile(data *tplData) {
//@param: a *model.AutoCodeStruct
//@return: err error
func AutoCreateApi(a *model.AutoCodeStruct) (err error) {
func AutoCreateApi(a *model.AutoCodeStruct) (ids []uint, err error) {
var apiList = []model.SysApi{
{
Path: "/" + a.Abbreviation + "/" + "create" + a.StructName,
......@@ -307,17 +353,20 @@ func AutoCreateApi(a *model.AutoCodeStruct) (err error) {
},
}
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
for _, v := range apiList {
var api model.SysApi
if errors.Is(tx.Where("path = ? AND method = ?", v.Path, v.Method).First(&api).Error, gorm.ErrRecordNotFound) {
if err := tx.Create(&v).Error; err != nil { // 遇到错误时回滚事务
if err = tx.Create(&v).Error; err != nil { // 遇到错误时回滚事务
return err
} else {
ids = append(ids, v.ID)
}
}
}
return nil
})
return err
return ids, err
}
func getNeedList(autoCode *model.AutoCodeStruct) (dataList []tplData, fileList []string, needMkdir []string, err error) {
......@@ -361,10 +410,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,
......
package service
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/utils"
"strings"
"go.uber.org/zap"
)
// CreateAutoCodeHistory RouterPath : RouterPath@RouterString;RouterPath2@RouterString2
func CreateAutoCodeHistory(autoCodeMeta string, injectionMeta string, tableName string, apiIds string) error {
return global.GVA_DB.Create(&model.SysAutoCodeHistory{
AutoCodeMeta: autoCodeMeta,
InjectionMeta: injectionMeta,
TableName: tableName,
ApiIDs: apiIds,
}).Error
}
// RollBack 回滚
func RollBack(id uint) error {
md := model.SysAutoCodeHistory{}
if err := global.GVA_DB.First(&md, id).Error; err != nil {
return err
}
// 清除API表
err := DeleteApiByIds(strings.Split(md.ApiIDs, ";"))
if err != nil {
global.GVA_LOG.Error("ClearTag DeleteApiByIds:", zap.Error(err))
}
// 获取全部表名
err, dbNames := GetTables(global.GVA_CONFIG.Mysql.Dbname)
if err != nil {
global.GVA_LOG.Error("ClearTag GetTables:", zap.Error(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
}
func GetSysHistoryPage(info request.PageInfo) (err error, list interface{}, total int64) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
db := global.GVA_DB
var fileLists []model.SysAutoCodeHistory
err = db.Find(&fileLists).Count(&total).Error
err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&fileLists).Error
return err, fileLists, total
}
......@@ -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
......
......@@ -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: 去除结构体空格
......
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("未找到内容")
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册