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

huangapple go评论189阅读模式
英文:

Handle dynamic parameters in URL in Golang

问题

目前我正在使用Golang开发一个API Rest。我已经完成了对所有表进行CRUD操作的过程。现在有人要求我开发一个端点,根据URL中发送的参数在其中一个表中进行搜索。假设这是我用于该表的结构体:

  1. type Media struct {
  2. ID uint
  3. Key string
  4. RecordKey string
  5. RecordID string
  6. SystemMediaKey string
  7. MediaObjectID string
  8. ChangedByID string
  9. ChangedByKey string
  10. MediaCategory string
  11. MimeType string
  12. ShortDescription string
  13. LongDescription string
  14. EntryTimestamp time.Time
  15. ModificationTimestamp time.Time
  16. DeletedAtTimestamp *time.Time
  17. MediaModificationTimestamp time.Time
  18. MediaURL string
  19. MediaHTML string
  20. Order int
  21. Group string
  22. Width int
  23. Height int
  24. ImageSize string
  25. ResourceName string
  26. ClassName string
  27. Permission *string
  28. MediaStatus string
  29. }

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

我正在使用Gorm处理与数据库的所有操作,使用gorilla/schema将值分配给POST请求,并使用Julien Schmidt Router。现在,我的问题是:

  1. 在路由中应该配置什么来接受动态参数?
  2. 如何将URL中的值分配给Media对象的属性?

谢谢!

英文:

currently am working on an API Rest in Golang. I have the process to CRUD all the tables. Now someone is asking me to develop an endpoint to search in one of that tables based on the parameters send in the URL. Let's say that this is my struct for that table:

  1. type Media struct {
  2. ID uint
  3. Key string
  4. RecordKey string
  5. RecordID string
  6. SystemMediaKey string
  7. MediaObjectID string
  8. ChangedByID string
  9. ChangedByKey string
  10. MediaCategory string
  11. MimeType string
  12. ShortDescription string
  13. LongDescription string
  14. EntryTimestamp time.Time
  15. ModificationTimestamp time.Time
  16. DeletedAtTimestamp *time.Time
  17. MediaModificationTimestamp time.Time
  18. MediaURL string
  19. MediaHTML string
  20. Order int
  21. Group string
  22. Width int
  23. Height int
  24. ImageSize string
  25. ResourceName string
  26. ClassName string
  27. Permission *string
  28. MediaStatus string
  29. }

Now, he can send me all or some of that fields in the URL, the I need to assign that values to my struct to be able to search in the database based on the data assigned to the object.

I am using Gorm to handle everything with the database, gorilla/schema to assign the values on the POST requests and the Julien Schmidt Router. Now,my questions are:

  1. What should I configure in the route to accept dynamic parameters?
  2. How can I assign the values that comes in the URL to the a type Media object?
    Thank you!

答案1

得分: 1

你可以使用reflect包按名称迭代字段并设置它们。请注意,reflect包使用起来比较麻烦,并且如果使用不当可能会导致panic的危险。

另外,请注意url.Values.Get只返回第一个值(详见https://godoc.org/net/url#Values.Get)。

编辑:我添加了处理结构体中指针的代码。它们需要特殊处理。

  1. package main
  2. import (
  3. "fmt"
  4. "net/url"
  5. "reflect"
  6. "time"
  7. )
  8. type Media struct {
  9. ID uint
  10. Key string
  11. RecordKey string
  12. RecordID string
  13. SystemMediaKey string
  14. MediaObjectID string
  15. ChangedByID string
  16. ChangedByKey string
  17. MediaCategory string
  18. MimeType string
  19. ShortDescription string
  20. LongDescription string
  21. EntryTimestamp time.Time
  22. ModificationTimestamp time.Time
  23. DeletedAtTimestamp *time.Time
  24. MediaModificationTimestamp time.Time
  25. MediaURL string
  26. MediaHTML string
  27. Order int
  28. Group string
  29. Width int
  30. Height int
  31. ImageSize string
  32. ResourceName string
  33. ClassName string
  34. Permission *string
  35. MediaStatus string
  36. }
  37. func main() {
  38. testUrl := "www.example.com/test?MimeType=themimetype&Key=thekey&Permission=admin"
  39. u, err := url.Parse(testUrl)
  40. if err != nil {
  41. fmt.Println(err)
  42. return
  43. }
  44. params := u.Query()
  45. media := &Media{}
  46. val := reflect.ValueOf(media)
  47. for i := 0; i < val.Elem().NumField(); i++ {
  48. // get the reflect.StructField so we can get the Name
  49. f := val.Elem().Type().Field(i)
  50. // check if URL.Values contains the field
  51. if v := params.Get(f.Name); v != "" {
  52. // get the reflect.Value associated with the Field
  53. field := val.Elem().FieldByName(f.Name)
  54. kind := field.Kind()
  55. // you must switch for each reflect.Kind (associated with the type in your struct)
  56. // so you know which Set... method to call
  57. switch kind {
  58. case reflect.String:
  59. field.SetString(v)
  60. case reflect.Ptr:
  61. // pointers are a special case that must be handled manually unfortunately.
  62. // because they default to nil, calling Elem() won't reveal the underlying type
  63. // so you must simply string match the struct values that are pointers.
  64. switch f.Name {
  65. case "Permission":
  66. newVal := reflect.New(reflect.TypeOf(v))
  67. newVal.Elem().SetString(v)
  68. field.Set(newVal.Elem().Addr())
  69. case "DeletedAtTimestamp":
  70. }
  71. }
  72. }
  73. }
  74. fmt.Printf("%#v\n", media)
  75. fmt.Println(*media.Permission)
  76. }

希望对你有帮助!

英文:

You could use the reflect package to iterate over the fields and set them by name. Be aware that the reflect package is arduous to use and comes with some dangers of panics if not used properly.

Also be aware that url.Values.Get only returns the first value (see https://godoc.org/net/url#Values.Get for details)

EDIT: I added code to account for the pointers in the struct. They are handled differently.

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

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;net/url&quot;
  5. &quot;reflect&quot;
  6. &quot;time&quot;
  7. )
  8. type Media struct {
  9. ID uint
  10. Key string
  11. RecordKey string
  12. RecordID string
  13. SystemMediaKey string
  14. MediaObjectID string
  15. ChangedByID string
  16. ChangedByKey string
  17. MediaCategory string
  18. MimeType string
  19. ShortDescription string
  20. LongDescription string
  21. EntryTimestamp time.Time
  22. ModificationTimestamp time.Time
  23. DeletedAtTimestamp *time.Time
  24. MediaModificationTimestamp time.Time
  25. MediaURL string
  26. MediaHTML string
  27. Order int
  28. Group string
  29. Width int
  30. Height int
  31. ImageSize string
  32. ResourceName string
  33. ClassName string
  34. Permission *string
  35. MediaStatus string
  36. }
  37. func main() {
  38. testUrl := &quot;www.example.com/test?MimeType=themimetype&amp;Key=thekey&amp;Permission=admin&quot;
  39. u, err := url.Parse(testUrl)
  40. if err != nil {
  41. fmt.Println(err)
  42. return
  43. }
  44. params := u.Query()
  45. media := &amp;Media{}
  46. val := reflect.ValueOf(media)
  47. for i := 0; i &lt; val.Elem().NumField(); i++ {
  48. // get the reflect.StructField so we can get the Name
  49. f := val.Elem().Type().Field(i)
  50. // check if URL.Values contains the field
  51. if v := params.Get(f.Name); v != &quot;&quot; {
  52. // get the reflect.Value associated with the Field
  53. field := val.Elem().FieldByName(f.Name)
  54. kind := field.Kind()
  55. // you must switch for each reflect.Kind (associated with the type in your struct)
  56. // so you know which Set... method to call
  57. switch kind {
  58. case reflect.String:
  59. field.SetString(v)
  60. case reflect.Ptr:
  61. // pointers are a special case that must be handled manually unfortunately.
  62. // because they default to nil, calling Elem() won&#39;t reveal the underlying type
  63. // so you must simply string match the struct values that are pointers.
  64. switch f.Name {
  65. case &quot;Permission&quot;:
  66. newVal := reflect.New(reflect.TypeOf(v))
  67. newVal.Elem().SetString(v)
  68. field.Set(newVal.Elem().Addr())
  69. case &quot;DeletedAtTimestamp&quot;:
  70. }
  71. }
  72. }
  73. }
  74. fmt.Printf(&quot;%#v\n&quot;, media)
  75. fmt.Println(*media.Permission)
  76. }

答案2

得分: 0

我终于成功使用了这个库,它可以将一个map转换为struct。唯一的问题是,我需要对URL.Query() Values返回的map进行预处理,因为它对每个值返回一个数组,而我只需要值,而不是数组中的值。

英文:

I finally managed to use this library that converts a map to a struct. The only thing, is that I had to pre-process the map that is returned by URL.Query() Values because it returns an array for each value and I needed only the value and not inside an array.

huangapple
  • 本文由 发表于 2017年7月4日 04:58:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/44893792.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定