개조 요청 본문에 원시 JSON 전체를 POST하는 방법은 무엇입니까?
이 질문은 이전에 요청되었을 수도 있지만 확실하게 답변되지 않았습니다. Retrofit 요청 본문에 원시 JSON 전체를 정확히 어떻게 게시합니까?
비슷한 질문을 여기에서보십시오 . 아니면이 대답은 양식 URL로 인코딩되어 필드로 전달되어야 한다는 것이 맞 습니까? 연결하려는 서비스가 게시물 본문에서 원시 JSON을 기대하기 때문에 실제로는 그렇지 않습니다. JSON 데이터의 특정 필드를 찾도록 설정되지 않았습니다.
나는 단지 restperts로 이것을 명확히하고 싶습니다 . 한 사람이 Retrofit을 사용하지 않겠다고 대답했습니다. 다른 구문은 확실하지 않았습니다. 다른 사람은 그렇다고 할 수 있지만 양식이 URL로 인코딩되어 필드에 배치 된 경우에만 가능하다고 생각합니다 (제 경우에는 허용되지 않습니다). 아니요, Android 클라이언트의 모든 서비스를 다시 코딩 할 수 없습니다. 예, 주요 프로젝트에서 JSON 컨텐츠를 필드 특성 값으로 전달하는 대신 원시 JSON을 게시하는 것이 매우 일반적입니다. 올바르게 해보자. 누군가 이것이 어떻게 수행되는지 보여주는 문서 또는 예제를 가리킬 수 있습니까? 또는 수행 할 수없는 이유를 제시하십시오.
업데이트 : 100 % 확실하게 말할 수있는 한 가지. Google 발리에서이 작업을 수행 할 수 있습니다. 내장되어 있습니다. Retrofit에서이 작업을 수행 할 수 있습니까?
@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 워드 프로세서는 훨씬 더 객체 직렬화가 어떻게 작동하는지에 있습니다.
이제 실제로 "raw"JSON을 본문으로 직접 보내려면 (그러나 Gson을 사용하십시오!) 여전히 사용할 수 있습니다 TypedInput
:
interface Foo {
@POST("/jayson")
FooResponse postRawJson(@Body TypedInput body);
}
TypedInput 은 "관련된 MIME 유형을 가진 이진 데이터"로 정의됩니다. 위의 선언으로 원시 데이터를 쉽게 보내는 방법에는 두 가지가 있습니다.
원시 바이트 및 JSON MIME 유형을 보내 려면 TypedByteArray 를 사용하십시오 .
String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}"; TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8")); FooResponse response = foo.postRawJson(in);
클래스 를 작성하는 서브 클래스 TypedString
TypedJsonString
:public class TypedJsonString extends TypedString { public TypedJsonString(String body) { super(body); } @Override public String mimeType() { return "application/json"; } }
그런 다음 # 1과 유사한 해당 클래스의 인스턴스를 사용하십시오.
클래스 대신 직접 HashMap<String, Object>
매개 변수를 전송 하기 위해 를 사용할 수도 있습니다.
interface Foo {
@POST("/jayson")
FooResponse postJson(@Body HashMap<String, Object> body);
}
예, 늦었다는 것을 알고 있지만 누군가는 아마 이로부터 혜택을받을 것입니다.
Retrofit2 사용 :
지난 밤 Volley에서 Retrofit2로 마이그레이션하는이 문제에 부딪 쳤습니다 (OP 상태에서는 이것이 Volley에 내장되어 있음 JsonObjectRequest
) .Jake의 대답은 Retrofit1.9 에 대한 올바른 대답 이지만 Retrofit2에는 없습니다 TypedString
.
내 경우 Map<String,Object>
에는 일부 null 값을 포함하고 JSONObject로 변환 된 @FieldMap
특수 객체를 변환하지 않고 일부는 변환되지 않는 null 값을 포함 할 수있는을 보내야하므로 @bnorms 힌트를 따르고 Square에 명시된대로 :
@Body 어노테이션이있는 HTTP 요청 본문으로 사용되도록 오브젝트를 지정할 수 있습니다.
개체는 Retrofit 인스턴스에 지정된 변환기를 사용하여 변환됩니다. 변환기를 추가하지 않으면 RequestBody 만 사용할 수 있습니다.
따라서 이것은 RequestBody
and를 사용하는 옵션입니다 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...
}
});
이것이 누군가를 돕기를 바랍니다!
위의 우아한 Kotlin 버전으로 나머지 애플리케이션 코드에서 JSON 변환의 매개 변수를 추상화 할 수 있습니다.
interface ServiceApi {
fun login(username: String, password: String) =
jsonLogin(createJsonRequestBody(
"username" to username, "password" to password))
@POST("/api/login")
fun jsonLogin(@Body params: RequestBody): Deferred<LoginResult>
private fun createJsonRequestBody(vararg params: Pair<String, String>) =
RequestBody.create(
okhttp3.MediaType.parse("application/json; charset=utf-8"),
JSONObject(mapOf(*params)).toString())
}
에서 Retrofit2 당신이 사용해야 원에서 매개 변수를 보내려면, 스칼라을 .
먼저 이것을 gradle에 추가하십시오.
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
인터페이스
public interface ApiInterface {
String URL_BASE = "http://10.157.102.22/rest/";
@Headers("Content-Type: application/json")
@POST("login")
Call<User> getUser(@Body String body);
}
활동
public class SampleActivity extends AppCompatActivity implements Callback<User> {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiInterface.URL_BASE)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiInterface apiInterface = retrofit.create(ApiInterface.class);
// prepare call in Retrofit 2.0
try {
JSONObject paramObject = new JSONObject();
paramObject.put("email", "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) {
}
}
사용 JsonObject
하는 방식은 다음과 같습니다.
다음과 같이 인터페이스를 작성하십시오.
public interface laInterfaz{ @POST("/bleh/blah/org") void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback); }
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*/
서비스를 호출하십시오.
service.registerPayer(obj, callBackRegistraPagador); Callback<JsonObject> callBackRegistraPagador = new Callback<JsonObject>(){ public void success(JsonObject object, Response response){ System.out.println(object.toString()); } public void failure(RetrofitError retrofitError){ System.out.println(retrofitError.toString()); } };
그리고 그것! 내 개인적인 견해로는, pojos를 만들고 클래스 엉망으로 작업하는 것보다 훨씬 낫습니다. 이것은 훨씬 더 깨끗합니다.
특히 위 의 TypedString
하위 클래스 에 대한 Jake의 제안이 마음에 듭니다 . 푸시 업하려는 POST 데이터의 종류에 따라 다양한 서브 클래스를 만들 수 있으며, 각각 고유 한 맞춤 조정 세트가 있습니다.
Retrofit API에서 JSON POST 메소드에 헤더 주석을 추가 할 수도 있습니다…
@Headers( "Content-Type: application/json" )
@POST("/json/foo/bar/")
Response fubar( @Body TypedString sJsonBody ) ;
…하지만 서브 클래스를 사용하는 것이 더 분명한 자체 문서화입니다.
@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
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 핸들러 클래스 만들기
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 schema 2 pojo에서 bean 클래스 만들기
기억
- 대상 언어 : 자바 -source 유형 : JSON -Annotation 스타일 : GSON이 -를 선택하여 getter 및 setter를 포함 당신이 선택할 수 있습니다 - 또한 추가 속성을 허용
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) Call Api 이렇게
private void ApiCallMethod() {
try {
if (CommonUtils.isConnectingToInternet(MyActivity.this)) {
final ProgressDialog dialog;
dialog = new ProgressDialog(MyActivity.this);
dialog.setMessage("Loading...");
dialog.setCanceledOnTouchOutside(false);
dialog.show();
Call<ResponseBean> registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap());
registerCall.enqueue(new retrofit2.Callback<ResponseBean>() {
@Override
public void onResponse(Call<ResponseBean> registerCall, retrofit2.Response<ResponseBean> response) {
try {
//print respone
Log.e(" Full json gson => ", new Gson().toJson(response));
JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
Log.e(" responce => ", jsonObj.getJSONObject("body").toString());
if (response.isSuccessful()) {
dialog.dismiss();
int success = response.body().getSuccess();
if (success == 1) {
} else if (success == 0) {
}
} else {
dialog.dismiss();
}
} catch (Exception e) {
e.printStackTrace();
try {
Log.e("Tag", "error=" + e.toString());
dialog.dismiss();
} catch (Resources.NotFoundException e1) {
e1.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBean> call, Throwable t) {
try {
Log.e("Tag", "error" + t.toString());
dialog.dismiss();
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
});
} else {
Log.e("Tag", "error= Alert no internet");
}
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
복합 객체를 @Body
매개 변수 로 사용할 때 Retrofit과 잘 작동하지 않는다는 것을 알았 습니다 (이를 GSONConverter
사용한다고 가정 할 때). 작업 할 때 사용 JsonObject
하지 말아야 JSONObject
하며 그것에 NameValueParams
대해 자세하게 설명하지 않고 로깅 인터셉터 및 다른 shenanigans의 다른 종속성을 추가하는 경우에만 볼 수 있습니다.
그래서 이것을 해결하는 가장 좋은 방법은을 사용하는 것 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>
개조에 ScalarsConverterFactory를 추가하십시오.
gradle에서 :
implementation'com.squareup.retrofit2:converter-scalars:2.5.0'
개조 :
retrofit = new Retrofit.Builder()
.baseUrl(WEB_DOMAIN_MAIN)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
호출 인터페이스 @Body 매개 변수를 String으로 변경하십시오 @Headers("Content-Type: application/json")
.
@Headers("Content-Type: application/json")
@POST("/api/getUsers")
Call<List<Users>> getUsers(@Body String rawJsonString);
이제 원시 json을 게시 할 수 있습니다.
많은 노력을 기울인 후 기본 차이점은 매개 변수로 JsonObject
대신 보내야한다는 것입니다 JSONObject
.
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
최고의 답변을 바탕으로 모든 요청에 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으로 전달 될 수 있습니다.
추가 클래스를 만들거나 사용하지 않으려면을 사용할 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)
모든 API 호출에 대해 pojo 클래스를 작성하지 않으려는 경우 해시 맵을 사용할 수 있습니다.
HashMap<String,String> hashMap=new HashMap<>();
hashMap.put("email","this@gmail.com");
hashMap.put("password","1234");
그리고 이렇게 보내
Call<JsonElement> register(@Body HashMap registerApiPayload);
나는 이것을 시도했다 : Retrofit 인스턴스를 만들 때이 변환기 팩토리를 개조 빌더에 추가하십시오.
gsonBuilder = new GsonBuilder().serializeNulls()
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
여기에 주어진 답변을 더 명확하게하기 위해 확장 기능을 사용하는 방법입니다. Kotlin을 사용하는 경우에만 해당
MediaType 및 RequestBodycom.squareup.okhttp3:okhttp:4.0.1
객체를 생성하는 오래된 방법을 사용 하는 경우 더 이상 사용되지 않으며 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)
'Programing' 카테고리의 다른 글
드롭 다운 목록에서 기본 화살표 아이콘을 제거하는 방법 (선택 요소)? (0) | 2020.04.03 |
---|---|
Windows 탐색기에서 PowerShell을 어떻게 시작합니까? (0) | 2020.04.03 |
생년월일을 YYYYMMDD 형식으로 계산하십시오. (0) | 2020.04.03 |
IntelliJ IDEA가있는 git : 원격 저장소에서 읽을 수 없습니다 (0) | 2020.04.03 |
템플릿 Haskell과 연관된 타입 동의어 얻기 (0) | 2020.04.03 |