Làm cách nào để gửi toàn bộ JSON thô trong phần thân của yêu cầu Retrofit?


284

Câu hỏi này có thể đã được hỏi trước đó nhưng không, nó không được trả lời dứt khoát. Làm thế nào chính xác một bài đăng toàn bộ JSON bên trong cơ thể của một yêu cầu Retrofit?

Xem câu hỏi tương tự ở đây . Hoặc câu trả lời này có đúng rằng nó phải được mã hóa dưới dạng url và được chuyển dưới dạng một trường không? Tôi thực sự hy vọng là không, vì các dịch vụ tôi đang kết nối chỉ đang mong đợi JSON thô trong phần thân bài. Chúng không được thiết lập để tìm kiếm một trường cụ thể cho dữ liệu JSON.

Tôi chỉ muốn làm rõ điều này với các restperts một lần và mãi mãi. Một người trả lời không sử dụng Retrofit. Cái khác không chắc chắn về cú pháp. Một người khác nghĩ có, có thể được thực hiện nhưng chỉ khi hình thức được mã hóa url và được đặt trong một trường (điều đó không được chấp nhận trong trường hợp của tôi). Không, tôi không thể mã lại tất cả các dịch vụ cho ứng dụng khách Android của mình. Và vâng, rất phổ biến trong các dự án lớn để đăng JSON thô thay vì chuyển qua nội dung JSON làm giá trị thuộc tính trường. Hãy làm cho nó đúng và đi tiếp. Ai đó có thể chỉ vào tài liệu hoặc ví dụ cho thấy làm thế nào được thực hiện? Hoặc cung cấp một lý do hợp lệ tại sao nó có thể / không nên được thực hiện.

CẬP NHẬT: Một điều tôi có thể nói với sự chắc chắn 100%. Bạn CÓ THỂ làm điều này trong Volley của Google. Nó được xây dựng ngay trong. Chúng ta có thể làm điều này trong Retrofit không?


7
Bài viết của Jake Wharton là chính xác! Đánh dấu là câu trả lời!
edotassi

1
Bạn có thể sử dụng jsonObject tốt hơn.
siêu người dùng

hoạt động hoàn hảo với RequestBodynhư thế này -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);cho chi tiết câu trả lời futurestud.io/tutorials/...
Kidus Tekeste

Câu trả lời:


461

Các @Bodychú thích định nghĩa một cơ thể yêu cầu duy nhất.

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

Do Retrofit sử dụng Gson theo mặc định, các FooRequestphiên bản sẽ được tuần tự hóa dưới dạng JSON làm phần thân duy nhất của yêu cầu.

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

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

Gọi với:

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

Sẽ mang lại cơ thể sau:

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

Các tài liệu Gson có nhiều hơn về cách thức tuần tự hóa đối tượng hoạt động.

Bây giờ, nếu bạn thực sự muốn gửi JSON "thô" như chính cơ thể (nhưng vui lòng sử dụng Gson cho việc này!) Bạn vẫn có thể sử dụng TypedInput:

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

TypedInput được định nghĩa là "Dữ liệu nhị phân có loại mime liên quan.". Có hai cách để dễ dàng gửi dữ liệu thô với khai báo trên:

  1. Sử dụng TypedByteArray để gửi byte thô và loại mime JSON:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Phân lớp TypedString để tạo một TypedJsonStringlớp:

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

    Và sau đó sử dụng một thể hiện của lớp đó tương tự như # 1.


5
Rất tốt, tuy nhiên, có cách nào để thực hiện điều này mà không làm pojos?
siêu người dùng

28
Điều này không hoạt động trên trang bị thêm 2. Các lớp TypedInput và TypedString đã bị xóa.
Ahmed Hegazy

2
@jakewharton Chúng ta có thể làm gì TypedStringvì nó đã bị xóa?
Jared Burrows

12
Đối với Retrofit2, bạn có thể sử dụng RequestBodyđể tạo một cơ thể thô.
bnorm

4
Tôi nhận được ngoại lệ nàyjava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal

154

Thay vì các lớp, chúng ta cũng có thể trực tiếp sử dụng HashMap<String, Object>để gửi các tham số cơ thể chẳng hạn

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

2
Tại thời điểm đó, bạn có thể tạo bản đồ Hash như HashMap <String, Object>, có thể tạo các mảng và đối tượng JSON phức tạp.
người học

2
Điều này thật tuyệt vời nếu bạn không muốn bị ràng buộc với một POJO nào đó.
Tim

2
@ Nếu bạn không thể gửi đối tượng json bằng cách sử dụng retrofit ... bạn tuân thủ pojo hoặc câu trả lời của tôi ... đây là bản chất của retrofit. Nếu bạn muốn biết thêm về điều này, hãy hỏi Jake Wharton, anh ta là người phát triển trang bị thêm, câu trả lời của anh ta cũng có sẵn với pojo .
người học

5
Tôi nhận được IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>với Moshi. Tôi nghĩ Gson là cần thiết để nó hoạt động
osrl

2
Nếu sử dụng Kotlin, hãy sử dụng hàm băm <String, Any>
peresisUser

148

Vâng, tôi biết là muộn, nhưng ai đó có thể sẽ được hưởng lợi từ việc này.

Sử dụng Retrofit2:

Tôi đã gặp vấn đề này đêm qua khi chuyển từ Volley sang Retrofit2 (và như các tiểu bang của OP, điều này được xây dựng ngay trong Volley với JsonObjectRequest), và mặc dù câu trả lời của Jake là câu trả lời đúng cho Retrofit1.9 , Retrofit2 không có TypedString.

Trường hợp của tôi yêu cầu gửi một Map<String,Object>giá trị có thể chứa một số giá trị null, được chuyển đổi thành JSONObject (sẽ không bay cùng @FieldMap, các ký tự đặc biệt, một số được chuyển đổi), do đó, theo gợi ý @bnorms và như Square đã nêu :

Một đối tượng có thể được chỉ định để sử dụng làm phần thân yêu cầu HTTP với chú thích @Body.

Đối tượng cũng sẽ được chuyển đổi bằng cách sử dụng trình chuyển đổi được chỉ định trong thể hiện Retrofit. Nếu không có trình chuyển đổi nào được thêm vào, chỉ có thể sử dụng RequestBody.

Vì vậy, đây là một tùy chọn sử dụng RequestBodyResponseBody:

Trong giao diện của bạn sử dụng @BodyvớiRequestBody

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

Trong điểm gọi của bạn, hãy tạo một RequestBody, nêu rõ MediaType và sử dụng JSONObject để chuyển đổi Bản đồ của bạn sang định dạng phù hợp:

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

Hy vọng điều này sẽ giúp bất cứ ai!


Một phiên bản Kotlin thanh lịch ở trên, để cho phép trừu tượng hóa các tham số từ hội tụ JSON trong phần còn lại của mã ứng dụng của bạn:

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
Vâng, tôi đang thấy rất nhiều câu trả lời phức tạp cho việc này. Nếu bạn đang sử dụng Retrofit2 và muốn thực hiện cú vô lê JsonObjectRequest, tất cả những gì bạn cần làm là điều này. Câu trả lời tốt.
VicVu

2
Retrofit thêm một khóa có tên "nameValuePairs" vào đầu tất cả các đối tượng json. Làm cách nào tôi có thể xóa cái này @TommySM
nr5

1
Cảm ơn bạn! Điều này đã giải quyết vấn đề của tôi. Bây giờ tôi có thể gửi JSONObject trực tiếp mà không cần tạo POJO.
Erfan GLMPR

1
Đây là giải pháp duy nhất giúp tôi post a null valueđến một tài sản trong requestBody mà nếu không thì bị bỏ qua.
Shubhral

Tôi biết tôi đến muộn nhưng những gì jsonParams.put("code", some_code);trong dòng thứ ba?
Naveen Niraula

81

Trong Retrofit2 , khi bạn muốn gửi tham số của mình ở dạng thô, bạn phải sử dụng vô hướng .

đầu tiên thêm điều này trong lớp của bạn:

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'

Giao diện của bạn

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

}

Hoạt động

   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) {
    }
}

9
Thủ thuật ở đây là bộ điều hợp vô hướng trước Gson, nếu không, Gson sẽ gói JSON được tuần tự hóa thủ công của bạn trong Chuỗi.
TWiStErRob

2
jonathan-nolasco-barrientos bạn phải thay đổi .baseUrl (ApiInterface.ENDPOINT) thành .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi

2
Khi bạn sử dụng GsonConverterFactory, .toString()không cần thiết. Bạn có thể tuyên bố Call<User> getUser(@Body JsonObject body);sử dụng JsonObjectthay vì JSONObjectvà vượt qua paramObjecttrực tiếp. Nó sẽ chỉ làm việc tốt.
Igor de Lorenzi

Cách tiếp cận tuyệt vời và đơn giản. Đã lưu trong ngày
Itai Spector

1
@IgordeLorenzi giải quyết vấn đề của tôi, vì tôi đang sử dụng boot mùa xuân để lấy json chỉ JsonObject từ gson hoạt động tốt
haidarvm

44

Sử dụng JsonObjectlà cách nó là:

  1. Tạo giao diện của bạn như thế này:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Tạo JsonObject theo cấu trúc 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. Gọi dịch vụ:

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

Và đó là nó! Theo ý kiến ​​cá nhân của tôi, nó tốt hơn rất nhiều so với việc làm pojos và làm việc với lớp học lộn xộn. Điều này là sạch sẽ hơn rất nhiều.


1
Điều gì xảy ra nếu tôi không muốn gửi giá trị cụ thể trong lớp jsonobject. Tôi có thể sử dụng annotaion nào ở trên để kiểm chứng?
Ali Gürelli

1
Như bạn có thể thấy ví dụ trên ... JsonObject vì nó là một đối tượng, không sử dụng bất kỳ sự anot nào. Trong trường hợp của bạn nếu bạn không muốn gửi giá trị cụ thể, bạn có thể không thêm nó dưới dạng tài sản ...
superUser

1
Ý tôi là tôi không muốn gửi giá trị được khai báo trong lớp. Btw tôi đã khắc phục vấn đề. Có một chú thích cho cái tên nào được phơi bày.
Ali Gürelli

2
Đây là cách linh hoạt nhất. Bạn có thể xây dựng đối tượng json của mình ngay cả khi bạn không biết mình sẽ có bao nhiêu trường hoặc thậm chí nếu bạn không biết họ đặt tên +1 từ tôi
Stoycho Andreev

1
im nhận lỗi Phương thức dịch vụ không thể trả về void. cho phương thức APIService.signUpUser
Erum

11

Tôi đặc biệt thích đề xuất của Jake về TypedStringlớp con ở trên . Bạn thực sự có thể tạo ra một loạt các lớp con dựa trên các loại dữ liệu POST mà bạn dự định đẩy lên, mỗi loại có một bộ chỉnh sửa tùy chỉnh riêng.

Bạn cũng có tùy chọn thêm chú thích tiêu đề vào các phương thức POST POST của mình trong API Retrofit API của bạn

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

Tuy nhiên, sử dụng một lớp con rõ ràng là tự viết tài liệu.

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

1
Đã lưu ngày với một ví dụ rõ ràng bằng TypedJsonString từ đề xuất JW
miroslavign

10

1) Thêm phụ thuộc-

 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) tạo lớp 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) tạo các lớp bean từ lược đồ Json 2 pojo

Ghi nhớ
- Ngôn ngữ nhắm mục tiêu : Java - Kiểu nguồn: JSON - Kiểu chú thích: Gson -select Bao gồm getters và setters -cũng bạn có thể chọn Cho phép các thuộc tính bổ sung

http://www.jsonschema2pojo.org/

4) thực hiện giao diện fro api gọi

    public interface Webservices {

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

}

nếu bạn có một tham số dữ liệu biểu mẫu thì thêm dòng dưới đây

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

Cách khác cho tham số dữ liệu biểu mẫu kiểm tra liên kết này

5) tạo JsonObject để truyền vào cơ thể làm tham số

 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) Gọi Api như thế này

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

Tôi thấy rằng khi bạn sử dụng một đối tượng ghép làm @Bodyparams, nó không thể hoạt động tốt với Retrofit GSONConverter(theo giả định bạn đang sử dụng đối tượng đó). Bạn phải sử dụng JsonObjectchứ không phải JSONObjectkhi làm việc với nó, nó bổ sung NameValueParamsmà không cần phải nói rõ về nó - bạn chỉ có thể thấy rằng nếu bạn thêm một phụ thuộc khác của đánh chặn đăng nhập và các shenanigans khác.

Vì vậy, những gì tôi tìm thấy cách tiếp cận tốt nhất để giải quyết điều này là sử dụng RequestBody. Bạn biến đối tượng của mình thành RequestBodymột cuộc gọi api đơn giản và khởi chạy nó. Trong trường hợp của tôi, tôi đang chuyển đổi bản đồ:

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

và đây là cuộc gọi:

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

2
Vâng, điều này đã giúp tôi sau khi googling qua đêm.
W4R10CK

8

Thêm ScalarsConverterFactory để trang bị thêm:

trong lớp

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

trang bị thêm của bạn:

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

thay đổi tham số @Body giao diện cuộc gọi của bạn thành Chuỗi, đừng quên thêm @Headers("Content-Type: application/json"):

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

bây giờ bạn có thể đăng json thô.


6

Bạn có thể sử dụng hàm băm nếu bạn không muốn tạo lớp pojo cho mỗi lệnh gọi API.

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

Và sau đó gửi như thế này

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

4

Sau rất nhiều nỗ lực, nhận thấy rằng sự khác biệt cơ bản là bạn cần gửi JsonObjectthay vì JSONObjecttham số.


Tôi cũng đang mắc lỗi tương tự: p
Mehtab Ahmed

4

sử dụng sau đây để gửi 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());

và chuyển nó vào url

@Body RequestBody key

4

Dựa trên câu trả lời hàng đầu, tôi có một giải pháp để không phải tạo POJO cho mọi yêu cầu.

Ví dụ, tôi muốn đăng JSON này.

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

Sau đó, tôi tạo một lớp chung như thế này:

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

Cuối cùng, khi tôi cần một cái json

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

Yêu cầu được đánh dấu chú thích @Bodysau đó có thể chuyển đến Retrofit.


4

Nếu bạn không muốn tạo thêm lớp hoặc sử dụng, JSONObjectbạn có thể sử dụng một HashMap.

Giao diện trang bị thêm:

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

Gọi:

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

Những điều cần thiết để gửi json thô trong Retrofit.

1) Đảm bảo thêm tiêu đề sau và xóa mọi tiêu đề trùng lặp khác. Vì, trên tài liệu chính thức của Retrofit, họ đề cập cụ thể-

Lưu ý rằng các tiêu đề không ghi đè lên nhau. Tất cả các tiêu đề có cùng tên sẽ được bao gồm trong yêu cầu.

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

2) a. Nếu bạn đang sử dụng một nhà máy chuyển đổi, bạn có thể chuyển json của mình dưới dạng Chuỗi, JSONObject, JsonObject và thậm chí là POJO. Cũng đã kiểm tra, có ScalarConverterFactorykhông cần thiết chỉ GsonConverterFactorylàm công việc.

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

2) b. Nếu bạn KHÔNG sử dụng bất kỳ nhà máy chuyển đổi nào thì bạn PHẢI sử dụng RequestBody của okhttp3 như tài liệu của Retrofit nói-

Đối tượng cũng sẽ được chuyển đổi bằng cách sử dụng trình chuyển đổi được chỉ định trong thể hiện Retrofit. Nếu không có trình chuyển đổi nào được thêm vào, chỉ có thể sử dụng 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) Thành công !!


2

Đây là những gì làm việc cho tôi cho phiên bản hiện tại của retrofit 2.6.2 ,

Trước hết, chúng ta cần thêm Bộ chuyển đổi vô hướng vào danh sách các phụ thuộc Gradle của chúng ta, việc này sẽ đảm nhiệm việc chuyển đổi các đối tượng java.lang.String sang các thân yêu cầu văn bản / đơn giản,

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

Sau đó, chúng tôi cần chuyển một nhà máy chuyển đổi sang nhà xây dựng Retrofit của chúng tôi. Sau đó, nó sẽ cho Retrofit biết cách chuyển đổi tham số @Body được truyền cho dịch vụ.

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

Lưu ý: Trong trình xây dựng trang bị thêm của tôi, tôi có hai trình chuyển đổi GsonScalarsbạn có thể sử dụng cả hai trình chuyển đổi nhưng để gửi cơ thể Json, chúng tôi cần phải tập trung Scalarsvì vậy nếu bạn không cần Gsonxóa nó

Sau đó, dịch vụ Retrofit với tham số thân chuỗi.

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

Sau đó tạo phần thân JSON

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

Gọi dịch vụ của bạn

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

2

✅✅✅✅✅✅✅✅✅✅✅✅ Giải pháp làm việc ✅✅✅✅✅✅✅✅✅✅✅✅

Trong khi tạo OkHttpClient sẽ được sử dụng cho Retrofit.

thêm một Interceptor như thế này.

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

Bây giờ URL và yêu cầu cơ thể của bạn mỗi Retrofit cuộc gọi sẽ được đăng nhập vào Logcat. Lọc nó bằng"gsonrequest"


1

Tôi đã thử điều này: Khi bạn đang tạo phiên bản Retrofit của mình, hãy thêm nhà máy chuyển đổi này vào trình xây dựng trang bị thêm:

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

1

Giải quyết vấn đề của tôi dựa trên câu trả lời TommySM (xem trước). Nhưng tôi không cần phải đăng nhập, tôi đã sử dụng Retrofit2 để thử nghiệm API GraphQL https như thế này:

  1. Xác định lớp BaseResponse của tôi với sự trợ giúp của các chú thích json (nhập 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. Xác định thủ tục cuộc gọi trong giao diện:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Được gọi là apicall trong phần thân của bài kiểm tra: Tạo một biến loại MyRequest (ví dụ: "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

Để rõ hơn về các câu trả lời được đưa ra ở đây, đây là cách bạn có thể sử dụng các chức năng mở rộng. Điều này chỉ khi bạn đang sử dụng Kotlin

Nếu bạn đang sử dụng com.squareup.okhttp3:okhttp:4.0.1các phương thức tạo đối tượng cũ hơn của MediaTypeRequestBody thì không được dùng nữa và không thể sử dụng trong Kotlin .

Nếu bạn muốn sử dụng các chức năng mở rộng để có được một MediaType đối tượng và một ResponseBody đối tượng từ dây của bạn, trước hết là thêm các dòng sau vào trong lớp mà bạn mong đợi để sử dụng chúng.

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

Bây giờ bạn có thể trực tiếp lấy một đối tượng của MediaType theo cách này

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

Để có được một đối tượng của RequestBody, trước tiên hãy chuyển đổi JSONObject mà bạn muốn gửi đến một chuỗi theo cách này. Bạn phải truyền đối tượng mediaType cho nó.

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

0

Tôi muốn so sánh tốc độ của bóng chuyền và trang bị thêm để gửi và nhận dữ liệu tôi đã viết mã bên dưới (đối với phần trang bị thêm)

phụ thuộc đầu tiên:

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

Sau đó giao diện:

 public interface IHttpRequest {

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

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

và một chức năng để đặt tham số để đăng dữ liệu lên máy chủ (Trong 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) {

        }
    });

}

Và tôi thấy Retrofit nhanh hơn bóng chuyền trong trường hợp của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.