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) ”
'FrontEnd > Android 기초' 카테고리의 다른 글
[Android] Fragment 프래그먼트 (0) | 2022.08.03 |
---|---|
[Android] Inflater (0) | 2022.08.01 |
[Android] JSON 데이터 파싱하는 방법 (0) | 2022.07.26 |
[Android] SharedPreferences를 이용한, 데이터 저장과 불러오기 (0) | 2022.07.24 |
[Android] 이메일 형식 체크: Patterns.EMAIL_ADDRESS (0) | 2022.07.24 |