본문 바로가기

FrontEnd/Android 기초

[Android] Retrofit에서 Multipart form으로 데이터를 보내는 방법

반응형

Retrofit에서 Multipart form으로 데이터를 보내는 방법

파일을 보내기 위한 방법

텍스트를 보내기 위한 방법

 

Multipart란?

Multipart는 HTTP를 통해 File을 Server로 전송하기 위해 사용되는 Content-type이다. HTTP 프로토콜은 크게 Header와 Body로 구분이 되고, 데이터는 Body에 들어가서 전송이 되는데, Body에 들어가는 데이터 타입을 명시해주는 게 Content-type이다. 이때 타입으로 지정해주는 형태를 MIME 타입으로 지정해줄 수 있는데, Multupart(=multipart/form-data)는 MIME 타입 중 하나이다.

 

Multipart는 말 그대로 메시지(파일)을 여러 파트로 나누어서 메시지를 전달하는 방식이라고 이해하면 좋다.


API 명세서

API를 작성할 때는, API명세서를 보면서 작성한다. 

기존에 작성해두었던 Postman에 있는 사진 파일 및 컨텐트 작성하여 업로드 하는 API를 참고하자. 

하기 포스트맨 이미지를 보면, 

서버에 전송될 내용은 

HTTP 메소드 : POST

Header에는 억세스토큰이, Body에는 파일인 KEY: photo, 그리고 메시지인 KEY: content라는 것을 볼 수 있다. 이 내용에 맞추어서 API 코드를 설계하면 된다. 

 


코드 작성 

 

1. 안드로이드에서 우선 Manifest에서 Permission을 추가한다.

 

핸드폰의 카메라를 사용할 수 있게, 그리고 저장소의 데이터를 저장하고 확인할 수 있는 퍼미션이다.

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 

 

2. API를 불러오기 전에, model 패키지 안에 PostRes의 자바 파일을 만들어서, 서버 응답을 받을 클래스를 만든다.

  서버에서 받을 응답은 “result: success”로 result 키값 하나뿐이니, 코드는 하기 참고. 그리고, getter,setter로 설정해준다.

 

 
public class PostRes {

   private String result;

   public String getResult() {
       return result;
   }
   public void setResult(String result) {
       this.result = result;
   }
}

 

3. api 패키지에 PostingApi의 인터페이스를 만들어준뒤, 서버와 통신하는 API를 작성한다. 

 

 
  @Multipart
   @POST("/posting")
// HTTP 메소드 ( “ 경로 ” )

   Call<PostRes> addPosting(@Header("Authorization") String token,
// PostRes 클래스에 응답을 받을 것이다.
// 함수 이름은 addPosting
// @Header은 Authorization이라고 되어있는 부분이고, 변수 이름은 token이라 하겠다.

                            @Part MultipartBody.Part photo,
// @Part 하나의 파트는 단일 FIle: MultipartBody.Part
// 여기서의 KEY-VALUE는 여기가 아니라 다른곳에서 작성할 것이다.
// 변수 이름은 photo라 하겠다.

                            @Part("content")RequestBody content);
// @Part 또 하나의 파트는 File이 아닌 단일 항목: RequestBody
// content는 메시지이다. 포스트맨을 보면 보내는 request KEY가 content이다. 
// 변수 이름은 content라 하겠다.

-> Multipart 어노테이션을 붙여줘야한다. 그래야 MultupartBody.part를 넣을 수 있다.

@Multipart

 

4. 해당 API를 호출할 액티비티로 가서 코드를 작성하기 전에 예외처리를 우선 한다.

- File이 없을 경우

- Content가 비어있을 경우

 
if(photoFile == null){
   Toast.makeText(AddActivity.this, "사진을 선택하세요.", Toast.LENGTH_SHORT).show();
   return;
}

String content = editContent.getText().toString().trim();

if(content.isEmpty()){
   Toast.makeText(AddActivity.this, "내용을 입력하세요.", Toast.LENGTH_SHORT).show();
   return;
}

Retrofit retrofit = NetworkClient.getRetrofitClient(AddActivity.this);
PostingApi api = retrofit.create(PostingApi.class);

예외 처리를 하고 나서, 네트워크 통신을 요청한다.

 

5. 파일/텍스트 파라미터 코드를 작성한다. 

 

Call<PostRes> call = api.addPosting()

여기에 파라미터가 억세스토큰, 파일, 메시지가 필요하므로 해당 코드를 작성해준다.

 

 
private File photoFile;

 

멤버 변수 만들어놓고

 

 

- 멀티파트로 파일을 보내는 경우, 파일 파라미터 만드는 방법

 
RequestBody fileBody = RequestBody.create(photoFile, MediaType.parse("image/*"));
// 첫번째 파라미터: 멤버변수로 만들어놓은 photoFile, 보낸 사진. 
// 두번째 파라미터: MediaType으로 보내는 파일의 타입을 정하는 것.
// parse로 정해준다. 여기서는 사진파일을 다루기 때문에 "image/*"로 처리했다.

MultipartBody.Part photo = MultipartBody.Part.createFormData("photo",
       photoFile.getName(), fileBody);
// 위에 작성한 fileBody를 쪼개라는 뜻. 우리에게 필요한 Multipart.Part로 변환해준다.
// 첫번째 파라미터: 서버에서 받는 KEY값
// 두번째 파라미터: 파일 이름. photoFile.getName() 해서 얻어올 수 있다.
// 세번째 파라미터는 상기 코드인 fileBody

 

API 명세서에 Form-data라고 되어있어, 해당 코드도 createFormData로 작성한다.

 

- 멀티파트로 텍스트를 보내는 경우, 파라미터 만드는 방법

 
RequestBody contentBody = RequestBody.create(content, MediaType.parse("text/plain"));
// 위와 같은 형식이다. 첫번째 파라미터는 EditText로 가져온 변수이름 content
// 두번째 파라미터는 미디어타입:텍스트이기 때문에 "text/plain"로 기재한다.

 

6. API 헤더에 들어갈 AcceessToken을 가져온다.

억세스 토큰은 SharedPreference에 있다.

 
SharedPreferences sp = getApplication().getSharedPreferences(Config.PREFERENCES_NAME, MODE_PRIVATE);

String accessToken = sp.getString("accessToken", "");

 

getSharedPreferences에서 저장소 이름은 Config 파일에서 모아 관리하였다.

 

7. API를 호출한다.

 
Call<PostRes> call = api.addPosting("Bearer "+ accessToken,
       photo,
       contentBody);

 

위에 작성한 코드의 변수를 넣었다.

 

8. 네트워크 실행

 
showProgress("포스팅 업로드 중...");

call.enqueue(new Callback<PostRes>() {
   @Override
   public void onResponse(Call<PostRes> call, Response<PostRes> response) {
       dismissProgress();

       Toast.makeText(AddActivity.this, "업로드가 완료되었습니다.", Toast.LENGTH_SHORT).show();
       finish();
   }

   @Override
   public void onFailure(Call<PostRes> call, Throwable t) {
       dismissProgress();
   }
});

 

ProgressBar를 네트워크 통신하는 동안 띄우고, 없어지게 해놓은 함수가 showProgress()와 dismissProgress()이다. 

코드는 하기와 같다.

 
void showProgress(String message){
   dialog = new ProgressDialog(this);
   dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
   dialog.setMessage(message);
   dialog.show();
}

void dismissProgress(){
   dialog.dismiss();
}

 

9. 테스트 해보고, 실제 업로드 되어있는 지 확인한다.

나는 AWS의 S3에 저장했음. 

추후 유지보수를 위해 Config파일에 상수를 만들어준다.

public static final String IMAGE_URL = “ (이미지 파일명 이전까지의 s3 URL) ”


반응형