web-dev-qa-db-ja.com

の仕方 POST Retrofitリクエストの本文に生のJSON全体?

この質問は以前に尋ねられたかもしれませんが、それは決定的に答えられませんでした。 1つの改造全体のJSONをRetrofitリクエストの本文の中に正確にポストするのはどのくらいですか?

同様の質問を参照してください ここ 。それとも、この答えは正しいですか - URLエンコードされ、フィールドとして渡される必要があります ?私が接続しているサービスは、投稿の本文に未加工のJSONを期待しているだけなので、本当にそうしないことを願っています。 JSONデータの特定のフィールドを探すようには設定されていません。

これを restperts で一度だけ明確にしたいのです。 1人がRetrofitを使わないと答えました。もう1つはその構文について確信が持てませんでした。他の人はそうだと思いますが、それはURLエンコードされてフィールドに配置されている場合にのみ可能です(私の場合は受け入れられません)。いいえ、Androidクライアントのすべてのサービスを書き直すことはできません。そして確かに、主要なプロジェクトでは、JSONコンテンツをフィールドプロパティ値として渡すのではなく、生のJSONをポストするのが一般的です。正しく理解して先に進みましょう。これがどのように行われるかを示す文書や例を誰かが指すことができますか?または、それが実行できない、または実行できない理由を正当な理由で説明してください。

更新:私は100%の確実性で言うことができる一つのこと。あなたはGoogleのVolleyでこれをすることができます。それは正しく組み込まれています。レトロフィットでこれを行うことができますか?

228
user3243335

@Body アノテーションは単一のリクエストボディを定義します。

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body FooRequest body);
}

RetrofitはデフォルトでGsonを使うので、FooRequestインスタンスはリクエストの唯一のボディとしてJSONとしてシリアライズされます。

public class FooRequest {
  final String foo;
  final String bar;

  FooRequest(String foo, String bar) {
    this.foo = foo;
    this.bar = bar;
  }
}

で呼び出す:

FooResponse = foo.postJson(new FooRequest("kit", "kat"));

次のようなボディが生成されます。

{"foo":"kit","bar":"kat"}

Gsonのドキュメント はオブジェクトのシリアライゼーションがどのように機能するかについてもっと多くの情報を持っています。

さて、もし本当にあなたが本当に生のJSONを本体として送りたいのなら(しかしこれにはGsonを使ってください!)あなたはまだTypedInputを使うことができます:

interface Foo {
  @POST("/jayson")
  FooResponse postRawJson(@Body TypedInput body);
}

TypedInput は "関連付けられたMIMEタイプを持つバイナリデータ"として定義されています。上記の宣言で生データを簡単に送信する方法は2つあります。

  1. 生バイトとJSON MIMEタイプを送信するには、 TypedByteArray を使用します。

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
    
  2. サブクラス TypedStringTypedJsonStringクラスを作成します。

    public class TypedJsonString extends TypedString {
      public TypedJsonString(String body) {
        super(body);
      }
    
      @Override public String mimeType() {
        return "application/json";
      }
    }
    

    そして#1と同じようにそのクラスのインスタンスを使います。

410
Jake Wharton

はい、私はそれが遅れていることを知っていますが、誰かがおそらくこれから利益を得るでしょう。

Retrofit2の使用:

私は昨晩この問題に出くわし、VolleyからRetrofit2に移行しました(そしてOP状態として、これはJsonObjectRequestでVolleyに直接組み込まれました)、そしてJakeの答えはRetrofit1.9、Retrofit2にはTypedStringがありません。

私のケースでは、JSONObjectに変換されたいくつかのnull値を含むMap<String,Object>を送信する必要がありました(@FieldMapで飛行せず、特殊文字も変換されず、一部は変換されます)。そして Square

@Bodyアノテーションを使用して、HTTPリクエスト本文として使用するオブジェクトを指定できます。

オブジェクトは、Retrofitインスタンスで指定されたコンバーターを使用して変換されます。コンバーターが追加されていない場合は、RequestBodyのみを使用できます。

したがって、これはRequestBodyおよびResponseBodyを使用するオプションです。

インターフェースで@BodyRequestBodyを使用します

public interface ServiceApi
{
    @POST("prefix/user/{login}")
    Call<ResponseBody> login(@Path("login") String postfix, @Body RequestBody params);  
}

呼び出しポイントでRequestBodyを作成し、MediaTypeであることを示し、JSONObjectを使用してマップを適切な形式に変換します。

Map<String, Object> jsonParams = new ArrayMap<>();
//put something inside the map, could be null
jsonParams.put("code", some_code);

RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(new JSONObject(jsonParams)).toString());
//serviceCaller is the interface initialized with retrofit.create...
Call<ResponseBody> response = serviceCaller.login("loginpostfix", body);

response.enqueue(new Callback<ResponseBody>()
    {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
        {
            try
            {
             //get your response....
              Log.d(TAG, "RetroFit2.0 :RetroGetLogin: " + rawResponse.body().string());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable throwable)
        {
        // other stuff...
        }
    });

これが誰にも役立つことを願っています!


上記のエレガントなKotlinバージョン。アプリケーションコードの残りの部分でJSON変換からパラメーターを抽出できます。

interface ServiceApi {

    fun login(username: String, password: String) =
            jsonLogin(createJsonRequestBody(
                "username" to username, "password" to password))

    @POST("/api/login")
    fun jsonLogin(@Body params: RequestBody): Deferred<LoginResult>

    private fun createJsonRequestBody(vararg params: Pair<String, String>) =
            RequestBody.create(
                okhttp3.MediaType.parse("application/json; charset=utf-8"), 
                JSONObject(mapOf(*params)).toString())

}
134
TommySM

クラスの代わりに、ボディパラメータを送信するためにHashMap<String, Object>を直接使用することもできます。

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}
133
Boopathi

Retrofit2 、あなたが生のパラメータを送りたいときは スカラー を使わなければなりません。

まずあなたのgradleにこれを追加してください。

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'

あなたのインターフェース

public interface ApiInterface {

    String URL_BASE = "http://10.157.102.22/rest/";

    @Headers("Content-Type: application/json")
    @POST("login")
    Call<User> getUser(@Body String body);

}

活動

   public class SampleActivity extends AppCompatActivity implements Callback<User> {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ApiInterface.URL_BASE)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        ApiInterface apiInterface = retrofit.create(ApiInterface.class);


        // prepare call in Retrofit 2.0
        try {
            JSONObject paramObject = new JSONObject();
            paramObject.put("email", "[email protected]");
            paramObject.put("pass", "4384984938943");

            Call<User> userCall = apiInterface.getUser(paramObject.toString());
            userCall.enqueue(this);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onResponse(Call<User> call, Response<User> response) {
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
    }
}

JsonObjectを使うのがその方法です:

  1. このようにあなたのインターフェースを作成します。

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
    
  2. JsonObjectをjsons構造体に合わせて作成します。

    JsonObject obj = new JsonObject();
    JsonObject payerReg = new JsonObject();
    payerReg.addProperty("crc","aas22");
    payerReg.addProperty("payerDevManufacturer","Samsung");
    obj.add("payerReg",payerReg);
    /*json/*
        {"payerReg":{"crc":"aas22","payerDevManufacturer":"Samsung"}}
    /*json*/
    
  3. サービスに連絡してください。

    service.registerPayer(obj, callBackRegistraPagador);
    
    Callback<JsonObject> callBackRegistraPagador = new Callback<JsonObject>(){
        public void success(JsonObject object, Response response){
            System.out.println(object.toString());
        }
    
        public void failure(RetrofitError retrofitError){
            System.out.println(retrofitError.toString());
        }
    };
    

そしてそれだ!私の個人的な意見では、それはpojosを作り、クラスの混乱を扱うことよりもずっと良いです。これはもっとずっときれいです。

36
superUser

私は特にJakeがTypedStringサブクラス above を提案しているのが好きです。実際にプッシュアップする予定のPOSTデータの種類に基づいてさまざまなサブクラスを作成でき、それぞれに独自のカスタム調整セットがあります。

Retrofit APIのJSON POSTメソッドにヘッダー注釈を追加することもできます。…

@Headers( "Content-Type: application/json" )
@POST("/json/foo/bar/")
Response fubar( @Body TypedString sJsonBody ) ;

…しかし、サブクラスを使うことはより明らかに自己文書化です。

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
10
zerobandwidth

1)依存関係を追加する

 compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

2)Api Handlerクラスを作る

    public class ApiHandler {


  public static final String BASE_URL = "URL";  

    private static Webservices apiService;

    public static Webservices getApiService() {

        if (apiService == null) {

           Gson gson = new GsonBuilder()
                    .setLenient()
                    .create();
            Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).baseUrl(BASE_URL).build();

            apiService = retrofit.create(Webservices.class);
            return apiService;
        } else {
            return apiService;
        }
    }


}

3)Jsonスキーマ2のpojoからBeanクラスを作成する

覚えている
- ターゲット言語: Java ソースタイプ:JSON - 注釈スタイル:Gson - 選択 ゲッターとセッターを含む - また選択可能 追加のプロパティを許可

http://www.jsonschema2pojo.org/

4)API呼び出しのためのインターフェイスを作る

    public interface Webservices {

@POST("ApiUrlpath")
    Call<ResponseBean> ApiName(@Body JsonObject jsonBody);

}

フォームデータパラメータがある場合は、以下の行を追加してください。

@Headers("Content-Type: application/x-www-form-urlencoded")

フォームデータパラメータの他のチェック方法はこちら link

5)パラメータとしてボディに渡すためのJsonObjectを作る

 private JsonObject ApiJsonMap() {

    JsonObject gsonObject = new JsonObject();
    try {
        JSONObject jsonObj_ = new JSONObject();
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");


        JsonParser jsonParser = new JsonParser();
        gsonObject = (JsonObject) jsonParser.parse(jsonObj_.toString());

        //print parameter
        Log.e("MY gson.JSON:  ", "AS PARAMETER  " + gsonObject);

    } catch (JSONException e) {
        e.printStackTrace();
    }

    return gsonObject;
}

6)Apiに電話をする

private void ApiCallMethod() {
    try {
        if (CommonUtils.isConnectingToInternet(MyActivity.this)) {
            final ProgressDialog dialog;
            dialog = new ProgressDialog(MyActivity.this);
            dialog.setMessage("Loading...");
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();

            Call<ResponseBean> registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap());
            registerCall.enqueue(new retrofit2.Callback<ResponseBean>() {
                @Override
                public void onResponse(Call<ResponseBean> registerCall, retrofit2.Response<ResponseBean> response) {

                    try {
                        //print respone
                        Log.e(" Full json gson => ", new Gson().toJson(response));
                        JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
                        Log.e(" responce => ", jsonObj.getJSONObject("body").toString());

                        if (response.isSuccessful()) {

                            dialog.dismiss();
                            int success = response.body().getSuccess();
                            if (success == 1) {



                            } else if (success == 0) {



                            }  
                        } else {
                            dialog.dismiss();


                        }


                    } catch (Exception e) {
                        e.printStackTrace();
                        try {
                            Log.e("Tag", "error=" + e.toString());

                            dialog.dismiss();
                        } catch (Resources.NotFoundException e1) {
                            e1.printStackTrace();
                        }

                    }
                }

                @Override
                public void onFailure(Call<ResponseBean> call, Throwable t) {
                    try {
                        Log.e("Tag", "error" + t.toString());

                        dialog.dismiss();
                    } catch (Resources.NotFoundException e) {
                        e.printStackTrace();
                    }
                }

            });

        } else {
            Log.e("Tag", "error= Alert no internet");


        }
    } catch (Resources.NotFoundException e) {
        e.printStackTrace();
    }
}
7
Adil

これまでの努力の結果、基本的な違いはJsonObjectの代わりにJSONObjectをパラメータとして送信する必要があることです。

4
umair151

ScalarsConverterFactoryを後付けに追加します。

gradleで:

implementation'com.squareup.retrofit2:converter-scalars:2.5.0'

あなたの改装:

retrofit = new Retrofit.Builder()
            .baseUrl(WEB_DOMAIN_MAIN)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

呼び出しインターフェースの@BodyパラメーターをStringに変更します。@Headers("Content-Type: application/json")を追加することを忘れないでください。

@Headers("Content-Type: application/json")
@POST("/api/getUsers")
Call<List<Users>> getUsers(@Body String rawJsonString);

今、あなたは生のjsonを投稿することができます。

4
ali-star

jsonを送信するために次を使用

final JSONObject jsonBody = new JSONObject();
    try {

        jsonBody.put("key", "value");

    } catch (JSONException e){
        e.printStackTrace();
    }
    RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(jsonBody).toString());

そしてそれをurlに渡します

@Body RequestBody key
3
Mahesh Pandit

トップの答えに基づいて、私はすべての要求のためにPOJOを作る必要がないという解決策を持っています。

例、このJSONを投稿したいです。

{
    "data" : {
        "mobile" : "qwer",
        "password" : "qwer"
    },
    "commom" : {}
}

それから、私はこのような共通クラスを作成します。

import Java.util.Map;
import Java.util.HashMap;

public class WRequest {

    Map<String, Object> data;
    Map<String, Object> common;

    public WRequest() {
        data = new HashMap<>();
        common = new HashMap<>();
    }
}

最後に、私はJSONが必要なとき

WRequest request = new WRequest();
request.data.put("type", type);
request.data.put("page", page);

アノテーション@Bodyとマークされたリクエストは、その後Retrofitに渡すことができます。

3
wjploop

@Bodyパラメータとして複合オブジェクトを使用すると、RetrofitのGSONConverterではうまくいかないことがわかりました(それを使用しているという仮定の下で)。それを扱うときはJsonObjectではなくJSONObjectを使用する必要があります。明確にすることなくNameValueParamsを追加します - ロギングインターセプターの依存性やその他の卑劣な行動を追加する場合にのみ確認できます。

だから私はこれに取り組むための最善のアプローチを見つけたRequestBodyを使用しています。あなたは単純なapi呼び出しであなたのオブジェクトをRequestBodyに変えてそれを起動します。私の場合は、地図を変換しています。

   val map = HashMap<String, Any>()
        map["orderType"] = orderType
        map["optionType"] = optionType
        map["baseAmount"] = baseAmount.toString()
        map["openSpotRate"] = openSpotRate.toString()
        map["premiumAmount"] = premiumAmount.toString()
        map["premiumAmountAbc"] = premiumAmountAbc.toString()
        map["conversionSpotRate"] = (premiumAmountAbc / premiumAmount).toString()
        return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSONObject(map).toString())

これが呼び出しです。

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>
2
peresisUser

追加のクラスを作成したくない場合やJSONObjectを使用したくない場合は、HashMapを使用できます。

改装インタフェース:

@POST("/rest/registration/register")
fun signUp(@Body params: HashMap<String, String>): Call<ResponseBody>

コール:

val map = hashMapOf(
    "username" to username,
    "password" to password,
    "firstName" to firstName,
    "surname" to lastName
)

retrofit.create(TheApi::class.Java)
     .signUp(map)
     .enqueue(callback)
2
SoftDesigner

ここで与えられた答えをより明確にするために、これが拡張機能の使用方法です。 これはKotlinを使用している場合のみです

com.squareup.okhttp3:okhttp:4.0.1を使用している場合、MediaTypeおよびRequestBodyのオブジェクトを作成する古い方法は廃止されており、では使用できませんKotlin

拡張機能を使用して文字列からMediaTypeオブジェクトとResponseBodyオブジェクトを取得する場合は、最初に次の行を使用する予定のクラスに追加します。

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

この方法でMediaTypeのオブジェクトを直接取得できるようになりました

val mediaType = "application/json; charset=utf-8".toMediaType()

RequestBodyのオブジェクトを取得するには、まずこの方法で、送信するJSONObjectを文字列に変換します。 mediaTypeオブジェクトを渡す必要があります。

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
1
Devenom

私がこれを試してみました:あなたがあなたのRetrofitインスタンスを作成しているとき、retrofitビルダーにこのコンバーターファクトリーを加えてください:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
1

API呼び出しごとにpojoクラスを作成したくない場合は、ハッシュマップを使用できます。

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","[email protected]");
        hashMap.put("password","1234");

そして、このように送ってください

Call<JsonElement> register(@Body HashMap registerApiPayload);
0
jatin rana