【问题标题】:Send complex object using Retrofit2使用 Retrofit2 发送复杂对象
【发布时间】:2020-04-20 10:11:21
【问题描述】:

我正在尝试使用 Retrofit2 和 Kotlin 发送一个复杂对象作为我的请求的参数。 该对象的结构如下:

{
  "id": "..."
  "token": "..."
  "message": "..."
  "list1": [
    { "id": 1, "value": 2 },
    { "id": 2, "value": 5 }
    //and so on...
  ]
  "list2": [
    { "id": 10, "value": 16 },
    { "id": 11, "value": 21 }
    //and so on...
  ]
  //and so on...
}

列表字段的数量是各种(可以是 2 个列表,可以是 10 个)以及每个列表中的项目数。 我正在使用以下代码来实现这一点,之前用适当的值填充了我的地图:

@JvmSuppressWildcards
@FormUrlEncoded
@POST("get_data.php")
fun getResponse(
    @FieldMap params: Map<String, Any>
): Observable<ResponseModelResult>

由于某种原因,该方法无法正常工作,服务器只是忽略了我的参数。 我也尝试将它们作为@Body 字符串/对象发送,但似乎服务器只接受 FormUrlEncoded 数据

谁能给我一个例子,我应该如何使用@FieldMap 方法发送这些数据作为参数?

【问题讨论】:

  • 您应该先创建 Json 对象,然后您可以使用 @Field 将此对象作为字符串传递。为此,您将需要任何键来传递此对象。
  • @MaradiyaKrupa 抱歉,我不明白。您所说的“将需要任何键来传递此对象”是什么意思?
  • 如果服务器只接受 FormUrlEncoded,您的代码应该可以正常工作。 @FieldMap(encoded = true) 这是你唯一能做的改变。

标签: android kotlin retrofit retrofit2


【解决方案1】:

如果您提供 api 或文档的演示 url 或其他可以帮助我更具体地找出问题的东西,那么我将根据您的 api 机制更新我的答案,现在您可以试试这个:

像这样声明你的 api 接口:

    @POST("get_data.php") 
    fun getResponse(@Query("params") params: String): Observable<ResponseModelResult>

像这样制作复杂的对象:

    val jsonObject1 = JsonObject().apply {
        addProperty("id", 1)
        addProperty("value", 1)
    }

    val jsonObject2 = JsonObject().apply {
        addProperty("id", 2)
        addProperty("value", 2)
    }

    val list1 = JsonArray().apply {
        add(jsonObject1)
        add(jsonObject2)
    }

    val jsonObject10 = JsonObject().apply {
        addProperty("id", 10)
        addProperty("value", 16)
    }

    val jsonObject11 = JsonObject().apply {
        addProperty("id", 11)
        addProperty("value", 21)
    }

    val list2 = JsonArray().apply {
        add(jsonObject10)
        add(jsonObject11)
    }

    val params = JsonObject().apply {
        addProperty("id", "...")
        addProperty("token", "...")
        addProperty("message", "...")
        add("list1", list1)
        add("list2", list2)
    }.toString()

现在你准备好了,调用你的 api 传递 params 作为查询参数,如:getResponse(params)

【讨论】:

  • 感谢您的回复。您提供的代码有 2 个问题: 1. 我不能在同一个请求中同时使用 FormUrlEncoded 和 Query(在我的情况下需要 FormUrlEncoded)。 2.如果我理解你的方法是正确的,顶级参数的键称为“参数”,所有其他对象(参数)都是嵌套的。但是服务器无论如何都无法解析“params”键,我需要直接发送id、token、消息等
【解决方案2】:

您可以使用 @Field 代替 @FieldMap,如下所示。

@JvmSuppressWildcards @FormUrlEncoded @POST("get_data.php") 有趣的getResponse( @Field("你的钥匙") jsonObject: String ): 可观察的

将 json 对象作为字符串传递。

【讨论】:

  • 现在知道了。但问题是列表的数量可能会动态变化。例如。用户可以选择 1、2 甚至 10 个列表,因此在我的情况下,按照您的建议单独发送每个字段并不是一个好主意。
【解决方案3】:

最后,我找到了解决方案。似乎改造无法处理 &lt;String, Any&gt; 映射,因此最简单的方法是以类似于 Postman 的方式发送请求参数。

val params = mutableMapOf<String, String>()
params["id"] = ...
params["token"] = ...
params["message"] = ...

params["list1[0][id]"] = "${1}"
params["list1[0][value]"] = "${2}"
params["list1[1][id]"] = "${2}"
params["list1[1][value]"] = "${5}"

params["list2[0][id]"] = "${10}"
params["list2[0][value]"] = "${16}"

//and so on

然后,在我的 ApiService 中:

@Headers("Content-Type: application/x-www-form-urlencoded")
@FormUrlEncoded
@POST("get_data.php")
fun getResponse(
    @FieldMap params: Map<String, String>
): Observable<ResponseModelResult>

这可能不是总体上最好的方法,但至少它对我有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多