Private
Public Access
1
0

新增:数据库可见性过滤与连接管理增强

功能:
- 支持配置 MySQL/MongoDB 可见数据库列表
- 连接删除时自动清理关联数据并关闭连接池
- 新增加载数据库列表 API
- 数据库错误提示优化

改进:
- 代码简化:消除重复的表单验证和密码处理逻辑
- ResultPanel 表格高度计算重构
- 删除调试日志和临时文件

后端:
- 新增 VisibleDatabases 字段到连接模型
- DeleteConnection 使用事务确保数据一致性
- LoadAllDatabases 支持 MySQL/MongoDB 数据库列表加载
This commit is contained in:
2026-02-13 00:38:25 +08:00
parent 0229cab550
commit d62b9ca7bd
15 changed files with 993 additions and 386 deletions

View File

@@ -1,6 +1,7 @@
package storage
import (
"context"
"encoding/json"
"fmt"
"u-desk/internal/crypto"
@@ -55,13 +56,14 @@ func (s *ConnectionService) SaveConnection(conn *models.DbConnection) error {
if conn.ID > 0 {
// 更新模式
updateData := map[string]interface{}{
"name": conn.Name,
"type": conn.Type,
"host": conn.Host,
"port": conn.Port,
"username": conn.Username,
"database": conn.Database,
"options": conn.Options,
"name": conn.Name,
"type": conn.Type,
"host": conn.Host,
"port": conn.Port,
"username": conn.Username,
"database": conn.Database,
"options": conn.Options,
"visible_databases": conn.VisibleDatabases,
}
// 如果提供了新密码,加密后更新
@@ -111,7 +113,26 @@ func (s *ConnectionService) GetConnection(id uint) (*models.DbConnection, error)
// DeleteConnection 删除连接配置
func (s *ConnectionService) DeleteConnection(id uint) error {
return s.db.Delete(&models.DbConnection{}, id).Error
var conn models.DbConnection
if err := s.db.First(&conn, id).Error; err != nil {
return nil // 连接不存在视为成功
}
// 使用事务删除
return s.db.Transaction(func(tx *gorm.DB) error {
// 清理关联数据
tx.Where("connection_id = ?", id).Delete(&models.SqlResultHistory{})
tx.Where("connection_id = ?", id).Delete(&models.SqlTab{})
// 删除连接
if err := tx.Delete(&conn).Error; err != nil {
return err
}
// 关闭连接池
dbclient.GetPool().CloseConnection(id, conn.Type)
return nil
})
}
// TestConnection 测试连接(需要根据类型调用不同的测试方法)
@@ -163,3 +184,127 @@ func testRedisConnection(host string, port int, password string) error {
func testMongoConnection(host string, port int, username, password, database, authSource, authMechanism string) error {
return dbclient.TestMongoConnectionWithOptions(host, port, username, password, database, authSource, authMechanism)
}
// TestConnectionWithParams 使用参数测试连接(不保存数据)
func (s *ConnectionService) TestConnectionWithParams(dbType, host string, port int, username, password, database, options string, id uint) error {
// 如果是编辑模式且有ID获取已保存的密码
if id > 0 && password == "" {
conn, err := s.GetConnection(id)
if err != nil {
return fmt.Errorf("获取连接信息失败: %v", err)
}
decryptPassword, err := crypto.DecryptPassword(conn.Password)
if err != nil {
return fmt.Errorf("密码解密失败: %v", err)
}
password = decryptPassword
}
// 根据类型测试连接
switch dbType {
case "mysql":
return testMySQLConnection(host, port, username, password, database)
case "redis":
return testRedisConnection(host, port, password)
case "mongo":
// 解析 Options 获取 MongoDB 连接参数
authSource := ""
authMechanism := ""
if options != "" {
var opts map[string]interface{}
if err := json.Unmarshal([]byte(options), &opts); err == nil {
if as, ok := opts["authSource"].(string); ok && as != "" {
authSource = as
}
if am, ok := opts["authMechanism"].(string); ok && am != "" {
authMechanism = am
}
}
}
return testMongoConnection(host, port, username, password, database, authSource, authMechanism)
default:
return fmt.Errorf("不支持的数据库类型: %s", dbType)
}
}
// LoadAllDatabases 加载全部数据库列表
func (s *ConnectionService) LoadAllDatabases(dbType, host string, port int, username, password, database, options string, id uint) ([]string, error) {
// 如果是编辑模式且有ID获取已保存的密码
if id > 0 && password == "" {
conn, err := s.GetConnection(id)
if err != nil {
return nil, fmt.Errorf("获取连接信息失败: %v", err)
}
decryptPassword, err := crypto.DecryptPassword(conn.Password)
if err != nil {
return nil, fmt.Errorf("密码解密失败: %v", err)
}
password = decryptPassword
}
// 根据类型加载数据库列表
switch dbType {
case "mysql":
return loadMySQLDatabases(host, port, username, password, database)
case "mongo":
return loadMongoDatabases(host, port, username, password, database, options)
case "redis":
// Redis 没有数据库概念,返回空列表
return []string{}, nil
default:
return nil, fmt.Errorf("不支持的数据库类型: %s", dbType)
}
}
// loadMySQLDatabases 加载 MySQL 数据库列表
func loadMySQLDatabases(host string, port int, username, password, defaultDatabase string) ([]string, error) {
config := &dbclient.MySQLConfig{
Host: host,
Port: port,
Username: username,
Password: password,
Database: defaultDatabase,
}
client, err := dbclient.NewMySQLClient(config)
if err != nil {
return nil, err
}
defer client.Close()
return client.ListDatabases(context.Background())
}
// loadMongoDatabases 加载 MongoDB 数据库列表
func loadMongoDatabases(host string, port int, username, password, defaultDatabase, options string) ([]string, error) {
// 解析 Options 获取 MongoDB 连接参数
authSource := ""
authMechanism := ""
if options != "" {
var opts map[string]interface{}
if err := json.Unmarshal([]byte(options), &opts); err == nil {
if as, ok := opts["authSource"].(string); ok && as != "" {
authSource = as
}
if am, ok := opts["authMechanism"].(string); ok && am != "" {
authMechanism = am
}
}
}
mongoConfig := &dbclient.MongoConfig{
Host: host,
Port: port,
Username: username,
Password: password,
Database: defaultDatabase,
AuthSource: authSource,
AuthMechanism: authMechanism,
}
client, err := dbclient.NewMongoClient(mongoConfig)
if err != nil {
return nil, err
}
defer client.Close()
return client.ListDatabases(context.Background())
}