글을 쓸 당시에는 직접 구현했던 것을 토대로 작성했는데, 현재는 그럴 수가 없어 업데이트를 하지 못했습니다.
변경사항이 있다고 하니 유의 바랍니다.
Retrofit2을 통해 서버로 파일을 전송할 때 사용하게 된다.
아마 다음과 같은 형태로 인터페이스를 정의할 것이다.
@Multipart
@POST("api주소")
Call<SomeResponse> request(파라미터들...);
파일 전송때문에 Multipart 어노테이션이 붙어서, 그냥 보낼 수 있는 타입도 Multipart에 맞게 보내야 했던 것 같다.
왜그랬는지 기억은 안나는데, file 전송할 때 자꾸 안돼서 이것저것 계속 시도했었던 것 같다.
일단 내 경우에 성공적으로 동작했던 방법을 정리한다.
한개만 보내면 되는 경우, RequestBody
를 사용하면 된다.
@Multipart
@POST("api주소")
Call<SomeResponse> request(@Part("key") RequestBody param);
RequestBody
는 다음과 같이 만들 수 있다.
String text = "some text";
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), text);
위 코드는 String을 담기 때문에 MediaType을 "text/plain"으로 지정해줬다.
단일 항목이 많아서 파라미터를 구구절절 쓰기 싫을 때는 Map
으로 모아서 보낼 수 있다.
@Multipart
@POST("api주소")
Call<SomeResponse> request(@PartMap Map<String, RequestBody> params);
다음과 같이 Map
을 만들 수 있다.
RequestBody nameBody = RequestBody.create(MediaType.parse("text/plain"), "철수");
RequestBody ageBody = RequestBody.create(MediaType.parse("text/plain"), "15살");
RequestBody emailBody = RequestBody.create(MediaType.parse("text/plain"), "chulsu@email.com");
HashMap<String, RequestBody> requestMap = new HashMap<>();
requestMap.put("name", nameBody);
requestMap.put("age", ageBody);
requestMap.put("email", emailBody);
put
에 들어가는 String은 서버에서 받는 key값? 필드아이디?가 되겠다.
같은 항목에 대해서 배열로 보내야 할 경우 List
를 사용한다.
하지만 RequestBody
를 사용하지 않고, MultipartBody.Part
를 사용한다.
@Multipart
@POST("api주소")
Call<SomeResponse> request(@Part List<MultipartBody.Part> params);
List<MultipartBody.Part>
는 다음과 같이 만들 수 있다.
ArrayList<MultipartBody.Part> names = new ArrayList<>();
names.add(Multipart.Part.createFormData("이름", "철수");
names.add(Multipart.Part.createFormData("이름", "제임스");
names.add(Multipart.Part.createFormData("이름", "존");
// 계속 추가...
그냥 MultipartBody.Part
형태로 보내면 된다.
@Multipart
@POST("api주소")
Call<SomeResponse> request(@Part MultipartBody.Part file);
file을 담는 MultipartBody.Part
는 다음과 같이 만든다.
나는 사진을 보냈어야 했기 때문에 예시도 사진을 보내는 경우를 썼다.
// Uri 타입의 파일경로를 가지는 RequestBody 객체 생성
RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), Uri filePath);
// RequestBody로 Multipart.Part 객체 생성
MultipartBody.part filePart = Multipart.Part.createFormData("photo", "photo.jpg", fileBody);
createFormData(...)
에 들어가는 파라미터는 순서대로 다음과 같은 의미를 가진다.
1. 서버에서 받는 키값 String
2. 파일 이름 String
3. 파일 경로를 가지는 RequestBody 객체
같은 key값으로 여러항목을 보낼 때 처럼 List
를 사용한다.
@Multipart
@POST("api주소")
Call<SomeResponse> request(@Part List<MultipartBody.Part> files);
file을 담는 List<MultipartBody.Part>
는 다음과 같이 만들 수 있다.
// 여러 file들을 담아줄 ArrayList
ArrayList<MultipartBody.Part> files = new ArrayList<>();
// 파일 경로들을 가지고있는 `ArrayList<Uri> filePathList`가 있다고 칩시다...
for (int i = 0; i < filePathList.size(); ++i) {
// Uri 타입의 파일경로를 가지는 RequestBody 객체 생성
RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), filePathList.get(i));
// 사진 파일 이름
String fileName = "photo" + i + ".jpg";
// RequestBody로 Multipart.Part 객체 생성
MultipartBody.part filePart = Multipart.Part.createFormData("photo", fileName, fileBody);
// 추가
files.add(filePart);
}
단일 file처럼 똑같이 RequestBody
만들고, 그걸로 MultipartBody.Part
만든 다음,
ArrayList<MultipartBody.Part>
에 넣어주기만 하면 된다.
이것때문에 아주 머리가 아팠다.
자꾸 안되는데, 사람마다 방법이 아예 다른것도 아니고 찔끔찔끔 다르고, file이 아닌걸 보내는 방법과... file인데 한개만 보내는 방법과... 여러개를 보내는 방법 등이 다 정리되어 있는 글도 없어서 더 복잡했다.
포스팅이 많이 도움이 되었습니다! 감사합니다 :)