feat(database): 实现数据库功能并优化数据导出

- 新增数据库相关 API 和服务
- 实现数据导出功能,支持导出到 JSON 文件
- 优化数据导入流程,增加数据校验
- 新增数据库页面,展示解析数据和统计信息
- 更新捕获页面,支持导入数据到数据库
This commit is contained in:
hu xiaotong
2025-07-04 12:48:40 +08:00
parent 910e2d4c4d
commit 1b90af57ba
20 changed files with 973 additions and 356312 deletions

View File

@@ -2,8 +2,8 @@ package service
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"time"
"equipment-analyzer/internal/capture"
@@ -13,18 +13,37 @@ import (
)
type App struct {
config *config.Config
logger *utils.Logger
captureService *CaptureService
parserService *ParserService
config *config.Config
logger *utils.Logger
captureService *CaptureService
parserService *ParserService
database *model.Database
databaseService *DatabaseService
}
func NewApp(cfg *config.Config, logger *utils.Logger) *App {
// 初始化数据库
database, err := model.NewDatabase()
if err != nil {
logger.Error("初始化数据库失败", "error", err)
// 如果数据库初始化失败,仍然创建应用,但数据库功能不可用
return &App{
config: cfg,
logger: logger,
captureService: NewCaptureService(cfg, logger),
parserService: NewParserService(cfg, logger),
}
}
databaseService := NewDatabaseService(database, logger)
return &App{
config: cfg,
logger: logger,
captureService: NewCaptureService(cfg, logger),
parserService: NewParserService(cfg, logger),
config: cfg,
logger: logger,
captureService: NewCaptureService(cfg, logger),
parserService: NewParserService(cfg, logger),
database: database,
databaseService: databaseService,
}
}
@@ -43,6 +62,15 @@ func (a *App) BeforeClose(ctx context.Context) (prevent bool) {
func (a *App) Shutdown(ctx context.Context) {
a.logger.Info("应用关闭")
// 关闭数据库连接
if a.database != nil {
if err := a.database.Close(); err != nil {
a.logger.Error("关闭数据库连接失败", "error", err)
} else {
a.logger.Info("数据库连接已关闭")
}
}
}
// GetNetworkInterfaces 获取网络接口列表
@@ -130,6 +158,80 @@ func (a *App) ExportData(hexDataList []string, filename string) error {
return nil
}
// ExportCurrentData 导出当前数据库中的数据到文件
func (a *App) ExportCurrentData(filename string) error {
if a.databaseService == nil {
return fmt.Errorf("数据库服务未初始化")
}
// 从数据库获取最新数据
parsedResult, err := a.GetLatestParsedDataFromDatabase()
if err != nil {
a.logger.Error("获取数据库数据失败", "error", err)
return err
}
if parsedResult == nil || (len(parsedResult.Items) == 0 && len(parsedResult.Heroes) == 0) {
return fmt.Errorf("没有数据可导出")
}
// 创建导出数据格式
exportData := map[string]interface{}{
"items": parsedResult.Items,
"heroes": parsedResult.Heroes,
}
// 序列化为JSON
jsonData, err := json.MarshalIndent(exportData, "", " ")
if err != nil {
a.logger.Error("序列化数据失败", "error", err)
return err
}
// 写入文件
err = utils.WriteFile(filename, jsonData)
if err != nil {
a.logger.Error("写入文件失败", "error", err)
return err
}
a.logger.Info("数据导出成功", "filename", filename, "items_count", len(parsedResult.Items), "heroes_count", len(parsedResult.Heroes))
return nil
}
// GetCurrentDataForExport 获取当前数据库中的数据,供前端导出使用
func (a *App) GetCurrentDataForExport() (string, error) {
if a.databaseService == nil {
return "", fmt.Errorf("数据库服务未初始化")
}
// 从数据库获取最新数据
parsedResult, err := a.GetLatestParsedDataFromDatabase()
if err != nil {
a.logger.Error("获取数据库数据失败", "error", err)
return "", err
}
if parsedResult == nil || (len(parsedResult.Items) == 0 && len(parsedResult.Heroes) == 0) {
return "", fmt.Errorf("没有数据可导出")
}
// 创建导出数据格式
exportData := map[string]interface{}{
"items": parsedResult.Items,
"heroes": parsedResult.Heroes,
}
// 序列化为JSON
jsonData, err := json.MarshalIndent(exportData, "", " ")
if err != nil {
a.logger.Error("序列化数据失败", "error", err)
return "", err
}
return string(jsonData), nil
}
// GetCaptureStatus 获取抓包状态
func (a *App) GetCaptureStatus() model.CaptureStatus {
return model.CaptureStatus{
@@ -145,13 +247,9 @@ func (a *App) getStatusMessage() string {
return "准备就绪"
}
// ReadRawJsonFile 供前端调用读取output_raw.json内容
// ReadRawJsonFile 已废弃请使用GetLatestParsedDataFromDatabase从数据库获取数据
func (a *App) ReadRawJsonFile() (*model.ParsedResult, error) {
data, err := ioutil.ReadFile("output_raw.json")
if err != nil {
return nil, err
}
return a.parserService.ReadRawJsonFile(string(data))
return a.GetLatestParsedDataFromDatabase()
}
// StopAndParseCapture 停止抓包并解析数据,供前端调用
@@ -161,5 +259,101 @@ func (a *App) StopAndParseCapture() (*model.ParsedResult, error) {
a.logger.Error("停止抓包并解析数据失败", "error", err)
return nil, err
}
// 将解析结果保存到数据库
if a.databaseService != nil && result != nil {
// 序列化装备数据
itemsJSON := "[]"
if result.Items != nil {
if jsonData, err := json.Marshal(result.Items); err == nil {
itemsJSON = string(jsonData)
}
}
// 序列化英雄数据
heroesJSON := "[]"
if result.Heroes != nil {
if jsonData, err := json.Marshal(result.Heroes); err == nil {
heroesJSON = string(jsonData)
}
}
// 保存到数据库
sessionName := fmt.Sprintf("capture_%d", time.Now().Unix())
if err := a.databaseService.SaveParsedDataToDatabase(sessionName, itemsJSON, heroesJSON); err != nil {
a.logger.Error("保存解析数据到数据库失败", "error", err)
// 不返回错误,因为解析成功了,只是保存失败
} else {
a.logger.Info("解析数据已保存到数据库", "session_name", sessionName)
}
}
return result, nil
}
// ========== 数据库相关API ==========
// SaveParsedDataToDatabase 保存解析后的数据到数据库
func (a *App) SaveParsedDataToDatabase(sessionName string, itemsJSON, heroesJSON string) error {
if a.databaseService == nil {
return fmt.Errorf("数据库服务未初始化")
}
return a.databaseService.SaveParsedDataToDatabase(sessionName, itemsJSON, heroesJSON)
}
// GetLatestParsedDataFromDatabase 从数据库获取最新的解析数据
func (a *App) GetLatestParsedDataFromDatabase() (*model.ParsedResult, error) {
if a.databaseService == nil {
return nil, fmt.Errorf("数据库服务未初始化")
}
itemsJSON, heroesJSON, err := a.databaseService.GetLatestParsedDataFromDatabase()
if err != nil {
return nil, err
}
// 解析装备数据
var items []interface{}
if itemsJSON != "" {
if err := json.Unmarshal([]byte(itemsJSON), &items); err != nil {
return nil, fmt.Errorf("解析装备数据失败: %w", err)
}
}
// 解析英雄数据
var heroes []interface{}
if heroesJSON != "" {
if err := json.Unmarshal([]byte(heroesJSON), &heroes); err != nil {
return nil, fmt.Errorf("解析英雄数据失败: %w", err)
}
}
return &model.ParsedResult{
Items: items,
Heroes: heroes,
}, nil
}
// SaveAppSetting 保存应用设置
func (a *App) SaveAppSetting(key, value string) error {
if a.databaseService == nil {
return fmt.Errorf("数据库服务未初始化")
}
return a.databaseService.SaveAppSetting(key, value)
}
// GetAppSetting 获取应用设置
func (a *App) GetAppSetting(key string) (string, error) {
if a.databaseService == nil {
return "", fmt.Errorf("数据库服务未初始化")
}
return a.databaseService.GetAppSetting(key)
}
// GetAllAppSettings 获取所有应用设置
func (a *App) GetAllAppSettings() (map[string]string, error) {
if a.databaseService == nil {
return nil, fmt.Errorf("数据库服务未初始化")
}
return a.databaseService.GetAllAppSettings()
}