【问题标题】:How to send object parameter in Retrofit GET request?如何在 Retrofit GET 请求中发送对象参数?
【发布时间】:2017-09-18 13:37:07
【问题描述】:

我有一个像这样工作的后端服务器

"api/videos?search_object={"cat_id" :2, "channel_id" : 3, etc}

基本上,您可以提供一个搜索对象作为输入,它会根据该对象过滤列表。现在我想通过 Retrofit 使用这个服务,像这样

@GET("videos")
Call<VideoListResponse> listVideos(@Query("search_object") VideoSearchObject videoSearchObject);

但上面的代码不起作用,我可以先将 VideoSearchModel 转换为 JSON 字符串,然后像这样传递给改造

@GET("videos")
Call<VideoListResponse> listVideos(@Query("search_object") String jsonString);

我想知道是否有更好更清晰的方法?任何建议将不胜感激。

【问题讨论】:

  • 如果你想在查询中发送json字符串,恐怕这是唯一的方法。

标签: android gson retrofit retrofit2 android-networking


【解决方案1】:

Retrofit 2 支持它。您所要做的就是实现一个自定义转换器工厂,并重写 stringConverter() 方法。

考虑以下带有自定义注释的改造友好界面:

@Target(PARAMETER)
@Retention(RUNTIME)
@interface ToJson {
}
interface IService {

    @GET("api/videos")
    Call<Void> get(
            @ToJson @Query("X") Map<String, Object> request
    );

}

注解用于表示必须转换为字符串的参数。

模拟OkHttpClient 始终以“HTTP 200 OK”响应并转储请求 URL:

private static final OkHttpClient mockHttpClient = new OkHttpClient.Builder()
        .addInterceptor(chain -> {
            System.out.println(chain.request().url());
            return new Response.Builder()
                    .request(chain.request())
                    .protocol(HTTP_1_0)
                    .code(HTTP_OK)
                    .body(ResponseBody.create(MediaType.parse("application/json"), "OK"))
                    .build();
        })
        .build();
private static final Gson gson = new Gson();
private static final Retrofit retrofit = new Retrofit.Builder()
        .client(mockHttpClient)
        .baseUrl("http://whatever")
        .addConverterFactory(new Converter.Factory() {
            @Override
            public Converter<?, String> stringConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
                if ( !hasToJson(annotations) ) {
                    return super.stringConverter(type, annotations, retrofit);
                }
                return value -> gson.toJson(value, type);
            }

            private boolean hasToJson(final Annotation[] annotations) {
                for ( final Annotation annotation : annotations ) {
                    if ( annotation instanceof ToJson ) {
                        return true;
                    }
                }
                return false;
            }
        })
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

要对其进行测试,您可以简单地调用服务接口方法:

final IService service = retrofit.create(IService.class);
service.get(ImmutableMap.of("k1", "v1", "k2", "v2")).execute();

结果:

http://whatever/api/videos?X={%22k1%22:%22v1%22,%22k2%22:%22v2%22}

其中X 参数参数是{"k1":"v1","k2":"v2"} 的编码表示。

【讨论】:

    【解决方案2】:
    "api/videos?search_object={"cat_id" :2, "channel_id" : 3, etc}
    

    基本上你可以给一个搜索对象作为输入

    不,您没有将对象作为输入。您提供包含在{ } 中的多个参数,以便它看起来 像一个对象(JavaScript 对象,不是Java 对象)。实际上它只是一个字符串。

    构造的 url 只是一堆字符。 url 中没有“对象”之类的东西。

    @Query("search_object") String jsonString 一样继续这样做。尽管您可能还想将参数从jsonString 重命名为searchString,因为它就是这样。它不是 JSON 字符串。 JSON 字符串会将所有" 字符转义,如\"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-14
      • 2017-06-23
      • 1970-01-01
      相关资源
      最近更新 更多