在Golang中处理URL中的动态参数

时间:2017-07-03 20:58:37

标签: go gorilla go-gorm

目前正在开发Golang中的API Rest。我有CRUD所有表的过程。现在有人要我开发一个端点,根据URL中发送的参数在其中一个表中进行搜索。假设这是我对该表的结构:

type Media struct {
    ID                         uint       
    Key                   string     
    RecordKey           string     
    RecordID            string     
    SystemMediaKey      string          
    MediaObjectID       string   
    ChangedByID         string   
    ChangedByKey        string   
    MediaCategory              string   
    MimeType                   string   
    ShortDescription           string   
    LongDescription            string   
    EntryTimestamp             time.Time
    ModificationTimestamp      time.Time  
    DeletedAtTimestamp         *time.Time 
    MediaModificationTimestamp time.Time
    MediaURL                   string   
    MediaHTML                  string   
    Order                      int      
    Group                      string   
    Width                      int      
    Height                     int      
    ImageSize                  string   
    ResourceName               string  
    ClassName                  string 
    Permission                 *string
    MediaStatus                string
}

现在,他可以在URL中向我发送全部或部分字段,我需要将这些值分配给我的结构,以便能够根据分配给对象的数据在数据库中进行搜索。

我正在使用Gorm处理数据库,gorilla / schema的所有内容,以便在POST请求和Julien Schmidt路由器上分配值。现在,我的问题是:

  1. 我应该在路由中配置什么来接受动态参数?
  2. 如何将URL中包含的值分配给Media对象类型? 谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用reflect包来迭代字段并按名称设置它们。请注意,reflect软件包使用起来非常困难,如果使用不当,会出现panic的一些危险。

另请注意,url.Values.Get仅返回第一个值(有关详细信息,请参阅https://godoc.org/net/url#Values.Get

编辑:我添加了代码来解释结构中的指针。他们的处理方式不同。

https://play.golang.org/p/AO4lYx7xka

package main

import (
    "fmt"
    "net/url"
    "reflect"
    "time"
)

type Media struct {
    ID                         uint
    Key                        string
    RecordKey                  string
    RecordID                   string
    SystemMediaKey             string
    MediaObjectID              string
    ChangedByID                string
    ChangedByKey               string
    MediaCategory              string
    MimeType                   string
    ShortDescription           string
    LongDescription            string
    EntryTimestamp             time.Time
    ModificationTimestamp      time.Time
    DeletedAtTimestamp         *time.Time
    MediaModificationTimestamp time.Time
    MediaURL                   string
    MediaHTML                  string
    Order                      int
    Group                      string
    Width                      int
    Height                     int
    ImageSize                  string
    ResourceName               string
    ClassName                  string
    Permission                 *string
    MediaStatus                string
}

func main() {

    testUrl := "www.example.com/test?MimeType=themimetype&Key=thekey&Permission=admin"

    u, err := url.Parse(testUrl)
    if err != nil {
        fmt.Println(err)
        return
    }

    params := u.Query()

    media := &Media{}

    val := reflect.ValueOf(media)

    for i := 0; i < val.Elem().NumField(); i++ {
        // get the reflect.StructField so we can get the Name
        f := val.Elem().Type().Field(i)

        // check if URL.Values contains the field
        if v := params.Get(f.Name); v != "" {
            // get the reflect.Value associated with the Field
            field := val.Elem().FieldByName(f.Name)

            kind := field.Kind()

            // you must switch for each reflect.Kind (associated with the type in your struct)
            // so you know which Set... method to call
            switch kind {
            case reflect.String:
                field.SetString(v)
            case reflect.Ptr:
                // pointers are a special case that must be handled manually unfortunately.
                // because they default to nil, calling Elem() won't reveal the underlying type
                // so you must simply string match the struct values that are pointers.
                switch f.Name {
                case "Permission":
                    newVal := reflect.New(reflect.TypeOf(v))
                    newVal.Elem().SetString(v)
                    field.Set(newVal.Elem().Addr())
                case "DeletedAtTimestamp":
                }
            }

        }
    }

    fmt.Printf("%#v\n", media)
    fmt.Println(*media.Permission)
}

答案 1 :(得分:0)

我终于设法使用this library将地图转换为结构。唯一的问题是,我必须预先处理URL.Query() Values返回的地图,因为它为每个值返回一个数组,我只需要值而不是数组。