게시판을 구현하던지, SNS앱을 구현하다보면 서버에 이미지와 같은 파일을 보내야할 때가 있다. 사실 저번 프로젝트에서도 사진과 String과 같은 데이터를 서버에 업로드해야했지만 결국 내가 못하고 다른 팀원이 했었다. 그래서 이번 프로젝트에서는 꼭 성공하고 싶었다. 관련 자료를 찾아봐도 내 프로젝트와 환경이 다르고 api 형식도 달라서 한참 헤맸다.
코틀린으로 된 코드도 많이 없었다...
먼저 위 사진은 서버파트 쪽에서 넘겨준 api 형식이다. 일단 이미지 파일과 같은 파일이 있는 경우 form-data 형식으로 api를 작성해서 넘겨줄 확률이 매우 높다.
먼저 retrofit의 service를 작성할 때 맨 윗줄에 Multipart를 어노테이션 해야 한다. 그 뒤 @Body를 통해 보내던 request를 저 위의 사진인 KEY, VALUE 개수 많큼 @Part를 이용해서 데이터를 담아야한다.
interface CreateProjectService {
@Multipart // 중요!!
@POST("/project/registration")
fun postCreateProject(
@Header("X-ACCESS-TOKEN") jwt: String,
@Part ("jsonList") jsonList: RequestBody, // 여기 RequestBody를 확인
@Part images: MultipartBody.Part?,
): Call<ResponseCreateProjectData>
}
만약 KEY, VALUE값이 너무나 많아서 하나로 묶고 싶으면 Part 대신 PartMap을 사용하면 된다. 또 중요한건 @Part 어노테이션이 들어간 변수의 형식은 RequestBody를 써야 한다. 서버측 api에서 jsonList가 String이라길래 String으로도 해봤는데 안된다. 그 뒤에 서버 연결하는 파일로 가서 다음과 같이 이미지 파일을 form-data
형태로 변환시켜준다. MIME 타입 참고 사이트
// mediaPath는 이미지 파일의 경로로 추후에 갤러리와 카메라로부터 사진 가져오기를 하면서 블로그에 남길 예정이다.
fileToUpload = if (mediaPath!=null){
val file = File(mediaPath)
// image/jpeg 타입은 MIME 타입을 따르기 위함이다. 일반적인 String같은 경우 text/plain과 같이 쓴다.
val requestBody = file.asRequestBody("image/jpeg".toMediaTypeOrNull())
MultipartBody.Part.createFormData("images", file.name, requestBody)
// 우리 프로젝트에서는 이미지 파일이 없으면 null로 넘겨주기로 약속했기 때문에 이미지 경로가 없으면 null처리 해준다.
} else{
null
}
이미지 파일 뿐만 아니라 jsonList의 키 값을 가진 형식도 RequestBody 형식으로 변환해주어야 한다.
val jsonString = "{프로젝트마다 들어가야 할 요소들}"
val jsonList = jsonString.toRequestBody("text/plain".toMediaTypeOrNull())
마지막으로 평상시 서버 연결할때 처럼 인자에 fileToUpload와 jsonList를 넣어주면 된다.
val call : Call<ResponseCreateProjectData> = ServiceCreator.createProjectService
.postCreateProject(jwt, jsonList , fileToUpload)