Comment afficher raw JSON entier dans le corps d'une demande de modification?
cette question a peut-être déjà été posée, mais non elle n'a pas reçu de réponse définitive. Comment exactement affiche-t-on un JSON entier brut dans le corps d'une demande de modification?
Voir question similaire ici . Ou est-ce que cette réponse est correcte qu'il doit être l'url du formulaire encodé et passé comme un champ ? J'espère vraiment que non, car les services auxquels je me connecte attendent simplement raw JSON dans le corps du post. Ils ne sont pas mis en place pour recherchez un champ particulier pour les données JSON.
je veux juste clarifier cela avec le restperts une fois pour toutes. Une personne a répondu de ne pas utiliser la modernisation. L'autre n'était pas certain de la syntaxe. Un autre pense que oui, il peut être fait, mais seulement si sa forme url-encodé et placé dans un champ (ce n'est pas acceptable dans mon cas). Non, Je ne peux pas RE-code tous les services pour mon client Android. Et oui, c'est très courant dans les grands projets de post raw JSON au lieu de passer le contenu JSON comme valeur de propriété de champ. Allons droit au but et passons à autre chose. Est-ce que quelqu'un peut montrer la documentation ou l'exemple qui montre comment cela est fait? Ou donnez une raison valable pour laquelle cela peut / ne devrait pas être fait.
mise à jour: une chose que je peux dire avec 100% de certitude. Vous pouvez le faire dans Google Volley. Il est intégré. On peut faire ça en rénovation?
10 réponses
l'annotation @Body
définit un corps de requête unique.
interface Foo {
@POST("/jayson")
FooResponse postJson(@Body FooRequest body);
}
puisque Retrofit utilise Gson par défaut, les instances FooRequest
seront sérialisées en JSON comme seul corps de la requête.
public class FooRequest {
final String foo;
final String bar;
FooRequest(String foo, String bar) {
this.foo = foo;
this.bar = bar;
}
}
appel avec:
FooResponse = foo.postJson(new FooRequest("kit", "kat"));
donnera le corps suivant:
{"foo":"kit","bar":"kat"}
le Gson docs ont beaucoup plus sur le fonctionnement de la sérialisation des objets.
maintenant, si vous voulez vraiment envoyer " raw " JSON comme le corps vous-même (mais s'il vous plaît utilisez Gson pour cela!) vous pouvez toujours utiliser TypedInput
:
interface Foo {
@POST("/jayson")
FooResponse postRawJson(@Body TypedInput body);
}
TypedInput est défini comme " données binaires avec un type mime associé.". Il y a deux façons d'envoyer facilement des données brutes avec la déclaration ci-dessus:
-
utilisation TypedByteArray pour envoyer des octets brutes et le JSON type mime:
String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}"; TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8")); FooResponse response = foo.postRawJson(in);
-
sous-classe Typographie pour créer une
TypedJsonString
classe:public class TypedJsonString extends TypedString { public TypedJsonString(String body) { super(body); } @Override public String mimeType() { return "application/json"; } }
Et ensuite utiliser une instance de cette classe similaire à #1.
au lieu de classes, nous pouvons aussi utiliser directement le HashMap<String, Object>
pour envoyer les paramètres du corps
par exemple
interface Foo {
@POST("/jayson")
FooResponse postJson(@Body HashMap<String, Object> body);
}
Oui je sais qu'il est tard, mais quelqu'un en profiterait probablement.
Utilisant Retrofit2:
j'ai rencontré ce problème hier soir lors de la migration de Volley à Retrofit2 (et comme L'indique OP, cela a été construit directement dans Volley avec JsonObjectRequest
), et bien que la réponse de Jake est la bonne pour Retrofit1.9 , Retrofit2 doesn't have TypedString
.
My cas nécessaire d'envoyer un Map<String,Object>
qui pourrait contenir des valeurs nulles, converti en un JSONObject (qui ne volera pas avec @FieldMap
, pas plus que les caractères spéciaux, certains seront convertis), donc suivant @ bnorms hint ,et comme indiqué par carré :
un objet peut être spécifié pour être utilisé comme un corps de requête HTTP avec l'annotation @Body.
l'objet sera également converti en utilisant un convertisseur spécifié sur la Rénovation de l'instance. Si aucun convertisseur n'est ajouté, seul RequestBody peut être utilisé.
donc c'est une option utilisant RequestBody
et ResponseBody
:
dans votre interface utilisez @Body
avec RequestBody
public interface ServiceApi
{
@POST("prefix/user/{login}")
Call<ResponseBody> login(@Path("login") String postfix, @Body RequestBody params);
}
dans votre point d'appel créer un RequestBody
, en indiquant Qu'il est MediaType, et en utilisant JSONObject pour convertir votre carte au format approprié:
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...
}
});
J'espère que Aide à n'importe qui!
une élégante version Kotlin de ce qui précède, pour permettre l'Abstraction des paramètres de la conversion JSON dans le reste de votre code d'application:
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())
}
Dans Retrofit2 , Lorsque vous voulez envoyer vos paramètres en raw, vous devez utiliser Scalaires .
ajoutez d'abord ceci dans votre Grad:
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'
Votre Interface
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);
}
activité
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) {
}
}
L'utilisation de JsonObject est la façon dont il est:
-
créez votre interface comme ceci:
public interface laInterfaz{ @POST("/bleh/blah/org") void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback); }
-
font le JsonObject d'après la structure 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*/
-
Appeler le service:
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()); }
};
et que son! Dans mon opinion personnelle, c'est beaucoup mieux que de faire des pojos et de travailler avec le désordre de la classe. C'est beaucoup plus propre.
j'aime particulièrement la suggestion de Jake de la TypedString
sous-classe au-dessus de . Vous pouvez en effet créer une variété de sous-classes basées sur les types de données POST que vous prévoyez de promouvoir, chacune avec son propre ensemble personnalisé de modifications cohérentes.
vous avez aussi l'option d'ajouter une annotation d'en-tête à vos méthodes de publication JSON POST dans votre API Retrofit...""
@Headers( "Content-Type: application/json" )
@POST("/json/foo/bar/")
Response fubar( @Body TypedString sJsonBody ) ;
... mais l'utilisation d'une sous-classe est plus évidemment auto-documentée.
@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
après tant d'efforts, trouvé que la différence de base est que vous devez envoyer le JsonObject
au lieu de JSONObject
comme paramètre.
1)Ajouter des dépendances -
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) faire de l'Api du Gestionnaire de classe
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) Faire des classes de haricots à partir de JSON schema 2 pojo
Souvenez-vous
- Langue cible: Java -Source type : JSON -Annotation style : Gson -sélectionnez Inclure les getters et les setters -vous pouvez également sélectionner autoriser des propriétés
http://www.jsonschema2pojo.org/
4)make interface from api calling
public interface Webservices {
@POST("ApiUrlpath")
Call<ResponseBean> ApiName(@Body JsonObject jsonBody);
}
si vous avez un formulaire-paramètres de données alors ajouter au-dessous de la ligne
@Headers("Content-Type: application/x-www-form-urlencoded")
Autre façon pour les données de formulaire vérification des paramètres de cette lien
5)faire JsonObject pour le passage dans le corps comme paramètre
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) appeler Api comme ceci
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();
}
}
basé sur la réponse du haut, j'ai une solution pour ne pas avoir à faire des POJOs pour chaque demande.
exemple, je veux poster ce JSON.
{
"data" : {
"mobile" : "qwer",
"password" : "qwer"
},
"commom" : {}
}
alors, je crée une classe commune comme celle-ci:
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<>();
}
}
enfin, quand j'ai besoin d'un json
WRequest request = new WRequest();
request.data.put("type", type);
request.data.put("page", page);
la demande annotée @Body
peut alors passer à la mise à niveau.
utiliser ce qui suit pour envoyer 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());
et passez-le à l'url
@Body RequestBody key