-
Android Studio - Retrofit @Multipart 이미지 & @PartMap으로 데이터 전송하기Android Studio 2021. 4. 5. 20:17
졸업작품은 이제 끝났으니..! 시간이 빈 김에 까먹지 않게끔 후딱! 쓰는 이미지 전송하기...
이미지를 전송할 땐 Multipart로 써야하는데, 이미지 뿐 아니라 다른 정보들까지 전송을 함께 해야하기 때문에 대체 뭘로 전송해야할지 감을 못 잡았다. 그리고 아래에도 서술하겠지만, 하라는거 다 했고, 서버로부터의 응답도 200인데 DB에 계속 이미지가 안 들어가길래 그걸로 한참 날렸다. 결과적으로 클라이언트 쪽에서 압축을 안하면 DB에 안 들어간다...^^ 너무 어이 없고 ㅋㅋㅋ 허무해서 눈물났었다. 쨌든 이미지 전송때문에 너무 고생했어서, 누군가에게 도움이 되었으면 하는 마음 + 다시는 이 고생 안 하리라는 다짐 겸 쓰는 포스팅이다.
우선 백엔드 담당 팀원이 올려준 위키의 RequestBody를 가져와봤다. 이미지와 다른 데이터(String, double등등) 들까지 보내야하는 상황이다.
저기서 이미지는 form-data(폼데이터)가 확실한데, 나머지는 대체 어떻게 보내는거지?? 하고 한참 헤맸다. 결론부터 말하자면, 사진의 나머지 데이터들(city, country등)도 request body로 만들어서 보내줘야한다.
우선 API 인터페이스 파일은 아래와 같이 작성했다.
@Multipart @POST("/record") Call<EditResponse> userEdit(@Header("token")String token, @Part MultipartBody.Part postImg, @PartMap HashMap<String, RequestBody> data);
RequestHeader에 있던 token은 그대로 @Header 어노테이션으로 넣어준다.
img파일은 MultipartBody.Part로 한번더 감싸서 넣어준다.
그리고 그 외 나머지 데이터들은 @PartMap으로 넣어주었다. (HashMap자료구조 사용)
그리고 이미지 제외한 나머지 데이터들은 RequestBody로 만들어서 map에 넣어주었다. MediaType은 그냥 text/plain으로 해주면 된다.
RequestBody town = RequestBody.create(MediaType.parse("text/plain"),city); RequestBody nation = RequestBody.create(MediaType.parse("text/plain"),country); RequestBody texts = RequestBody.create(MediaType.parse("text/plain"),text); RequestBody lats = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(lat)); RequestBody lons = RequestBody.create(MediaType.parse("text/plain"),String.valueOf(lon)); RequestBody useridx = RequestBody.create(MediaType.parse("text/plain"),String.valueOf(userIdx)); RequestBody date = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(resetDate)); RequestBody locate = RequestBody.create(MediaType.parse("text/plain"), detailAddress); map.put("city", town); map.put("country", nation); map.put("text", texts); map.put("lattitude", lats); map.put("longtitude", lons); map.put("userIdx", useridx); map.put("date", date); map.put("location", locate);
근데 여기서 주의사항이 있는데, RequestBody에는 int, double같은 숫자형 데이터가 안 들어간다. 그냥 lat(double형) 넣으려하면 빨간줄 쳐지면서 안 된다고 뜬다. 그래서 String.valueOf()로 변환해서 넣어줘야 한다.
RequestBody lats = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(lat));
그러고 나서 map에 넣어야하는데, 이때 key값은 서버 위키에 써있는 값과 동일하게 써줘야한다. (위의 위키 캡처에 써있는 key값 참고)
map.put("서버측이 써준 키값", RequestBody);
map은 위 방법대로 생성해 주고, 다음은 이미지 처리를 위한 코드이다.
//filepath는 String 변수로 갤러리에서 이미지를 가져올 때 photoUri.getPath()를 통해 받아온다. File file = new File(filepath); InputStream inputStream = null; try { inputStream = getContext().getContentResolver().openInputStream(photoUri); }catch(IOException e) { e.printStackTrace(); } Bitmap bitmap = BitmapFactory.decodeStream(inputStream); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 20, byteArrayOutputStream); RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpg"), byteArrayOutputStream.toByteArray()); MultipartBody.Part uploadFile = MultipartBody.Part.createFormData("postImg", file.getName() ,requestBody);
bitmap이미지를 jpeg포맷으로 20%압축하여 byteArrayOutputStream에 저장한다. 이를 RequestBody로 만들어주고, 한번 더 MultipartBody.Part로 감싸주었다.
createFormData의 두 번째 변수에 file의 이름이 필요해서 file객체를 맨 위의 줄에서 만들었다.
createFormData의 첫 번째 변수 postImg는 서버에 전달할 이름이다. (서버에서 붙여준 변수 이름대로 작성)
* 압축하는 이유?
압축을 처음에 진행을 안하고 했었는데 서버로부터의 응답은 200 OK 인데 DB에 안 들어가는 일이 있었다. 서버 측에서는 postman으로 넣었을 때는 된다고 해서 왜 안돼지???하다가 압축하니까 바로 들어갔었다. 혹시 다 맞춰썼는데 DB에 안 들어간다면 이 이유일수도 있다.
마지막으로, 최종 서버와 통신하는 코드는 다음과 같다.
serviceApi.userEdit(token, uploadFile, map).enqueue(new Callback<EditResponse>() { @Override public void onResponse(Call<EditResponse> call, Response<EditResponse> response) { EditResponse result = response.body(); if(result.getStatus() == 200) { Toast.makeText(save_button.getContext(),"저장이 완료되었습니다.",Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<EditResponse> call, Throwable t) { Toast.makeText(save_button.getContext(), "통신에러",Toast.LENGTH_SHORT).show(); } } );
막상 포스팅하니까 별로 내용이 많진 않은데, 정말 며칠동안 헤맸다. 다시는 헤매지 않기 위해 작성하는 글 겸, 혹시 서버로부터 200떴는데 왜 DB에 안들어가는지 구글링하는 분들을 위해 쓴다. 도움이 되었으면 좋겠다... :D'Android Studio' 카테고리의 다른 글
Android Studio EditText 최소 글자 제한하기(최소 N글자 이상 입력하게끔) (0) 2021.03.28 Android Studio - 주소 찾기 with getSubAdminArea(), getSubLocality() (0) 2021.03.18 Android Studio - 지오코딩, 역지오코딩(feat.GoogleMapAPI) (0) 2021.03.15 Android Studio - Retrofit 이용한 서버와의 통신 (0) 2021.02.28 Android Studio - Google Map API 협업 / Git에 업로드 (0) 2021.02.01