Як розмістити сировину JSON у тій частині запиту на вдосконалення?


284

Це питання, можливо, було задано і раніше, але ніхто не отримав остаточної відповіді. Як саме один пост-сирий весь JSON знаходиться в тілі запиту на вдосконалення?

Дивіться подібне запитання тут . Або ця відповідь правильна, що вона повинна бути зашифрована у вигляді URL-адреси та передана як поле ? Я дуже сподіваюся, що ні, оскільки служби, до яких я підключаюсь, просто очікують сирого JSON в тілі посади. Вони не створені для пошуку конкретного поля для даних JSON.

Я просто хочу раз і назавжди прояснити це з рештою . Одна людина відповіла, що не використовує Retrofit. Інший не був певний у синтаксисі. Інший вважає, що так це можна зробити, але лише якщо його форма кодується URL-адресою та розміщується в полі (це не прийнятно в моєму випадку). Ні, я не можу перекодувати всі послуги для свого клієнта Android. І так, у великих проектах дуже часто розміщувати необроблений JSON, а не передавати вміст JSON як значення властивостей поля. Давайте розберемося і продовжимо далі. Чи може хтось вказати на документацію чи приклад, який показує, як це робиться? Або наведіть поважну причину, чому цього можна / не слід робити.

ОНОВЛЕННЯ: Одне, що я можу сказати зі 100% впевненістю. МОЖЕТЕ це зробити у Воллі Google. Він вбудований прямо. Чи можемо ми це зробити в Retrofit?


7
Пост Джейка Уортона правильний! Позначте як відповідь!
edotassi

1
Ви можете краще використовувати jsonObject.
superUser

прекрасно працює з RequestBodyцим -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);для детальної відповіді futurestud.io/tutorials/…
Kidus Tekeste

Відповіді:


461

@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." Є два способи легко надсилати необроблені дані за допомогою наведеної вище декларації:

  1. Використовуйте TypedByteArray для надсилання необроблених байтів та типу mime JSON:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Підклас TypedString для створення TypedJsonStringкласу:

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

    А потім використовуйте екземпляр цього класу, подібний до №1.


5
Дуже добре, проте чи все-таки можна зробити це, не роблячи піхов?
superUser

28
Це не працює над оновленням 2. Класи TypedInput та TypedString були видалені.
Ахмед Гегазі

2
@jakewharton Що ми можемо зробити, TypedStringоскільки його було видалено?
Джаред Берроуз

12
Для Retrofit2 ви можете використовувати RequestBodyдля створення необробленого тіла.
Борм

4
Я отримую цей винятокjava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal

155

Замість класів ми також можемо безпосередньо використовувати, наприклад, HashMap<String, Object>для надсилання параметрів тіла

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

2
У той час ви можете створити карту Hash на зразок HashMap <String, Object>, можливо для створення свого роду складних масивів та об'єктів JSON.
учень

2
Це чудово, якщо ви не хочете бути прив’язаними до якогось POJO.
Тім

2
@Ніколи ви не можете надіслати об’єкт json, використовуючи модернізацію ... ви дотримуєтесь pojo або моєї відповіді ... це природа модернізації. Якщо ви хочете більше про це, запитайте Джейка Уортона, він є хлопцем, який займається модернізацією, його відповідь також доступна з pojo .
учень

5
Я можу IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>з Моші. Я думаю, що Gson потрібен для цього
osrl

2
Якщо ви використовуєте Kotlin, використовуйте хешмак <String, Any>
peresisПользователь

148

Так, я знаю, що пізно, але хтось, мабуть, від цього виграє.

Використання Retrofit2:

Я зіткнувся з цією проблемою вчора ввечері, переходячи з Воллі на Retrofit2 (і, як заявляє ОП, це було вбудовано прямо у Воллі JsonObjectRequest), і хоча відповідь Джейка є правильною для Retrofit1.9 , Retrofit2 не має TypedString.

Мій випадок вимагав надсилання Map<String,Object>знака, який міг би містити деякі нульові значення, перетворені в JSONObject (які не будуть літати з @FieldMap, а також спеціальні символи, деякі конвертуються), так що слідуючи @bnorms натяк, і як зазначено у Square :

Об'єкт може бути визначений для використання в якості запиту HTTP з анотацією @Body.

Об'єкт також буде перетворений за допомогою перетворювача, визначеного в екземплярі Retrofit. Якщо конвертер не додано, можна використовувати лише RequestBody.

Так що це варіант використання RequestBodyі ResponseBody:

У вашому інтерфейсі використовуйте @BodyсRequestBody

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...
        }
    });

Сподіваюся, це допомагає комусь!


Елегантна версія Котліна з вищезазначеного, що дозволяє абстрагувати параметри від перетворення 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())

}

2
Так, я бачу багато складних відповідей для цього. Якщо ви використовуєте Retrofit2 і хочете займатися залпом JsonObjectRequest, все, що вам потрібно зробити, це це. Хороша відповідь.
VicVu

2
Модернізація додає ключ з назвою "nameValuePairs" у верхню частину всіх об'єктів json. Як я можу видалити цю @TommySM
nr5

1
Дякую! Це вирішило мою проблему. Тепер я можу надсилати JSONObject безпосередньо, не створюючи POJO.
Ерфан GLMPR

1
Це єдине рішення, яке допомогло мені post a null valueвласність у запиті, тіло, яке інакше було ігноровано.
Шубхрал

Я знаю, що я спізнююсь, але що jsonParams.put("code", some_code);в третьому рядку?
Naveen Niraula

81

У Retrofit2 , Коли ви хочете відправити параметри в сирому вигляді, ви повинні використовувати Scalars .

спочатку додайте це у свою ступінь:

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", "sample@gmail.com");
            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) {
    }
}

10
Хитрість полягає в тому, щоб адаптер Scalar перед Gson, інакше Gson загорне ваш серіалізований JSON вручну в String.
TWiStErRob

2
jonathan-nolasco-barrientos вам доведеться змінити .baseUrl (ApiInterface.ENDPOINT) на .baseUrl (ApiInterface.URL_BASE)
Мілад Ахмаді

2
Коли ви користуєтесь GsonConverterFactory, .toString()це не потрібно. Ви можете заявити про Call<User> getUser(@Body JsonObject body);використання JsonObjectзамість JSONObjectі передати paramObjectбезпосередньо. Це буде працювати чудово.
Ігор де Лоренці

1
@IgordeLorenzi вирішити мою проблему, оскільки я використовую весняний завантажувач, щоб отримати json тільки JsonObject з gson, працює чудово
haidarvm

1
@IgordeLorenzi Чи є різниця, який краще JSONObject або JsonObject використовувати зі скалярами.
Суміт Шукла

44

Використання 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());
        }
    };

І це його! На мою особисту думку, це набагато краще, ніж робити піхоти та працювати з класним безладом. Це набагато чистіше.


1
Що робити, якщо я не хочу надсилати значення specif в клас jsonobject. який зауваження я можу використовувати для цього вище?
Алі Гюреллі

1
Як ви бачите вищенаведений приклад ... JsonObject, оскільки це об'єкт, не використовує жодних анотацій. У вашому випадку, якщо ви не хочете надсилати конкретне значення, ви можете просто не додати його як властивість ...
superUser

1
Я маю на увазі, я не хочу надсилати значення, яке оголошено в класі. Btw я вирішив проблему. Там було анотацію до того, яке ім’я виставляється.
Алі Гюреллі

2
Це найбільш гнучкий спосіб. Ви можете сконструювати свій json об’єкт, навіть якщо ви не знаєте, скільки у вас буде полів, або навіть якщо ви не знаєте, вони називають +1 від мене
Стойчо Андрєєв

1
я отримую помилку Методи обслуговування не можуть повернутись до недійсних. для методу APIServices.signUpUser
Ерум

11

Мені особливо подобається пропозиція Джейком про TypedStringпідклас вище . Ви дійсно можете створити різноманітні підкласи на основі типів даних POST, які ви плануєте передати, кожен зі своїм власним набором послідовних налаштувань.

Також у вас є можливість додати анотацію до заголовка до методів JSON POST в API модернізації…

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

… Але використання підкласу є більш очевидним самодокументуванням.

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

1
Врятував день наочним прикладом, використовуючи TypedJsonString з пропозиції JW
miroslavign

10

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

Запам’ятайте
- Мова цілі: 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")

Інший спосіб для параметра "Форма даних" перевірте це посилання

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) Зателефонуйте Апі так

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();
    }
}

9

Я виявив, що коли ви використовуєте складений об'єкт як @Bodyпарами, він не може працювати добре із впорядкованими елементами GSONConverter(за припущенням, що ви використовуєте це). Ви повинні використовувати, JsonObjectа не JSONObjectпрацюючи з цим, це додає, NameValueParamsне будучи про це багатослівним - це ви можете бачити лише, якщо ви додасте іншу залежність від перехоплювача реєстрації та інших шнаніганів.

Тож я знайшов найкращий підхід для вирішення цього питання RequestBody. Ви звертаєте свій об'єкт до RequestBodyпростого дзвінка api та запускаєте його. У моєму випадку я перетворюю карту:

   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
Ну, це допомогло мені після гугління протягом ночі.
W4R10CK

8

Додати ScalarsConverterFactory для модернізації:

in 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.


6

Ви можете використовувати хешмап, якщо ви не хочете створювати клас pojo для кожного дзвінка API.

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","this@gmail.com");
        hashMap.put("password","1234");

А потім надсилайте так

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

4

Після стількох зусиль виявив, що основна різниця полягає в тому, що потрібно надіслати JsonObjectзамість цього JSONObjectпараметр.


Я також робив ту саму помилку: p
Мехтаб Ахмед

4

використовувати наступне для надсилання 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

4

Виходячи з верхньої відповіді, у мене є рішення не потрібно робити 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.


4

Якщо ви не хочете створювати додаткові класи або використовувати, 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)

3

Речі, необхідні для надсилання сирого json в Retrofit.

1) Обов’язково додайте наступний заголовок та видаліть будь-який інший дублікат заголовка. Оскільки в офіційній документації Retrofit вони конкретно згадуються:

Зауважте, що заголовки не перезаписують один одного. Усі заголовки з тим самим іменем будуть включені до запиту.

@Headers({"Content-Type: application/json"})

2) а. Якщо ви використовуєте фабрику перетворювачів, ви можете передавати свій json як String, JSONObject, JsonObject і навіть POJO. Також перевірили, маючи ScalarConverterFactoryне обов’язково тільки GsonConverterFactoryвиконує роботу.

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                     @Body JsonObject/POJO/String requestBody);

2) б. Якщо ви НЕ використовуєте жодної фабрики перетворювачів, ви ОБОВ'ЯЗКОВО використовувати RequestBody okhttp3 як документація Retrofit,

Об'єкт також буде перетворений за допомогою перетворювача, визначеного в екземплярі Retrofit. Якщо конвертер не додано, можна використовувати лише RequestBody.

RequestBody requestBody=RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonString);

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                 @Body RequestBody requestBody);

3) Успіх !!


2

Це те, що мені працює для поточної версії retrofit 2.6.2 ,

Перш за все, нам потрібно додати конвертер скалярів до списку наших залежностей від Gradle, який би переймався перетворенням об'єктів java.lang.String в текстові / прості органи запитів,

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

Потім нам потрібно передати фабрику перетворювачів нашому виробнику модернізації. Пізніше розповість Retrofit, як перетворити параметр @Body, переданий службі.

private val retrofitBuilder: Retrofit.Builder by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
}

Примітка. У моєму конструкторі модернізації у мене є два перетворювачі, Gsonі Scalarsви можете використовувати обидва, але для того, щоб надіслати Json тіло, нам потрібно зосередитися, Scalarsтому якщо вам не потрібно Gsonйого видалити

Потім послуга модернізації з параметром тіла String.

@Headers("Content-Type: application/json")
@POST("users")
fun saveUser(@Body   user: String): Response<MyResponse>

Потім створіть корпус JSON

val user = JsonObject()
 user.addProperty("id", 001)
 user.addProperty("name", "Name")

Зателефонуйте до служби

RetrofitService.myApi.saveUser(user.toString())

2

✅✅✅✅✅✅✅✅✅✅✅✅ Робоче рішення ✅✅✅✅✅✅✅✅✅✅✅✅

Під час створення OkHttpClient цього буде використано для модернізації.

додати подібний перехоплювач.

 private val httpClient = OkHttpClient.Builder()
        .addInterceptor (other interceptors)
        ........................................

        //This Interceptor is the main logging Interceptor
        .addInterceptor { chain ->
            val request = chain.request()
            val jsonObj = JSONObject(Gson().toJson(request))

            val requestBody = (jsonObj
            ?.getJSONObject("tags")
            ?.getJSONObject("class retrofit2.Invocation")
            ?.getJSONArray("arguments")?.get(0) ?: "").toString()
            val url = jsonObj?.getJSONObject("url")?.getString("url") ?: ""

            Timber.d("gsonrequest request url: $url")
            Timber.d("gsonrequest body :$requestBody")

            chain.proceed(request)
        }

        ..............
        // Add other configurations
        .build()

Тепер URL і тіло запиту кожного вашої ДООСНАСТКА виклику буде зареєстровано в Logcat. Відфільтруйте його за"gsonrequest"


1

Я спробував це: Коли ви створюєте екземпляр Retrofit, додайте цю конвертерну фабрику до конструктора модернізації:

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

1

Вирішив мою проблему на основі відповіді TommySM (див. Попередню). Але мені не потрібно було входити в систему, я використовував Retrofit2 для тестування https GraphQL API так:

  1. Визначив мій клас BaseResponse за допомогою анотацій json (імпорт jackson.annotation.JsonProperty).

    public class MyRequest {
        @JsonProperty("query")
        private String query;
    
        @JsonProperty("operationName")
        private String operationName;
    
        @JsonProperty("variables")
        private String variables;
    
        public void setQuery(String query) {
            this.query = query;
        }
    
        public void setOperationName(String operationName) {
            this.operationName = operationName;
        }
    
        public void setVariables(String variables) {
            this.variables = variables;
        }
    }
  2. Визначена процедура виклику в інтерфейсі:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Викликається apicall в тілі тесту: Створіть змінну типу MyRequest (наприклад, "myLittleRequest").

    Map<String, Object> jsonParams = convertObjectToMap(myLittleRequest);
    RequestBody body = 
         RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),
                        (new JSONObject(jsonParams)).toString());
    response = hereIsYourInterfaceName().apicall(body).execute();

0

Для більш чіткості відповідей, наведених тут, саме так можна використовувати функції розширення. Це лише в тому випадку, якщо ви використовуєте 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)

0

Я хотів порівняти швидкість залпу та модернізування для надсилання та отримання даних. Я написав нижче код (для деталей)

перша залежність:

dependencies {
     implementation 'com.squareup.retrofit2:retrofit:2.4.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
}

Потім інтерфейс:

 public interface IHttpRequest {

    String BaseUrl="https://example.com/api/";

    @POST("NewContract")
    Call<JsonElement> register(@Body HashMap registerApiPayload);
}

і функція для встановлення параметрів для розміщення даних на сервері (In MainActivity):

private void Retrofit(){

    Retrofit retrofitRequest = new Retrofit.Builder()
            .baseUrl(IHttpRequest.BaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // set data to send
    HashMap<String,String> SendData =new HashMap<>();
    SendData.put("token","XYXIUNJHJHJHGJHGJHGRTYTRY");
    SendData.put("contract_type","0");
    SendData.put("StopLess","37000");
    SendData.put("StopProfit","48000");

    final IHttpRequest request=retrofitRequest.create(IHttpRequest.class);

    request.register(SendData).enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
            if (response.isSuccessful()){
                Toast.makeText(getApplicationContext(),response.body().toString(),Toast.LENGTH_LONG).show();
            }
        }

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

        }
    });

}

І я знайшов Retrofit швидше, ніж залп у моєму випадку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.