【问题标题】:how to parse multiple query params and pass them to a sql command如何解析多个查询参数并将它们传递给 sql 命令
【发布时间】:2020-03-21 16:16:17
【问题描述】:

我在 go 中玩其他 API,当我用这个进行 get 调用时

http://localhost:8000/photos?albumId=1&id=1

我只想返回 db 中对应于 alubmId=1 和 id =1 的值,或查询中的任何其他键,而不存储为变量,然后将其传递给查询,当我不提供任何查询参数我希望它返回数据库中的所有帖子

  func getPhotos(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            var photos []Photo

            db, err = sql.Open("mysql", "root:$pwd@tcp(127.0.0.1:3306)/typicode")
            if err != nil {
                    panic(err.Error())
            }

            defer db.Close()

            for k, v := range r.URL.Query() {
                    fmt.Printf("%s: %s\n", k, v)
            }

            result, err := db.Query("SELECT id, albumId, Title,thumbnailUrl,url from photo")
            if err != nil {
                    panic(err.Error())
            }

            defer result.Close()

            for result.Next() {
                    var photo Photo
                    err := result.Scan(&photo.Id, &photo.AlbumId, &photo.Title, &photo.Url, &photo.Thumbnailurl)
                    if err != nil {
                            panic(err.Error())
                    }
                    photos = append(photos, photo)
            }
            json.NewEncoder(w).Encode(photos)
    }

【问题讨论】:

  • “不存储为变量,然后将其传递给查询” 为什么?您还如何告诉数据库应该返回哪些行?如果不使用带有搜索条件的 WHEREHAVING 子句,您将如何过滤表记录?
  • @mkopriva 我的意思是关于我们正在循环遍历 URL.Query 并获取专辑 ID 和 ID 的查询,这是在 2 次迭代中得到的,我想在一次迭代中得到它,所以我可以使用 WHERE 子句传递它们。现在我有两个变量专辑 id 和 id ,传递从循环中获得的值,将这些变量分配给它,然后传递给查询,我不想这样做

标签: mysql rest go


【解决方案1】:

首先,您需要一组可以在查询中使用的有效表列,这是为了避免因拼写错误的列和恶意输入的 sql 注入造成不必要的错误。

var photocolumns = map[string]struct{}{
    "id":      {},
    "albumId": {},
    // all the other columns you accept as input
}

现在取决于数据库,您可能需要也可能不需要解析查询值并将它们转换为对应列的正确类型。您可以利用列映射将每列与正确的转换器类型/功能相关联。

// a wrapper around strconv.Atoi that has the signature of the map-value type below
func atoi(s string) (interface{}, error) {
    return strconv.Atoi(s)
}

var photocolumns = map[string]func(string) (interface{}, error) {
    "id":      atoi,
    "albumId": atoi,
    // all the other columns you accept as input
}

然后,您所需要的只是一个循环,您可以在其中完成所有需要的工作。您获得正确的列名,将值转换为正确的类型,将转换后的值聚合成一个切片以便可以将其传递给数据库,并构造 WHERE 子句以便将其连接到 sql 查询字符串。

where := ""
params := []interface{}{}
for k, v := range r.URL.Query() {
    if convert, ok := photocolumns[k]; ok {
        param, err := convert(v[0])
        if err != nil {
            fmt.Println(err)
            return
        }

        params = append(params, param)
        where += k + " = ? AND " 
    }
}
if len(where) > 0 {
    // prefix the string with WHERE and remove the last " AND "
    where = " WHERE " + where[:len(where)-len(" AND ")]
}

rows, err := db.Query("SELECT id, albumId, Title,thumbnailUrl,url from photo" + where, params...)
// ...

【讨论】:

    猜你喜欢
    • 2010-09-18
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    相关资源
    最近更新 更多