diff --git a/mayfly_go_web/src/views/ops/db/DbList.vue b/mayfly_go_web/src/views/ops/db/DbList.vue
index 9591c3ac..f52af841 100644
--- a/mayfly_go_web/src/views/ops/db/DbList.vue
+++ b/mayfly_go_web/src/views/ops/db/DbList.vue
@@ -81,7 +81,7 @@
详情
SQL执行记录
- 导出
+ 导出
@@ -180,14 +180,25 @@
-
-
-
- 结构
- 数据
- 结构+数据
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -333,7 +344,7 @@ const columns = ref([
TableColumn.new('name', '名称'),
TableColumn.new('database', '数据库').isSlot().setMinWidth(70),
TableColumn.new('remark', '备注'),
- TableColumn.new('more', '更多').isSlot().setMinWidth(200).fixedRight(),
+ TableColumn.new('more', '更多').isSlot().setMinWidth(220).fixedRight(),
]);
// 该用户拥有的的操作列按钮权限
@@ -422,13 +433,17 @@ const state = reactive({
tableNameSearch: '',
tableCommentSearch: '',
},
+
exportDialog: {
visible: false,
dbId: 0,
type: 3,
data: [],
value: [],
+ contents: [],
+ extName: '',
},
+
columnDialog: {
visible: false,
columns: [],
@@ -653,6 +668,8 @@ const onDumpDbs = async (row: any) => {
state.exportDialog.value = []
state.exportDialog.data = data
state.exportDialog.dbId = row.id;
+ state.exportDialog.contents = ["结构", "数据"]
+ state.exportDialog.extName = "sql"
state.exportDialog.visible = true;
};
@@ -662,9 +679,17 @@ const onDumpDbs = async (row: any) => {
const dumpDbs = () => {
isTrue(state.exportDialog.value.length > 0, '请添加要导出的数据库');
const a = document.createElement('a');
+ let type = 0
+ for (let c of state.exportDialog.contents) {
+ if (c == "结构") {
+ type += 1
+ } else if (c == "数据") {
+ type += 2
+ }
+ }
a.setAttribute(
'href',
- `${config.baseApiUrl}/dbs/${state.exportDialog.dbId}/dump?db=${state.exportDialog.value.join(',')}&type=${state.exportDialog.type}&token=${getSession(
+ `${config.baseApiUrl}/dbs/${state.exportDialog.dbId}/dump?db=${state.exportDialog.value.join(',')}&type=${type}&extName=${state.exportDialog.extName}&token=${getSession(
'token'
)}`
);
diff --git a/server/internal/db/api/db.go b/server/internal/db/api/db.go
index 8b9425e2..a8af29d6 100644
--- a/server/internal/db/api/db.go
+++ b/server/internal/db/api/db.go
@@ -1,6 +1,7 @@
package api
import (
+ "compress/gzip"
"fmt"
"io"
"mayfly-go/internal/db/api/form"
@@ -32,6 +33,18 @@ type Db struct {
TagApp tagapp.TagTree
}
+type gzipResponseWriter struct {
+ writer *gzip.Writer
+}
+
+func (g gzipResponseWriter) WriteString(data string) {
+ g.writer.Write([]byte(data))
+}
+
+func (g gzipResponseWriter) Close() {
+ g.writer.Close()
+}
+
const DEFAULT_ROW_SIZE = 5000
// @router /api/dbs [get]
@@ -227,6 +240,13 @@ func (d *Db) DumpSql(rc *req.Ctx) {
dbNamesStr := g.Query("db")
dumpType := g.Query("type")
tablesStr := g.Query("tables")
+ extName := g.Query("extName")
+ switch extName {
+ case ".gz", ".gzip", "gz", "gzip":
+ extName = ".gz"
+ default:
+ extName = ""
+ }
// 是否需要导出表结构
needStruct := dumpType == "1" || dumpType == "3"
@@ -237,9 +257,12 @@ func (d *Db) DumpSql(rc *req.Ctx) {
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, db.TagPath), "%s")
now := time.Now()
- filename := fmt.Sprintf("%s.%s.sql", db.Name, now.Format("20060102150405"))
+ filename := fmt.Sprintf("%s.%s.sql%s", db.Name, now.Format("20060102150405"), extName)
g.Header("Content-Type", "application/octet-stream")
g.Header("Content-Disposition", "attachment; filename="+filename)
+ if extName != ".gz" {
+ g.Header("Content-Encoding", "gzip")
+ }
var dbNames, tables []string
if len(dbNamesStr) > 0 {
@@ -248,7 +271,8 @@ func (d *Db) DumpSql(rc *req.Ctx) {
if len(dbNames) == 1 && len(tablesStr) > 0 {
tables = strings.Split(tablesStr, ",")
}
- writer := g.Writer
+ writer := gzipResponseWriter{writer: gzip.NewWriter(g.Writer)}
+ defer writer.Close()
for _, dbName := range dbNames {
d.dumpDb(writer, db, dbName, tables, needStruct, needData)
}
@@ -256,7 +280,7 @@ func (d *Db) DumpSql(rc *req.Ctx) {
rc.ReqParam = fmt.Sprintf("DB[id=%d, tag=%s, name=%s, databases=%s, tables=%s, dumpType=%s]", db.Id, db.TagPath, db.Name, dbNamesStr, tablesStr, dumpType)
}
-func (d *Db) dumpDb(writer gin.ResponseWriter, db *entity.Db, dbName string, tables []string, needStruct bool, needData bool) {
+func (d *Db) dumpDb(writer gzipResponseWriter, db *entity.Db, dbName string, tables []string, needStruct bool, needData bool) {
writer.WriteString("-- ----------------------------")
writer.WriteString("\n-- 导出平台: mayfly-go")
writer.WriteString(fmt.Sprintf("\n-- 导出时间: %s ", time.Now().Format("2006-01-02 15:04:05")))
@@ -269,10 +293,8 @@ func (d *Db) dumpDb(writer gin.ResponseWriter, db *entity.Db, dbName string, tab
switch dbInst.Info.Type {
case entity.DbTypeMysql:
writer.WriteString(fmt.Sprintf("use `%s`;\n", dbName))
- case entity.DbTypePostgres:
- writer.WriteString(fmt.Sprintf("\\connect `%s`;\n", dbName))
default:
- biz.IsTrue(false, "数据库类型必须为 MySQL 或 PostgreSQL")
+ biz.IsTrue(false, "数据库类型必须为 %s", entity.DbTypeMysql)
}
dbMeta := dbInst.GetMeta()
if len(tables) == 0 {