Jak zamieścić cały JSON w treści żądania modernizacji?

284

To pytanie mogło zostać zadane wcześniej, ale nie, na które nie udzielono ostatecznej odpowiedzi. Jak dokładnie jeden post surowego całego JSON znajduje się w treści wniosku o modernizację?

Zobacz podobne pytanie tutaj . Czy ta odpowiedź jest poprawna, że musi być zakodowana z adresu URL i przekazana jako pole ? Naprawdę mam nadzieję, że nie, ponieważ usługi, z którymi się łączę, po prostu oczekują surowego JSON w treści postu. Nie są skonfigurowane do wyszukiwania określonego pola dla danych JSON.

Chcę tylko wyjaśnić to z restperts raz na zawsze. Jedna osoba odpowiedziała, aby nie używać Modernizacji. Drugi nie był pewien składni. Inny uważa, że ​​tak, można to zrobić, ale tylko wtedy, gdy jego forma jest zakodowana w url i umieszczona w polu (w moim przypadku jest to nie do przyjęcia). Nie, nie mogę ponownie kodować wszystkich usług mojego klienta Android. I tak, w dużych projektach bardzo często publikuje się surowy JSON zamiast przekazywać zawartość JSON jako wartości właściwości pola. Zróbmy to dobrze i przejdźmy dalej. Czy ktoś może wskazać dokumentację lub przykład, który pokazuje, jak to się robi? Lub podaj prawidłowy powód, dla którego nie można tego zrobić.

AKTUALIZACJA: Jedno mogę powiedzieć ze 100% pewnością. Możesz to zrobić w Google Volley. Jest wbudowany. Czy możemy to zrobić w ramach modernizacji?

użytkownik3243335
źródło
7
Post Jake'a Whartona jest poprawny! Oznacz jako odpowiedź!
edotassi
1
Możesz lepiej użyć jsonObject.
superUser
działa idealnie z RequestBodytym w ten sposób -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);szczegółowa odpowiedź futurestud.io/tutorials/...
Kidus Tekeste

Odpowiedzi:

461

@BodyAdnotacja wyznacza jeden organ żądania.

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

Ponieważ Retrofit domyślnie korzysta z Gson, FooRequestinstancje będą serializowane jako JSON jako jedyna treść żądania.

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

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

Dzwonię z:

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

Przyniesie następujące ciało:

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

Dokumenty Gson mają znacznie więcej informacji na temat serializacji obiektów.

Teraz, jeśli naprawdę chcesz sam wysłać „surowe” JSON jako ciało (ale w tym celu użyj Gsona!), Nadal możesz używać TypedInput:

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

TypedInput jest zdefiniowany jako „Dane binarne z powiązanym typem MIME”. Istnieją dwa sposoby łatwego wysyłania surowych danych z powyższą deklaracją:

  1. Użyj TypedByteArray, aby wysłać surowe bajty i typ MIME JSON:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Podklasa TypedString, aby utworzyć TypedJsonStringklasę:

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

    A następnie użyj instancji tej klasy podobnej do # 1.

Jake Wharton
źródło
5
Bardzo dobrze, czy jest jednak jakoś to zrobić bez zrobienia pojos?
superUser
28
Nie działa to w przypadku modernizacji 2. Klasy TypedInput i TypedString zostały usunięte.
Ahmed Hegazy
2
@jakewharton Co możemy zrobić, TypedStringskoro została usunięta?
Jared Burrows,
12
W przypadku Retrofit2 możesz użyć RequestBodydo utworzenia surowego obiektu.
bnorm
4
Dostaję ten wyjątekjava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal
155

Zamiast klas możemy również bezpośrednio użyć HashMap<String, Object>na przykład parametrów wysyłania ciała

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}
uczeń
źródło
2
W tym czasie możesz utworzyć mapę Hash, taką jak HashMap <Ciąg, Obiekt>, możliwe jest tworzenie trochę złożonych tablic i obiektów JSON.
uczeń
2
Jest to doskonałe, jeśli nie chcesz być przywiązany do jakiegoś POJO.
Tim
2
@Nil nie możesz wysłać obiektu Json za pomocą modernizacji ... trzymasz się rozumienia lub mojej odpowiedzi ... taka jest natura modernizacji. Jeśli chcesz więcej na ten temat zapytaj Jake'a Whartona, on jest facetem od modernizacji, jego odpowiedź jest również dostępna w pojo .
uczeń
5
Rozumiem IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>z Moshi. Myślę, że Gson jest do tego potrzebny
osrl
2
Jeśli używasz Kotlina, użyj skrótu <String, Any>
peresisUser
148

Tak, wiem, że jest późno, ale ktoś prawdopodobnie skorzystałby na tym.

Korzystanie z Retrofit2:

Natknąłem się na ten problem podczas migracji z Volley do Retrofit2 (i jak twierdzi OP, został on wbudowany w Volley z JsonObjectRequest) i chociaż odpowiedź Jake'a jest poprawna dla Retrofit1.9 , Retrofit2 nie ma TypedString.

Mój przypadek wymagał wysłania wartości, Map<String,Object>która mogłaby zawierać pewne wartości null, przekonwertowane na obiekt JSONObject (który nie będzie latał @FieldMap, nie zostaną też przekonwertowane znaki specjalne, niektóre zostaną przekonwertowane), więc zgodnie ze wskazówkami @bnorms i zgodnie z twierdzeniem Square :

Obiekt może zostać określony do użycia jako treść żądania HTTP z adnotacją @Body.

Obiekt zostanie również przekonwertowany przy użyciu konwertera określonego w instancji Retrofit. Jeśli nie zostanie dodany żaden konwerter, można użyć tylko RequestBody.

Jest to więc opcja przy użyciu RequestBodyiResponseBody :

W interfejsie używaj @BodyzRequestBody

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

W punkcie wywoławczym utwórz RequestBody , podając MediaType i używając JSONObject do konwersji mapy do odpowiedniego formatu:

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

Mam nadzieję, że to pomoże każdemu!


Elegancka wersja powyższego Kotlina, aby umożliwić wyodrębnienie parametrów z konwersji JSON w pozostałej części kodu aplikacji:

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

}
TommySM
źródło
2
Tak, widzę na to wiele skomplikowanych odpowiedzi. Jeśli używasz Retrofit2 i chcesz robić siatkówkę JsonObjectRequest, wszystko, co musisz zrobić, to zrobić. Dobra odpowiedź.
VicVu
2
Modernizacja dodaje klucz o nazwie „nameValuePairs” na górze wszystkich obiektów json. Jak mogę usunąć ten @TommySM
nr5
1
Dziękuję Ci! To rozwiązało mój problem. Teraz mogę wysłać JSONObject bezpośrednio, bez tworzenia POJO.
Erfan GLMPR
1
To jedyne rozwiązanie, które pomogło mi przejść post a null valuedo właściwości w requestBody, która w przeciwnym razie była ignorowana.
Shubhral
Wiem, że jestem spóźniony, ale co jest jsonParams.put("code", some_code);w trzeciej linii?
Naveen Niraula
81

W Retrofit2 , jeśli chcesz przesłać swoje parametry w stanie surowym, musisz użyć skalarów .

najpierw dodaj to do swojej klasy:

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'

Twój interfejs

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

}

Czynność

   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) {
    }
}
Jonathan Nolasco Barrientos
źródło
10
Sztuką jest tutaj adapter Scalar przed Gsonem, w przeciwnym razie Gson owinie ręcznie serializowany JSON w łańcuch.
TWiStErRob
2
jonathan-nolasco-barrientos musisz zmienić .baseUrl (ApiInterface.ENDPOINT) na .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi
2
Podczas korzystania GsonConverterFactoryThe .toString()nie jest konieczne. Możesz zadeklarować Call<User> getUser(@Body JsonObject body);użycie JsonObjectzamiast JSONObjecti przekazać paramObjectbezpośrednio. Będzie dobrze działać.
Igor de Lorenzi
1
@IgordeLorenzi rozwiązuje mój problem, ponieważ używam wiosennego rozruchu, aby odzyskać JSona tylko JsonObject z gson działa dobrze
haidarvm
1
@IgordeLorenzi Czy istnieje różnica, która z nich jest lepsza do użycia z skalarami JSONObject lub JsonObject.
Sumit Shukla
44

Używanie JsonObjectjest takie, jak to jest:

  1. Utwórz interfejs w następujący sposób:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Wykonaj JsonObject zgodnie ze strukturą 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. Zadzwoń do serwisu:

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

I to jest to! Moim osobistym zdaniem jest to o wiele lepsze niż tworzenie koncepcji i praca z klasowym bałaganem. To jest o wiele czystsze.

superUser
źródło
1
Co jeśli nie chcę wysyłać wartości specif w klasie jsonobject. jakiej adnotacji mogę użyć w tym celu powyżej?
Ali Gürelli,
1
Jak widać powyższy przykład ... JsonObject, ponieważ jest obiektem, nie używa żadnej anotacji. W twoim przypadku, jeśli nie chcesz wysyłać określonej wartości, możesz po prostu nie dodać jej jako właściwości ...
superUser
1
Mam na myśli, że nie chcę wysyłać wartości zadeklarowanej w klasie. Przy okazji naprawiłem problem. Była adnotacja do tego, która nazwa jest ujawniona.
Ali Gürelli
2
To najbardziej elastyczny sposób. Możesz zbudować obiekt Json, nawet jeśli nie wiesz, ile pól będziesz mieć, a nawet jeśli nie wiesz, że one nazywają ode mnie +1
Stoycho Andreev
1
otrzymuję błąd Metody serwisowe nie mogą zostać unieważnione. dla metody APIServices.signUpUser
Erum
11

Szczególnie podoba mi się sugestia Jake'a z TypedStringpodklasy powyżej . Rzeczywiście możesz stworzyć wiele podklas w oparciu o rodzaje danych POST, które planujesz zwiększyć, każda z własnym niestandardowym zestawem spójnych poprawek.

Masz również opcję dodania adnotacji nagłówka do metod JSON POST w interfejsie API Retrofit…

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

… Ale użycie podklasy jest bardziej oczywiste.

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
zerobandwidth
źródło
1
Oszczędność dnia dzięki wyraźnemu przykładowi przy użyciu TypedJsonString z sugestii JW
miroslavign
10

1) Dodaj zależności

 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) uczynić klasę 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) twórz klasy fasoli ze schematu Jsona 2 pojo

Pamiętaj -
Język docelowy: Java - Typ źródła: JSON - Styl adnotacji: Gson - wybierz Uwzględnij metody pobierające i ustawiające - możesz także wybrać Zezwalaj na dodatkowe właściwości

http://www.jsonschema2pojo.org/

4) wykonaj interfejs do wywoływania interfejsu API

    public interface Webservices {

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

}

jeśli masz parametry danych formularza, dodaj poniższy wiersz

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

W inny sposób dla parametru danych formularza sprawdź ten link

5) ustaw JsonObject do przekazania do ciała jako parametr

 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) Zadzwoń do API w ten sposób

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();
    }
}
Adil
źródło
9

Odkryłem, że kiedy używasz obiektu złożonego jako @Bodyparams, nie może on dobrze działać z Retrofit GSONConverter(przy założeniu, że go używasz). Musisz używać, JsonObjecta nie JSONObjectpodczas pracy z tym, dodaje to NameValueParamsbez mówienia o tym - możesz to zobaczyć tylko wtedy, gdy dodasz inną zależność rejestrowania przechwytywacza i innych shenaniganów.

Więc to, co znalazłem najlepsze podejście do rozwiązania tego problemu, to wykorzystanie RequestBody. Obróć swój obiekt RequestBodyza pomocą prostego wywołania interfejsu API i uruchom go. W moim przypadku przekształcam mapę:

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

i to jest wezwanie:

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>
peresisUser
źródło
2
Cóż, pomogło mi to po googlowaniu na noc.
W4R10CK,
8

Dodaj ScalarsConverterFactory do modernizacji:

w stopniach:

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

Twoja modernizacja:

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

zmień parametr @Body interfejsu wywołania na String, nie zapomnij dodać @Headers("Content-Type: application/json"):

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

teraz możesz pisać surowego Jsona.

ali-star
źródło
6

Możesz użyć hashmap, jeśli nie chcesz tworzyć klasy pojo dla każdego wywołania API.

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

A potem wyślij tak

Call<JsonElement> register(@Body HashMap registerApiPayload);
jatin rana
źródło
4

Po tylu wysiłkach okazało się, że podstawową różnicą jest przesłanie parametru JsonObjectzamiast JSONObjectjako parametru.

umair151
źródło
Popełniłem również ten sam błąd: p
Mehtab Ahmed
4

użyj następującego, aby wysłać 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());

i przekaż to na adres URL

@Body RequestBody key
Mahesh Pandit
źródło
4

W oparciu o najwyższą odpowiedź mam rozwiązanie, aby nie musieć tworzyć POJO dla każdego żądania.

Przykład, chcę opublikować ten JSON.

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

następnie tworzę wspólną klasę taką jak ta:

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

Wreszcie, kiedy potrzebuję jsona

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

Żądanie oznaczone adnotacją @Bodymoże następnie przejść do modernizacji.

wjploop
źródło
4

Jeśli nie chcesz tworzyć dodatkowych klas ani używać JSONObject, możesz użyćHashMap .

Interfejs modernizacji:

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

Połączenie:

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

retrofit.create(TheApi::class.java)
     .signUp(map)
     .enqueue(callback)
SoftDesigner
źródło
3

Rzeczy wymagane do wysłania surowego Jsona w ramach modernizacji.

1) Pamiętaj, aby dodać następujący nagłówek i usunąć wszelkie inne zduplikowane nagłówki. Ponieważ w oficjalnej dokumentacji Retrofit wyraźnie wspominają:

Pamiętaj, że nagłówki nie zastępują się nawzajem. Wszystkie nagłówki o tej samej nazwie zostaną uwzględnione w żądaniu.

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

2) a. Jeśli używasz fabryki konwerterów, możesz przekazać json jako String, JSONObject, JsonObject, a nawet POJO. Sprawdziłem również, że posiadanie ScalarConverterFactorynie jest konieczne tylko GsonConverterFactorywykonuje pracę.

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

2) b. Jeśli NIE korzystasz z żadnej fabryki konwerterów, MUSISZ użyć RequestBody okhttp3, ponieważ dokumentacja Retrofit mówi:

Obiekt zostanie również przekonwertowany przy użyciu konwertera określonego w instancji Retrofit. Jeśli nie zostanie dodany żaden konwerter, można użyć tylko 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) Sukces !!

Darshan Miskin
źródło
2

To działa dla mnie w bieżącej wersji retrofit 2.6.2 ,

Przede wszystkim musimy dodać konwerter skalarów do listy naszych zależności Gradle, który zająłby się konwertowaniem obiektów java.lang.String na ciała tekstowe / zwykłe żądania,

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

Następnie musimy przekazać fabrykę konwerterów do naszego konstruktora modernizacji. Później powie Retrofit, jak przekonwertować parametr @Body przekazany do usługi.

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

Uwaga: W moim kreatorze modernizacji mam dwa konwertery Gsoni Scalarsmożesz używać obu z nich, ale aby wysłać ciało Jsona, musimy się skoncentrować, Scalarswięc jeśli nie potrzebujesz Gsongo usunąć

Następnie usługa modernizacji z parametrem Body String.

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

Następnie utwórz ciało JSON

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

Zadzwoń do serwisu

RetrofitService.myApi.saveUser(user.toString())
Jimale Abdi
źródło
2

✅✅✅✅✅✅✅✅✅✅✅✅ Działające rozwiązanie ✅✅✅✅✅✅✅✅✅✅✅✅

Podczas tworzenia OkHttpClient zostanie użyty do modernizacji.

dodaj taki przechwytywacz.

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

Teraz URL i treści żądania spełnić każde modernizacyjny wywołania będą rejestrowane w Logcat. Filtruj według"gsonrequest"

erluxman
źródło
1

Próbowałem tego: podczas tworzenia instancji Retrofit dodaj tę fabrykę konwerterów do konstruktora modernizacji:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
Arman Ramezanzadeh
źródło
1

Rozwiązałem mój problem na podstawie odpowiedzi TommySM (patrz poprzedni). Ale nie musiałem się logować, użyłem Retrofit2 do testowania API https GraphQL w następujący sposób:

  1. Zdefiniowałem moją klasę BaseResponse za pomocą adnotacji json (import 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. Zdefiniowano procedurę wywołania w interfejsie:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. W treści testu nazywany apicall: utwórz zmienną typu MyRequest (na przykład „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();
Natalya Shatalova
źródło
0

Aby uzyskać większą przejrzystość podanych tutaj odpowiedzi, możesz skorzystać z funkcji rozszerzenia. Jest to możliwe tylko w przypadku korzystania z Kotlin

Jeśli korzystasz com.squareup.okhttp3:okhttp:4.0.1ze starszych metod tworzenia obiektów MediaType i RequestBody, są one przestarzałe i nie można ich używać w Kotlin .

Jeśli chcesz użyć funkcji rozszerzenia, aby uzyskać obiekt MediaType i obiekt ResponseBody ze swoich ciągów, najpierw dodaj następujące wiersze do klasy, w której spodziewasz się ich użyć.

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

W ten sposób możesz teraz bezpośrednio uzyskać obiekt MediaType

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

Aby uzyskać obiekt RequestBody, najpierw przekonwertuj obiekt JSONObject, który chcesz wysłać w ten sposób na ciąg. Musisz przekazać do niego obiekt mediaType.

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
Devenom
źródło
0

Chciałem porównać prędkość siatkówki i modernizacji do wysyłania i odbierania danych, które napisałem poniżej kodu (dla części modernizacyjnej)

pierwsza zależność:

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

Następnie interfejs:

 public interface IHttpRequest {

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

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

oraz funkcja do ustawiania parametrów wysyłania danych do serwera (w 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) {

        }
    });

}

W moim przypadku odnalazłem Retrofit szybciej niż siatkówkę.

Liam
źródło