Go 項目實戰—參數綁定,類型轉換

goshop 開源項目的更新

備註:前面項目中用到的代碼已經分享到 GitHub 中去了,並且以後所有項目中會出現的代碼都會提交上去,歡迎查閱。感興趣的可以點個 star 哦~  

https://gitee.com/jobhandsome/goshop/

最近在研究微服務框架 go-zero,沒有更新,在這裏說聲抱歉,後面會持續更新新的功能。請繼續關注~~~~

今天考慮參數綁定獲取。這裏肯定有些疑惑,之前不是封裝了獲取全部參數的方法嗎?

回顧之前咱們封裝了獲取全部參數的方法,只能是 POST 請求,並且請求方式必須是:application/x-www-form-urlencoded 才能正常獲取,侷限性非常大。

需求 1:使用任意請求方式,任意請求格式都可以獲取到指定的值?

需求 2:獲取到的 struct 類型參數,轉換成 map 類型用於 gorm 的 DB 查詢?

通過分析上面的兩個需求得到幾個結論:

  1. gin 框架中可以使用參數綁定進行任意請求方式和請求類型獲取請求的參數

  2. gin 框架集成 gorm,使用 DB.Where 條件查詢時,需要傳入 map 類型的數組格式,需要 struct 轉 map。

既然知道要做什麼了,那就開始:

首先,先使用綁定的方式獲取參數:

//1. 先定義一下傳入的參數,這裏使用form進行綁定,json進行別名
type ParamsRequest struct {
  Page     int64  `form:"page" binding:"required" json:"page"`
  PageSize int64  `form:"pageSize" binding:"required" json:"pageSize"`
  Name     string `form:"name" json:"name"`
}
//2. 使用綁定來獲取請求的參數 ctx => *gin.Context
var params ParamsRequest
if err := ctx.ShouldBind(¶ms); err != nil {
  utils.Fail(ctx, "參數錯誤:"+err.Error(), nil)
  return
}

獲取到參數後,咱們就要使用參數進行 gorm 的 DB.Where 查詢:

//1. 首先先對 struct 轉換 map
paramsMap, _ := utils.AnyToMap(params)
// 對應方法 AnyToMap interface 轉 ma
func AnyToMap(v any) (map[string]any, error) {
  dataJson, err := json.Marshal(v)
  if err != nil {
    return nil, err
  }
  var MapData map[string]any
  err = json.Unmarshal(dataJson, &MapData)
  if err != nil {
    return nil, err
  }
  return MapData, nil
}
//2. 需要 過濾page和pageSize,不參與查詢的
ParamsFilter := utils.ParamsFilter("page,pageSize", paramsMap)
// 過濾指定數組中的key
func ParamsFilter(isFilterStr string, params map[string]any) map[string]any {
  var data = make(map[string]any)
  for key, value := range params {
    if value != "" {
      find := strings.Contains(isFilterStr, key)
      if !find {
        data[key] = value
      }
    }
  }
  return data
}
//3. 前面都是鋪墊,現在纔是重點
// 獲取 gorm 的 DB 句柄
DB := config.GetDB()
// 這裏使用自己定義的模型就好
var Result []*model.Category
// 使用 Scopes 傳入要分頁的指針
resErr := DB.Scopes(Paginate.Paginate(strconv.FormatInt(params.Page, 10), strconv.FormatInt(params.PageSize, 10))).Where(ParamsFilter).Find(&Result).Error
// 查詢的返回錯誤,如果有錯誤,就返回
if resErr != nil {
  utils.Fail(ctx, resErr.Error(), nil)
  return
}
// 對查詢的 struct 數組轉換 樹結構 ToTree 
var category model.Category
ResultLists := category.ToTree(Result)
utils.Success(ctx, "獲取成功", ResultLists)

對應的 model 文件:

type Category struct {
  gorm.Model
  Name     string         `form:"name" binding:"required" json:"name" gorm:"varchar(255);not null;default:'';comment:'分類名稱'"` // 分類名稱
  Pid      int64          `form:"pid" json:"pid" gorm:"size:11;not null;default:0;comment:'分類節點'"`                            // 分類節點:0根節點
  Icon     string         `form:"icon" json:"icon" gorm:"varchar(255);not null;default:'';comment:'分類圖標'"`                    // 分類圖標
  State    int64          `form:"state" json:"state" gorm:"size:1;not null;default:0;comment:'分類狀態:0未啓用,1已啓用'"`               // 分類狀態:0未啓用,1已啓用
  Sort     int64          `form:"sort" json:"sort" gorm:"size:11;not null;default:0;comment:'分類排序'"`                          // 分類排序
  Tag      string         `form:"tag" json:"tag" gorm:"varchar(255);not null;default:0;comment:'分類標籤'"`                       // 分類標籤
  Children *CategoryTrees `json:"children"`
}
// CategoryTrees 二叉樹列表
type CategoryTrees []*Category
// ToTree 轉換爲樹形結構
func (Category) ToTree(data CategoryTrees) CategoryTrees {
  // 定義 HashMap 的變量,並初始化
  TreeData := make(map[int64]*Category)
  // 先重組數據:以數據的ID作爲外層的key編號,以便下面進行子樹的數據組合
  for _, item := range data {
    TreeData[int64(item.ID)] = item
  }
  // 定義 RoleTrees 結構體
  var TreeDataList CategoryTrees
  // 開始生成樹形
  for _, item := range TreeData {
    // 如果沒有根節點樹,則爲根節點
    if item.Pid == 0 {
      // 追加到 TreeDataList 結構體中
      TreeDataList = append(TreeDataList, item)
      // 跳過該次循環
      continue
    }
    // 通過 上面的 TreeData HashMap的組合,進行判斷是否存在根節點
    // 如果存在根節點,則對應該節點進行處理
    if pItem, ok := TreeData[item.Pid]; ok {
      // 判斷當次循環是否存在子節點,如果沒有則作爲子節點進行組合
      if pItem.Children == nil {
        // 寫入子節點
        children := CategoryTrees{item}
        // 插入到 當次結構體的子節點字段中,以指針的方式
        pItem.Children = &children
        // 跳過當前循環
        continue
      }
      // 以指針地址的形式進行追加到結構體中
      *pItem.Children = append(*pItem.Children, item)
    }
  }
  return TreeDataList
}

到了這一步,咱們就實現了上面需求的功能。 更多功能請持續關注!!!!!

星球地址:https://t.zsxq.com/03MJM7YfI

程序員小喬 一個喜愛編程技術的非著名碼農人士

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6TSl-wW8gsEZkQWyb043-w