이미지를 포함한 Retrofit 2.0을 사용한 POST 다중 부품 폼 데이터
Retrofit 2.0을 사용하여 서버에 HTTP POST를 수행하려고 합니다.
MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/*");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG,90,byteArrayOutputStream);
profilePictureByte = byteArrayOutputStream.toByteArray();
Call<APIResults> call = ServiceAPI.updateProfile(
RequestBody.create(MEDIA_TYPE_TEXT, emailString),
RequestBody.create(MEDIA_TYPE_IMAGE, profilePictureByte));
call.enqueue();
서버에서 파일이 올바르지 않다는 오류를 반환합니다.
iOS에서 (다른 라이브러리를 사용하여) 동일한 형식의 파일을 업로드하려고 했지만 성공적으로 업로드되기 때문에 이상합니다.
Retrofit 2.0을 사용하여 이미지를 업로드하는 올바른 방법이 무엇인지 궁금합니다.
업로드하기 전에 디스크에 저장해야 합니까?
추신: 저는 이미지가 포함되지 않은 다른 멀티파트 요청에 대해 개조를 사용했고 성공적으로 완료되었습니다.문제는 제가 신체에 바이트를 포함시키려고 할 때입니다.
Retrofit 2와 함께 해킹 없이 파일 이름을 업로드하는 올바른 방법이 있습니다.
API 인터페이스 정의:
@Multipart
@POST("uploadAttachment")
Call<MyResponse> uploadAttachment(@Part MultipartBody.Part filePart);
// You can add other parameters too
다음과 같은 파일 업로드:
File file = // initialize file here
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
Call<MyResponse> call = api.uploadAttachment(filePart);
, . 동일한 방법으로 다른 매개 변수를 추가할 수도 있습니다.@Part
주석
1.9와 2.0 모두에서 솔루션을 강조하고 있는데, 이는 일부 사용자에게 유용하기 때문입니다.
1.9
하고 다음과 file로 이 더
RetroFit 1.9
(서버 측 구현에 대해 잘 모르겠습니다) 이와 유사한 API 인터페이스 방법이 있습니다.
@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file") TypedFile file,
@Part("folder") String folder,
Callback<Response> callback);
그리고 이렇게 사용합니다.
TypedFile file = new TypedFile("multipart/form-data",
new File(path));
RetroFit 2의 경우 다음 방법을 사용합니다.
RetroFit 2.0(이것은 RetroFit 2의 문제에 대한 해결 방법이었으며, 현재 수정되었습니다. 올바른 방법은 jimmy0251의 답변을 참조하십시오.)
API 인터페이스:
public interface ApiInterface {
@Multipart
@POST("/api/Accounts/editaccount")
Call<User> editUser(@Header("Authorization") String authorization,
@Part("file\"; filename=\"pp.png\" ") RequestBody file,
@Part("FirstName") RequestBody fname,
@Part("Id") RequestBody id);
}
다음과 같이 사용:
File file = new File(imageUri.getPath());
RequestBody fbody = RequestBody.create(MediaType.parse("image/*"),
file);
RequestBody name = RequestBody.create(MediaType.parse("text/plain"),
firstNameField.getText()
.toString());
RequestBody id = RequestBody.create(MediaType.parse("text/plain"),
AZUtils.getUserId(this));
Call<User> call = client.editUser(AZUtils.getToken(this),
fbody,
name,
id);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(retrofit.Response<User> response,
Retrofit retrofit) {
AZUtils.printObject(response.body());
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
레지스터 사용자를 위해 Retrofit 2.0을 사용하여 멀티파트/폼 전송 레지스터 계정에서 파일 이미지와 텍스트를 보냅니다.
내 등록 활동에서 비동기 작업 사용
//AsyncTask
private class Register extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {..}
@Override
protected String doInBackground(String... params) {
new com.tequilasoft.mesasderegalos.dbo.Register().register(txtNombres, selectedImagePath, txtEmail, txtPassword);
responseMensaje = StaticValues.mensaje ;
mensajeCodigo = StaticValues.mensajeCodigo;
return String.valueOf(StaticValues.code);
}
@Override
protected void onPostExecute(String codeResult) {..}
그리고 내 Register.java 클래스에서는 동기식 호출과 함께 Retrofit을 사용합니다.
import android.util.Log;
import com.tequilasoft.mesasderegalos.interfaces.RegisterService;
import com.tequilasoft.mesasderegalos.utils.StaticValues;
import com.tequilasoft.mesasderegalos.utils.Utilities;
import java.io.File;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;
/**Created by sam on 2/09/16.*/
public class Register {
public void register(String nombres, String selectedImagePath, String email, String password){
try {
// create upload service client
RegisterService service = ServiceGenerator.createUser(RegisterService.class);
// add another part within the multipart request
RequestBody requestEmail =
RequestBody.create(
MediaType.parse("multipart/form-data"), email);
// add another part within the multipart request
RequestBody requestPassword =
RequestBody.create(
MediaType.parse("multipart/form-data"), password);
// add another part within the multipart request
RequestBody requestNombres =
RequestBody.create(
MediaType.parse("multipart/form-data"), nombres);
MultipartBody.Part imagenPerfil = null;
if(selectedImagePath!=null){
File file = new File(selectedImagePath);
Log.i("Register","Nombre del archivo "+file.getName());
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual file name
imagenPerfil = MultipartBody.Part.createFormData("imagenPerfil", file.getName(), requestFile);
}
// finally, execute the request
Call<ResponseBody> call = service.registerUser(imagenPerfil, requestEmail,requestPassword,requestNombres);
Response<ResponseBody> bodyResponse = call.execute();
StaticValues.code = bodyResponse.code();
StaticValues.mensaje = bodyResponse.message();
ResponseBody errorBody = bodyResponse.errorBody();
StaticValues.mensajeCodigo = errorBody==null
?null
:Utilities.mensajeCodigoDeLaRespuestaJSON(bodyResponse.errorBody().byteStream());
Log.i("Register","Code "+StaticValues.code);
Log.i("Register","mensaje "+StaticValues.mensaje);
Log.i("Register","mensajeCodigo "+StaticValues.mensaje);
}
catch (Exception e){
e.printStackTrace();
}
}
}
RegisterService 인터페이스
public interface RegisterService {
@Multipart
@POST(StaticValues.REGISTER)
Call<ResponseBody> registerUser(@Part MultipartBody.Part image,
@Part("email") RequestBody email,
@Part("password") RequestBody password,
@Part("nombre") RequestBody nombre
);
}
유틸리티의 경우 r InputStream 응답 구문 분석
public class Utilities {
public static String mensajeCodigoDeLaRespuestaJSON(InputStream inputStream){
String mensajeCodigo = null;
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(
inputStream, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
inputStream.close();
mensajeCodigo = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
return mensajeCodigo;
}
}
Retrofit 2.0에서 이미지 파일 업로드를 위한 코드 업데이트
public interface ApiInterface {
@Multipart
@POST("user/signup")
Call<UserModelResponse> updateProfilePhotoProcess(@Part("email") RequestBody email,
@Part("password") RequestBody password,
@Part("profile_pic\"; filename=\"pp.png")
RequestBody file);
}
MediaType.parse("image/*")
MediaType.parse("image/jpeg")
RequestBody reqFile = RequestBody.create(MediaType.parse("image/jpeg"),
file);
RequestBody email = RequestBody.create(MediaType.parse("text/plain"),
"upload_test4@gmail.com");
RequestBody password = RequestBody.create(MediaType.parse("text/plain"),
"123456789");
Call<UserModelResponse> call = apiService.updateProfilePhotoProcess(email,
password,
reqFile);
call.enqueue(new Callback<UserModelResponse>() {
@Override
public void onResponse(Call<UserModelResponse> call,
Response<UserModelResponse> response) {
String
TAG =
response.body()
.toString();
UserModelResponse userModelResponse = response.body();
UserModel userModel = userModelResponse.getUserModel();
Log.d("MainActivity",
"user image = " + userModel.getProfilePic());
}
@Override
public void onFailure(Call<UserModelResponse> call,
Throwable t) {
Toast.makeText(MainActivity.this,
"" + TAG,
Toast.LENGTH_LONG)
.show();
}
});
그래서 이것은 여러분의 임무를 달성하는 아주 간단한 방법입니다.다음 단계를 수행해야 합니다.
첫걸음
public interface APIService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(
@Part("item") RequestBody description,
@Part("imageNumber") RequestBody description,
@Part MultipartBody.Part imageFile
);
}
은 전체 를 전체통화다해합니야다로 해야 .@Multipart request
.item
그리고.image number
는 그냥 에싸 있문본뿐문입다니일로 싸인 문자열 입니다.RequestBody
우리는 사용합니다.MultipartBody.Part class
시할 수 .
두 번째 단계
File file = (File) params[0];
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body =MultipartBody.Part.createFormData("Image", file.getName(), requestBody);
RequestBody ItemId = RequestBody.create(okhttp3.MultipartBody.FORM, "22");
RequestBody ImageNumber = RequestBody.create(okhttp3.MultipartBody.FORM,"1");
final Call<UploadImageResponse> request = apiService.uploadItemImage(body, ItemId,ImageNumber);
이제 당신은image path
로 변환해야 합니다.file
.이제 변환file
안으로RequestBody
사용법RequestBody.create(MediaType.parse("multipart/form-data"), file)
이제 변환해야 합니다.RequestBody requestFile
안으로MultipartBody.Part
사용법MultipartBody.Part.createFormData("Image", file.getName(), requestBody);
.
ImageNumber
그리고.ItemId
서버로 보내야 하는 또 다른 데이터이기 때문에 저도 두 가지를 모두 만들고 있습니다.RequestBody
.
@insomniac이 제공한 답변에 추가.다음을 생성할 수 있습니다.Map
에 대한 매개 변수를 지정합니다.RequestBody
이미지를 포함합니다.
인터페이스 코드
public interface ApiInterface {
@Multipart
@POST("/api/Accounts/editaccount")
Call<User> editUser (@Header("Authorization") String authorization, @PartMap Map<String, RequestBody> map);
}
자바 클래스의 코드
File file = new File(imageUri.getPath());
RequestBody fbody = RequestBody.create(MediaType.parse("image/*"), file);
RequestBody name = RequestBody.create(MediaType.parse("text/plain"), firstNameField.getText().toString());
RequestBody id = RequestBody.create(MediaType.parse("text/plain"), AZUtils.getUserId(this));
Map<String, RequestBody> map = new HashMap<>();
map.put("file\"; filename=\"pp.png\" ", fbody);
map.put("FirstName", name);
map.put("Id", id);
Call<User> call = client.editUser(AZUtils.getToken(this), map);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(retrofit.Response<User> response, Retrofit retrofit)
{
AZUtils.printObject(response.body());
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
의 확장 메서드를 MediaType, RequestBody 및 RequestBody로 사용하면 kotlin은 매우 간단합니다. 예를 들어 다음과 같습니다.
여기에 pdf 파일과 멀티파트를 사용한 이미지 파일과 함께 두 개의 일반 필드를 게시합니다.
Retrofit을 사용한 API 선언입니다.
@Multipart
@POST("api/Lesson/AddNewLesson")
fun createLesson(
@Part("userId") userId: RequestBody,
@Part("LessonTitle") lessonTitle: RequestBody,
@Part pdf: MultipartBody.Part,
@Part imageFile: MultipartBody.Part
): Maybe<BaseResponse<String>>
그리고 이것을 실제로 부르는 방법은 다음과 같습니다.
api.createLesson(
userId.toRequestBody("text/plain".toMediaType()),
lessonTitle.toRequestBody("text/plain".toMediaType()),
startFromRegister.toString().toRequestBody("text/plain".toMediaType()),
MultipartBody.Part.createFormData(
"jpeg",
imageFile.name,
imageFile.asRequestBody("image/*".toMediaType())
),
MultipartBody.Part.createFormData(
"pdf",
pdfFile.name,
pdfFile.asRequestBody("application/pdf".toMediaType())
)
* Return MultipartBody from file path
public static MultipartBody.Part generateFileBody(String imagePath)
{
File file = new File(imagePath);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
return MultipartBody.Part.createFormData("mediaProfilePic", file.getName(), requestFile);
}
Retrofit을 사용하여 파일을 업로드하는 것은 매우 간단합니다. api 인터페이스를 다음과 같이 구축해야 합니다.
public interface Api {
String BASE_URL = "http://192.168.43.124/ImageUploadApi/";
@Multipart
@POST("yourapipath")
Call<MyResponse> uploadImage(@Part("image\"; filename=\"myfile.jpg\" ") RequestBody file, @Part("desc") RequestBody desc);
}
위의 코드 이미지에 키 이름이 있으므로 php를 사용하는 경우 $_FILES['image']['tmp_name']를 입력하여 이를 얻을 수 있습니다.그리고 filename="myfile.jpg"는 요청과 함께 전송되는 파일의 이름입니다.
이제 파일을 업로드하려면 URI에서 절대 경로를 제공하는 방법이 필요합니다.
private String getRealPathFromURI(Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
이제 아래 코드를 사용하여 파일을 업로드할 수 있습니다.
private void uploadFile(Uri fileUri, String desc) {
//creating a file
File file = new File(getRealPathFromURI(fileUri));
//creating request body for file
RequestBody requestFile = RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), file);
RequestBody descBody = RequestBody.create(MediaType.parse("text/plain"), desc);
//The gson builder
Gson gson = new GsonBuilder()
.setLenient()
.create();
//creating retrofit object
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Api.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
//creating our api
Api api = retrofit.create(Api.class);
//creating a call and calling the upload image method
Call<MyResponse> call = api.uploadImage(requestFile, descBody);
//finally performing the call
call.enqueue(new Callback<MyResponse>() {
@Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
if (!response.body().error) {
Toast.makeText(getApplicationContext(), "File Uploaded Successfully...", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Some error occurred...", Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<MyResponse> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
자세한 내용은 이 Retrofit Upload File 튜토리얼을 참조하십시오.
Kotlin 버전 및 사용률 감소를 위한 업데이트 포함RequestBody.create
:
인터페이스 개조
@Multipart
@POST("uploadPhoto")
fun uploadFile(@Part file: MultipartBody.Part): Call<FileResponse>
및 업로드 대상
fun uploadFile(fileUrl: String){
val file = File(fileUrl)
val fileUploadService = RetrofitClientInstance.retrofitInstance.create(FileUploadService::class.java)
val requestBody = file.asRequestBody(file.extension.toMediaTypeOrNull())
val filePart = MultipartBody.Part.createFormData(
"blob",file.name,requestBody
)
val call = fileUploadService.uploadFile(filePart)
call.enqueue(object: Callback<FileResponse>{
override fun onFailure(call: Call<FileResponse>, t: Throwable) {
Log.d(TAG,"Fckd")
}
override fun onResponse(call: Call<FileResponse>, response: Response<FileResponse>) {
Log.d(TAG,"success"+response.toString()+" "+response.body().toString()+" "+response.body()?.status)
}
})
}
@jimmy0251 덕분에
requestBody는 업로드에 사용할 수 있습니다.
val body: RequestBody = Builder().setType(MultipartBody.FORM)
.addFormDataPart(
"file", "<image name you wish to give>",
RequestBody.create(
MediaType.parse("application/octet-stream"),
File(path)
)
)
.build()
uploadProfilePhoto(body)
그러면 다음과 같이 전화합니다.
@POST("/**")
suspend fun uploadProfilePhoto(
@Body body: RequestBody,
): ResponseBody
}
함수 이름에 여러 매개 변수를 사용하지 말고 코드의 가독성을 높일 수 있는 간단한 몇 개의 변수 규칙만 사용하면 됩니다. 이를 위해 다음과 같이 할 수 있습니다.
// MultipartBody.Part.createFormData("partName", data)
Call<SomReponse> methodName(@Part MultiPartBody.Part part);
// RequestBody.create(MediaType.get("text/plain"), data)
Call<SomReponse> methodName(@Part(value = "partName") RequestBody part);
/* for single use or you can use by Part name with Request body */
// add multiple list of part as abstraction |ease of readability|
Call<SomReponse> methodName(@Part List<MultiPartBody.Part> parts);
Call<SomReponse> methodName(@PartMap Map<String, RequestBody> parts);
// this way you will save the abstraction of multiple parts.
Retrofit을 사용하는 동안 발생할 수 있는 여러 예외가 있을 수 있습니다. 모든 예외는 코드로 문서화되어 있습니다. 두 가지 기능을 수행할 수 있습니다.parseParameterAnnotation
그리고.parseMethodAnnotation
예외를 적용할 수 있는 경우 이 과정을 거치면 구글/스택 오버플로보다 시간이 많이 절약됩니다.
저의 경우 PDF 파일을 보내야 했습니다.application/pdf
), JSON 정보와 함께 (application/json
감사하게도, Retrofit2는 이것을 매우 간단하게 만듭니다.
내 인터페이스는 다음과 같습니다.
interface MyApi {
@Multipart
@POST("upload")
fun uploadPDF(
@Part file: MultipartBody.Part,
@Part(value = "jsoninfo") jsoninfo: MyJsonObject
): Call<MyResponse>
}
어디에jsoninfo
내 JSON 데이터의 이름입니다.MyJsonObject
이고, 데터클입다니스래이다▁my입니다.MyResponse
물론 제가 기대하는 반응입니다.
그런 다음, 저는 제 API 메서드를 다음과 같이 부릅니다.
val myJsonObject = MyJsonObject(...)
// "file" is of type byte[] already
val requestBody = RequestBody.create(file, MediaType.parse("application/pdf"))
val filePart = MultipartBody.Part.createFormData("file", "myfile.pdf", requestBody)
api.uploadPDF(filePart, myJsonObject).enqueue(...)
언급URL : https://stackoverflow.com/questions/34562950/post-multipart-form-data-using-retrofit-2-0-including-image
'programing' 카테고리의 다른 글
Android의 .dex 파일이란 무엇입니까? (0) | 2023.08.02 |
---|---|
추가하기 전에 클래스가 이미 할당되었는지 확인합니다. (0) | 2023.08.02 |
웹 방법 대 스크립트 방법 (0) | 2023.08.02 |
Oracle 환경에서 TNS: 청취자란 무엇입니까? (0) | 2023.08.02 |
H1 텍스트를 로고 이미지로 대체: SEO 및 접근성을 위한 최선의 방법? (0) | 2023.08.02 |