This commit is contained in:
vipg
2025-11-11 18:23:51 +08:00
parent 89838b60be
commit 8d6c211767
3 changed files with 240 additions and 10 deletions

View File

@@ -1 +1,228 @@
package logic 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,
},
})
}

View File

@@ -35,9 +35,13 @@ func main() {
r.POST("/country/create", logic.CreateHandler) r.POST("/country/create", logic.CreateHandler)
zap.L().Info("✅ 创建接口注册完成: POST /country/create") zap.L().Info("✅ 创建接口注册完成: POST /country/create")
// 注册读取国家的接口POST请求由logic.ReadHandler
r.POST("/country/read", logic.ReadHandler)
zap.L().Info("✅ 读取接口注册完成: POST /country/read")
// 注册更新国家的接口POST请求由logic.UpdateHandler // 注册更新国家的接口POST请求由logic.UpdateHandler
r.POST("/country/update", logic.UpdateHandler) r.POST("/country/update", logic.UpdateHandler)
zap.L().Info("✅ 删除接口注册完成: POST /country/update") zap.L().Info("✅ 更新接口注册完成: POST /country/update")
// 注册删除国家的接口POST请求由logic.DeleteHandler处理 // 注册删除国家的接口POST请求由logic.DeleteHandler处理
r.POST("/country/delete", logic.DeleteHandler) r.POST("/country/delete", logic.DeleteHandler)

View File

@@ -17,19 +17,18 @@
--- ---
分析这个项目,在 update.go 中完成以下需求: 分析这个项目,在 update.go 中完成以下需求:
1、接收 country_id,namecode 两个参数。 1、接收 country_id,namecode 参数。
2、确认提交的 country_id 参数有不能为空,如果为空,则返回提示。 2、确认提交的 country_id 参数有不能为空,如果为空,则返回提示。
3、确认提交的 namecode 两个参数,必须有一个不能为空,如果都为空,则返回提示。 3、确认提交的 namecode 两个参数,必须有一个不能为空,如果都为空,则返回提示。
4、如果 name 不为空,开启事务保存到 name 中。 4、如果 name 不为空,开启事务保存到 name 中。
5、如果 code 不为空,开启事务保存到 code 中。 5、如果 code 不为空,开启事务保存到 code 中。
6、如果 namecode 都不为空,开启事务保存到 namecode 中。 6、如果 namecode 都不为空,开启事务保存到 namecode 中。
--- ---
分析这个项目,在 update.go 中完成以下需求: 分析这个项目,在 read.go 中完成以下需求:
1、接收 country_id,namecode 两个参数。 1、接收 country_idnamecodepagepage_size 参数。
2、确认提交的 country_id 参数有不能为空,如果为空,则返回提示。 2、确认提交的 country_idnamecode 必须有一个不能为空,如果为空,则返回提示。
3、确认提交的 namecode 两个参数,必须有一个不能为空,如果为空,则返回提示 3、确认提交的 pagepage_size, 如果为空,则 page 默认为 1page_size 默认为20
4、如果 name 不为空,开启事务保存到 name 中 3、根据参数去 country_info_view 中查找数据,并做分页查询
5、如果 code 不为空,开启事务保存到 code 中 4、将查找的数据分页返回
6、如果 namecode 都不为空,开启事务保存到 namecode 中。
--- ---