From 8d6c211767089f7444f7c1bd4a1117579b555c77 Mon Sep 17 00:00:00 2001 From: vipg Date: Tue, 11 Nov 2025 18:23:51 +0800 Subject: [PATCH] add --- backend/country/src/logic/read.go | 229 +++++++++++++++++++++++++++++- backend/country/src/main.go | 6 +- backend/提示词条.md | 15 +- 3 files changed, 240 insertions(+), 10 deletions(-) diff --git a/backend/country/src/logic/read.go b/backend/country/src/logic/read.go index 697a16f..322dceb 100644 --- a/backend/country/src/logic/read.go +++ b/backend/country/src/logic/read.go @@ -1 +1,228 @@ -package logic \ No newline at end of file +package logic + +import ( + "country/db" + "net/http" + "strconv" + "time" + "strings" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "go.uber.org/zap" +) + +// ReadRequest 读取请求参数结构 +type ReadRequest struct { + CountryID string `form:"country_id"` // 国家ID,可选 + Name string `form:"name"` // 国家名称,可选 + Code string `form:"code"` // 国家代码,可选 + Page string `form:"page"` // 页码,可选 + PageSize string `form:"page_size"` // 每页条数,可选 +} + +// ReadData 读取响应数据结构 +type ReadData struct { + Total int64 `json:"total"` // 总条数 + Page int `json:"page"` // 当前页码 + PageSize int `json:"page_size"`// 每页条数 + Items []CountryInfoViewItem `json:"items"` // 数据列表 +} + +// CountryInfoViewItem 视图数据项结构 +type CountryInfoViewItem struct { + CountryID string `json:"country_id"` // 国家ID + Name string `json:"name"` // 国家名称 + Code string `json:"code"` // 国家代码 +} + +// ReadResponse 读取响应结构 +type ReadResponse struct { + Success bool `json:"success"` // 操作是否成功 + Message string `json:"message"` // 提示信息 + Data ReadData `json:"data"` // 响应数据 +} + +// ReadHandler 处理国家信息查询逻辑 +func ReadHandler(c *gin.Context) { + startTime := time.Now() + // 获取或生成请求ID + reqID := c.Request.Header.Get("X-ReadRequest-ID") + if reqID == "" { + reqID = uuid.New().String() + zap.L().Debug("✨ 生成新的请求ID", zap.String("req_id", reqID)) + } + + // 记录请求接收日志 + zap.L().Info("📥 收到国家查询请求", + zap.String("req_id", reqID), + zap.String("path", c.Request.URL.Path), + zap.String("method", c.Request.Method), + ) + + // 绑定请求参数 + var req ReadRequest + if err := c.ShouldBindQuery(&req); err != nil { + zap.L().Warn("⚠️ 请求参数解析失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusBadRequest, ReadResponse{ + Success: false, + Message: "请求参数格式错误", + }) + return + } + + // 验证查询条件至少有一个不为空 + if req.CountryID == "" && req.Name == "" && req.Code == "" { + zap.L().Warn("⚠️ 请求参数验证失败", + zap.String("req_id", reqID), + zap.String("reason", "country_id、name、code不能同时为空"), + ) + c.JSON(http.StatusBadRequest, ReadResponse{ + Success: false, + Message: "请求参数错误:country_id、name、code不能同时为空", + }) + return + } + + // 处理分页参数默认值 + page, err := strconv.Atoi(req.Page) + if err != nil || page < 1 { + page = 1 + } + pageSize, err := strconv.Atoi(req.PageSize) + if err != nil || pageSize < 1 { + pageSize = 20 + } + + zap.L().Debug("✅ 请求参数验证通过", + zap.String("req_id", reqID), + zap.String("country_id", req.CountryID), + zap.String("name", req.Name), + zap.String("code", req.Code), + zap.Int("page", page), + zap.Int("page_size", pageSize), + ) + + // 构建查询条件和参数 + whereClauses := []string{} + args := []interface{}{} + paramIndex := 1 + + if req.CountryID != "" { + whereClauses = append(whereClauses, "country_id = $"+strconv.Itoa(paramIndex)) + args = append(args, req.CountryID) + paramIndex++ + } + if req.Name != "" { + whereClauses = append(whereClauses, "name LIKE $"+strconv.Itoa(paramIndex)) + args = append(args, "%"+req.Name+"%") + paramIndex++ + } + if req.Code != "" { + whereClauses = append(whereClauses, "code LIKE $"+strconv.Itoa(paramIndex)) + args = append(args, "%"+req.Code+"%") + paramIndex++ + } + + // 构建基础SQL + baseSQL := "SELECT country_id, name, code FROM country_info_view" + countSQL := "SELECT COUNT(*) FROM country_info_view" + if len(whereClauses) > 0 { + whereStr := " WHERE " + strings.Join(whereClauses, " AND ") + baseSQL += whereStr + countSQL += whereStr + } + + // 计算分页偏移量 + offset := (page - 1) * pageSize + + // 拼接分页SQL + querySQL := baseSQL + " ORDER BY country_id LIMIT $"+strconv.Itoa(paramIndex)+" OFFSET $"+strconv.Itoa(paramIndex+1) + args = append(args, pageSize, offset) + + // 查询总条数 + var total int64 + err = db.DB.QueryRow(countSQL, args...[:len(args)-2]...).Scan(&total) + if err != nil { + zap.L().Error("❌ 查询总条数失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "查询数据失败,请稍后重试", + }) + return + } + + // 执行分页查询 + rows, err := db.DB.Query(querySQL, args...) + if err != nil { + zap.L().Error("❌ 分页查询失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "查询数据失败,请稍后重试", + }) + return + } + defer rows.Close() + + // 处理查询结果 + var items []CountryInfoViewItem + for rows.Next() { + var item CountryInfoViewItem + if err := rows.Scan(&item.CountryID, &item.Name, &item.Code); err != nil { + zap.L().Error("❌ 解析查询结果失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "数据处理失败,请稍后重试", + }) + return + } + items = append(items, item) + } + + // 检查行迭代过程中是否发生错误 + if err := rows.Err(); err != nil { + zap.L().Error("❌ 行迭代错误", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "查询数据失败,请稍后重试", + }) + return + } + + // 记录请求处理耗时 + duration := time.Since(startTime) + zap.L().Info("✅ 国家查询请求处理完成", + zap.String("req_id", reqID), + zap.Int64("total", total), + zap.Int("page", page), + zap.Int("page_size", pageSize), + zap.Duration("duration", duration), + ) + + // 返回成功响应 + c.JSON(http.StatusOK, ReadResponse{ + Success: true, + Message: "查询成功", + Data: ReadData{ + Total: total, + Page: page, + PageSize: pageSize, + Items: items, + }, + }) +} \ No newline at end of file diff --git a/backend/country/src/main.go b/backend/country/src/main.go index e4fba60..5c41f24 100644 --- a/backend/country/src/main.go +++ b/backend/country/src/main.go @@ -35,9 +35,13 @@ func main() { r.POST("/country/create", logic.CreateHandler) zap.L().Info("✅ 创建接口注册完成: POST /country/create") + // 注册读取国家的接口,POST请求,由logic.ReadHandler + r.POST("/country/read", logic.ReadHandler) + zap.L().Info("✅ 读取接口注册完成: POST /country/read") + // 注册更新国家的接口,POST请求,由logic.UpdateHandler r.POST("/country/update", logic.UpdateHandler) - zap.L().Info("✅ 删除接口注册完成: POST /country/update") + zap.L().Info("✅ 更新接口注册完成: POST /country/update") // 注册删除国家的接口,POST请求,由logic.DeleteHandler处理 r.POST("/country/delete", logic.DeleteHandler) diff --git a/backend/提示词条.md b/backend/提示词条.md index ce6d5e3..b3d6c2c 100644 --- a/backend/提示词条.md +++ b/backend/提示词条.md @@ -17,19 +17,18 @@ --- 分析这个项目,在 update.go 中完成以下需求: -1、接收 country_id,name,code 两个参数。 +1、接收 country_id,name,code 参数。 2、确认提交的 country_id 参数有不能为空,如果为空,则返回提示。 3、确认提交的 name,code 两个参数,必须有一个不能为空,如果都为空,则返回提示。 4、如果 name 不为空,开启事务保存到 name 中。 5、如果 code 不为空,开启事务保存到 code 中。 6、如果 name,code 都不为空,开启事务保存到 name,code 中。 --- -分析这个项目,在 update.go 中完成以下需求: +分析这个项目,在 read.go 中完成以下需求: -1、接收 country_id,name,code 两个参数。 -2、确认提交的 country_id 参数有不能为空,如果为空,则返回提示。 -3、确认提交的 name,code 两个参数,必须有一个不能为空,如果都为空,则返回提示。 -4、如果 name 不为空,开启事务保存到 name 中。 -5、如果 code 不为空,开启事务保存到 code 中。 -6、如果 name,code 都不为空,开启事务保存到 name,code 中。 +1、接收 country_id,name,code,page,page_size 参数。 +2、确认提交的 country_id,name,code 必须有一个不能为空,如果都为空,则返回提示。 +3、确认提交的 page,page_size, 如果为空,则 page 默认为 1,page_size 默认为20。 +3、根据参数去 country_info_view 中查找数据,并做分页查询。 +4、将查找的数据分页返回。 --- \ No newline at end of file