2

Go项目实战—参数绑定,类型转换

 1 year ago
source link: https://studygolang.com/articles/35738
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Go项目实战—参数绑定,类型转换

qiaoshuai951123 · 2天之前 · 479 次点击 · 预计阅读时间 5 分钟 · 大约8小时之前 开始浏览    

goshop开源项目的更新

备注:前面项目中用到的代码已经分享到GitHub中去了,并且以后所有项目中会出现的代码都会提交上去,欢迎查阅。感兴趣的可以点个star哦~
https://gitee.com/jobhandsome/goshop/

最近在研究微服务框架go-zero,没有更新,在这里说声抱歉,后面会持续更新新的功能。请继续关注~~~~

今天考虑参数绑定获取。这里肯定有些疑惑,之前不是封装了获取全部参数的方法吗?

回顾之前咱们封装了获取全部参数的方法,只能是POST请求,并且请求方式必须是:application/x-www-form-urlencoded 才能正常获取,局限性非常大。

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

  • 需求2:获取到的struct类型参数,转换成map类型用于gormDB查询?

通过分析上面的两个需求得到几个结论:

  • gin框架中可以使用参数绑定进行任意请求方式和请求类型获取请求的参数

  • 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(&params); err != nil {
  utils.Fail(ctx, "参数错误:"+err.Error(), nil)
  return
}

获取到参数后,咱们就要使用参数进行gormDB.Where查询: 首先先对 struct 转换 map

// 对应方法 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
}

需要 过滤pagepageSize,不参与查询的

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
}

前面都是铺垫,现在才是重点,使用gorm进行数据查询

// 获取 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

关注公众号「程序员小乔」

程序员小乔


有疑问加站长微信联系(非本文作者))

280

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK