|
@@ -36,10 +36,10 @@ type wafLogRepository struct {
|
|
|
*repository.Repository
|
|
|
}
|
|
|
|
|
|
-// buildExportQuery 是一个辅助函数,用于构建导出日志的公共查询条件
|
|
|
-func (r *wafLogRepository) buildExportQuery(ctx context.Context, req adminApi.ExportWafLog) *gorm.DB {
|
|
|
- // 使用 Table("waf_log as wl") 是为了给主表起一个别名,方便子查询中引用
|
|
|
- query := r.DBWithName(ctx, "admin").Model(&model.WafLog{}).Table("waf_log as wl")
|
|
|
+// buildExportQuery 是一个辅助函数,用于构建导出日志的公共查询条件(支持分表)
|
|
|
+func (r *wafLogRepository) buildExportQuery(ctx context.Context, req adminApi.ExportWafLog, tableName string) *gorm.DB {
|
|
|
+ // 使用传入的表名,给表起一个别名,方便子查询中引用
|
|
|
+ query := r.DBWithName(ctx, "admin").Model(&model.WafLog{}).Table(tableName + " as wl")
|
|
|
|
|
|
if req.RequestIp != "" {
|
|
|
query = query.Where("wl.request_ip = ?", strings.TrimSpace(req.RequestIp))
|
|
@@ -78,6 +78,43 @@ func (r *wafLogRepository) buildExportQuery(ctx context.Context, req adminApi.Ex
|
|
|
return query
|
|
|
}
|
|
|
|
|
|
+// getExportTimeRange 根据请求参数解析时间范围,用于确定需要查询的分表
|
|
|
+func (r *wafLogRepository) getExportTimeRange(req adminApi.ExportWafLog) (*time.Time, *time.Time) {
|
|
|
+ var startTime, endTime *time.Time
|
|
|
+
|
|
|
+ if req.StartTime != "" {
|
|
|
+ if t, err := time.Parse("2006-01-02 15:04:05", strings.TrimSpace(req.StartTime)); err == nil {
|
|
|
+ startTime = &t
|
|
|
+ } else if t, err := time.Parse("2006-01-02", strings.TrimSpace(req.StartTime)); err == nil {
|
|
|
+ startTime = &t
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if req.EndTime != "" {
|
|
|
+ if t, err := time.Parse("2006-01-02 15:04:05", strings.TrimSpace(req.EndTime)); err == nil {
|
|
|
+ endTime = &t
|
|
|
+ } else if t, err := time.Parse("2006-01-02", strings.TrimSpace(req.EndTime)); err == nil {
|
|
|
+ endTime = &t
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return startTime, endTime
|
|
|
+}
|
|
|
+
|
|
|
+// buildSubQueryForTable 为指定的表构建子查询
|
|
|
+func (r *wafLogRepository) buildSubQueryForTable(ctx context.Context, tableName string) *gorm.DB {
|
|
|
+ // 需要在所有可能包含"分配网关组"数据的表中查找
|
|
|
+ // 这里简化处理,先在当前表中查找,如果需要跨表查找可以进一步优化
|
|
|
+ return r.DBWithName(ctx, "admin").Table(tableName).
|
|
|
+ Select("extra_data").
|
|
|
+ Where("api_name = ?", "分配网关组").
|
|
|
+ Where("host_id = wl.host_id").
|
|
|
+ Where("uid = wl.uid").
|
|
|
+ Where("created_at <= wl.created_at").
|
|
|
+ Order("created_at DESC").
|
|
|
+ Limit(1)
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
func (r *wafLogRepository) GetWafLog(ctx context.Context, id int64) (*model.WafLog, error) {
|
|
|
var res model.WafLog
|
|
@@ -338,54 +375,159 @@ func (r *wafLogRepository) ExportWafLog(ctx context.Context, req adminApi.Export
|
|
|
return r.ExportWafLogWithPagination(ctx, req, 0, 0)
|
|
|
}
|
|
|
|
|
|
-// ExportWafLogWithPagination 使用子查询获取每条日志在当时时间点的正确网关组IP
|
|
|
+// ExportWafLogWithPagination 使用子查询获取每条日志在当时时间点的正确网关组IP(支持分表)
|
|
|
func (r *wafLogRepository) ExportWafLogWithPagination(ctx context.Context, req adminApi.ExportWafLog, page, pageSize int) ([]model.WafLogWithGatewayIP, error) {
|
|
|
- var res []model.WafLogWithGatewayIP
|
|
|
+ // 1. 解析时间范围
|
|
|
+ startTime, endTime := r.getExportTimeRange(req)
|
|
|
|
|
|
- // 1. 使用辅助函数构建基础查询
|
|
|
- query := r.buildExportQuery(ctx, req)
|
|
|
+ // 2. 获取需要查询的分表
|
|
|
+ existingTables := r.Manager.GetTableNamesWithExistenceCheck(r.DBWithName(ctx, "admin"), "waf_log", startTime, endTime)
|
|
|
+
|
|
|
+ if len(existingTables) == 0 {
|
|
|
+ return []model.WafLogWithGatewayIP{}, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(existingTables) == 1 {
|
|
|
+ // 单表查询
|
|
|
+ return r.exportFromSingleTable(ctx, req, existingTables[0], page, pageSize)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 多表查询(不分页,获取所有数据)
|
|
|
+ if page > 0 && pageSize > 0 {
|
|
|
+ return r.exportFromMultipleTablesWithPagination(ctx, req, existingTables, page, pageSize)
|
|
|
+ } else {
|
|
|
+ return r.exportFromMultipleTables(ctx, req, existingTables)
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
+// exportFromSingleTable 从单个表导出数据
|
|
|
+func (r *wafLogRepository) exportFromSingleTable(ctx context.Context, req adminApi.ExportWafLog, tableName string, page, pageSize int) ([]model.WafLogWithGatewayIP, error) {
|
|
|
+ var res []model.WafLogWithGatewayIP
|
|
|
+
|
|
|
+ // 1. 构建基础查询
|
|
|
+ query := r.buildExportQuery(ctx, req, tableName)
|
|
|
+
|
|
|
// 2. 构建子查询
|
|
|
- subQuery := r.DBWithName(ctx, "admin").Model(&model.WafLog{}).
|
|
|
- Select("extra_data").
|
|
|
- Where("api_name = ?", "分配网关组").
|
|
|
- Where("host_id = wl.host_id").
|
|
|
- Where("uid = wl.uid").
|
|
|
- Where("created_at <= wl.created_at").
|
|
|
- Order("created_at DESC").
|
|
|
- Limit(1)
|
|
|
-
|
|
|
- // 3. 添加 Select 和分页
|
|
|
+ subQuery := r.buildSubQueryForTable(ctx, tableName)
|
|
|
+
|
|
|
+ // 3. 添加 Select
|
|
|
query = query.Select("wl.*, (?) as gateway_ip_data", subQuery)
|
|
|
+
|
|
|
+ // 4. 添加分页
|
|
|
if page > 0 && pageSize > 0 {
|
|
|
offset := (page - 1) * pageSize
|
|
|
query = query.Offset(offset).Limit(pageSize)
|
|
|
}
|
|
|
-
|
|
|
- // 4. 执行查询
|
|
|
+
|
|
|
+ // 5. 执行查询
|
|
|
if err := query.Find(&res).Error; err != nil {
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
|
return []model.WafLogWithGatewayIP{}, nil
|
|
|
}
|
|
|
return nil, err
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return res, nil
|
|
|
}
|
|
|
|
|
|
+// exportFromMultipleTables 从多个表导出所有数据(不分页)
|
|
|
+func (r *wafLogRepository) exportFromMultipleTables(ctx context.Context, req adminApi.ExportWafLog, tableNames []string) ([]model.WafLogWithGatewayIP, error) {
|
|
|
+ var allResults []model.WafLogWithGatewayIP
|
|
|
+
|
|
|
+ for _, tableName := range tableNames {
|
|
|
+ tableResults, err := r.exportFromSingleTable(ctx, req, tableName, 0, 0)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("查询表 %s 失败: %v", tableName, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ allResults = append(allResults, tableResults...)
|
|
|
+ }
|
|
|
+
|
|
|
+ return allResults, nil
|
|
|
+}
|
|
|
|
|
|
-// GetWafLogExportCount 获取导出数据总数(已优化)
|
|
|
+// exportFromMultipleTablesWithPagination 从多个表导出数据(支持分页)
|
|
|
+func (r *wafLogRepository) exportFromMultipleTablesWithPagination(ctx context.Context, req adminApi.ExportWafLog, tableNames []string, page, pageSize int) ([]model.WafLogWithGatewayIP, error) {
|
|
|
+ var allResults []model.WafLogWithGatewayIP
|
|
|
+ currentOffset := (page - 1) * pageSize
|
|
|
+ remaining := pageSize
|
|
|
+
|
|
|
+ for _, tableName := range tableNames {
|
|
|
+ if remaining <= 0 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ // 先获取表的总记录数
|
|
|
+ countQuery := r.buildExportQuery(ctx, req, tableName)
|
|
|
+ var tableCount int64
|
|
|
+ if err := countQuery.Count(&tableCount).Error; err != nil {
|
|
|
+ return nil, fmt.Errorf("统计表 %s 记录数失败: %v", tableName, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果当前偏移量大于等于表记录数,跳过这个表
|
|
|
+ if currentOffset >= int(tableCount) {
|
|
|
+ currentOffset -= int(tableCount)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算在当前表中需要查询的数据
|
|
|
+ tablePageSize := remaining
|
|
|
+ if int(tableCount) - currentOffset < tablePageSize {
|
|
|
+ tablePageSize = int(tableCount) - currentOffset
|
|
|
+ }
|
|
|
+
|
|
|
+ tablePage := (currentOffset / pageSize) + 1
|
|
|
+ tableOffset := currentOffset % pageSize
|
|
|
+
|
|
|
+ // 查询当前表数据
|
|
|
+ tableResults, err := r.exportFromSingleTable(ctx, req, tableName, tablePage, tablePageSize)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("查询表 %s 失败: %v", tableName, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有偏移量,跳过前面的记录
|
|
|
+ if tableOffset > 0 && len(tableResults) > tableOffset {
|
|
|
+ tableResults = tableResults[tableOffset:]
|
|
|
+ }
|
|
|
+
|
|
|
+ allResults = append(allResults, tableResults...)
|
|
|
+ remaining -= len(tableResults)
|
|
|
+ currentOffset = 0 // 后续表从0开始
|
|
|
+ }
|
|
|
+
|
|
|
+ return allResults, nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// GetWafLogExportCount 获取导出数据总数(支持分表)
|
|
|
func (r *wafLogRepository) GetWafLogExportCount(ctx context.Context, req adminApi.ExportWafLog) (int, error) {
|
|
|
- var count int64
|
|
|
+ // 1. 解析时间范围
|
|
|
+ startTime, endTime := r.getExportTimeRange(req)
|
|
|
|
|
|
- // 直接复用 buildExportQuery 来构建查询
|
|
|
- query := r.buildExportQuery(ctx, req)
|
|
|
+ // 2. 获取需要查询的分表
|
|
|
+ existingTables := r.Manager.GetTableNamesWithExistenceCheck(r.DBWithName(ctx, "admin"), "waf_log", startTime, endTime)
|
|
|
|
|
|
- if err := query.Count(&count).Error; err != nil {
|
|
|
- return 0, err
|
|
|
+ if len(existingTables) == 0 {
|
|
|
+ return 0, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ var totalCount int64
|
|
|
+
|
|
|
+ // 3. 逐表统计
|
|
|
+ for _, tableName := range existingTables {
|
|
|
+ var tableCount int64
|
|
|
+
|
|
|
+ // 使用更新后的 buildExportQuery 方法
|
|
|
+ query := r.buildExportQuery(ctx, req, tableName)
|
|
|
+
|
|
|
+ if err := query.Count(&tableCount).Error; err != nil {
|
|
|
+ return 0, fmt.Errorf("统计表 %s 记录数失败: %v", tableName, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ totalCount += tableCount
|
|
|
}
|
|
|
|
|
|
- return int(count), nil
|
|
|
+ return int(totalCount), nil
|
|
|
}
|
|
|
|
|
|
|