flask-restx 안드로이드 이미지 업로드

정훈·2022년 8월 21일
0

개발 공부

목록 보기
2/4
post-thumbnail

처음에 플라스크로 이미지 업로드 하는 부분에서는 예제가 많이 나와 있어 큰 문제는 없었다. 하지만 안드로이드 부분에서 multipart/form-data 형식으로 이미지를 보내야 하는데 있어 엄청나게 삽질을 많이 했다. Retrofit2, HttpUrlConnection, Volley 등 엄청나게 많은 예제를 시도 해보았지만 모두가 안드로이드에서 지원을 안하는것인지 우리 팀 코드와 맞지 않은 것인지 모르겠지만 접속이 안되거나 접속이 되도 request부분에 null값이 들어가있는 현상이 나타났다. 혹시나 우리 팀과 같은 시도를 할 사람들을 위해 고생을 하지 않았으면 해서 남긴다. 파이썬과 안드로이드가 http통신을 하며 파일을 주고 받는 예제는 많이 없기 때문에 엄청 고생을 하였다.

플라스크 사용법

간단하게 플라스크와 restx의 설치와 사용방법을 설명하고 시작하겠습니다.

  • 플라스크와 restx 설치 방법

    > pip install flask
    > pip install flask-restx

cmd창을 켜서 위 두 문장을 실행해서 플라스크와 restx를 설치해주시면 됩니다.

  • 간단한 사용방법

# 첫 번째 Flask Server
from flask import Flask  # 서버 구현을 위한 Flask 객체 import
from flask_restx import Api, Resource  # Api 구현을 위한 Api 객체 import

app = Flask(__name__)  # Flask 객체 선언, 파라미터로 어플리케이션 패키지의 이름을 넣어줌.
api = Api(app)  # Flask 객체에 Api 객체 등록


@api.route('/hello')  # 데코레이터 이용, '/hello' 경로에 클래스 등록
class HelloWorld(Resource):
    def get(self):  # GET 요청시 리턴 값에 해당 하는 dict를 JSON 형태로 반환
        return {"hello": "world!"}

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)

이런식으로 flask-restx를 통한 서버를 간단하게 구현을 할 수 있습니다.

서버 이미지 업로드 구현

일단 플라스크를 통해 이미지 업로드를 구현하기 위한 파이썬 코드는 아래와 같다.

from urllib import request
from flask import Flask, request
from flask_restx import Resource, Api
from werkzeug.utils import secure_filename

app = Flask(__name__)
api = Api(app)

@api.route('/upload')
class uploadging(Resource):
    def post(self):
        f = request.files['image']
        f.save(secure_filename(str(f.filename)))
        return {"isUploadSuccess" : "success"}

if __name__ == "__main__":
    app.run(debug=True, host='127.0.0.1', port=80)

위와 같이 파이썬 코드를 쓰면 된다.

<html>
   <body>
      <form action = "http://127.0.0.1:80/upload" method = "POST" 
         enctype = "multipart/form-data">
         <input type = "file" name = "image" />
         <input type = "submit"/>
      </form>
   </body>
</html>

위에는 파이썬 코드가 제대로 작동할 수 있는지 테스트 할 수 있는 html 코드이다.
두 파일을 실행 시켜 보면

파일 선택에서 파일선택 후 제출을 누르면


파이썬 파일이 저장되어 있는 폴더에 사진이 저장되어 있는 것을 확인 할 수 있다.

클라이언트 안드로이드 구현

  • 인터넷 / 저장소 사용 권한과 usesCleartextTraffic 을 True로 하자.

AndoridManifest.xml

<application
      ...
      android:usesCleartextTraffic="true"
      ...>
      <activity android:name=".MainActivity">
         ...
      </activity>
  </application>

  <uses-permission android:name="android.permission.INTERNET" android:required="true"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:required="true"/>

인터넷 / 저장소 사용 권한과 usesCleartextTraffic 을 True로 하자.

FileUploadUtils.java

import android.util.Log;

  import java.io.File;  
  import java.io.IOException;

  import okhttp3.Call;  
  import okhttp3.Callback;  
  import okhttp3.MultipartBody;  
  import okhttp3.OkHttpClient;  
  import okhttp3.Request;  
  import okhttp3.RequestBody;  
  import okhttp3.Response;

  public class FileUploadUtils {  
    public static void send2Server(File file){  
        RequestBody requestBody = new MultipartBody.Builder()  
          .setType(MultipartBody.FORM)  
          .addFormDataPart("files", file.getName(), RequestBody.create(MultipartBody.FORM, file))  
          .build();
        Request request = new Request.Builder()
                .url("http://127.0.0.1:80/upload") // Server URL 은 본인 IP를 입력
                .post(requestBody)
                .build();

        OkHttpClient client = new OkHttpClient();
        client.newCall(request).enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d("TEST : ", response.body().string());
            }
        });
    }
  }

okhttp 기반으로 만들었다. 사진을 보내기 위해서는 multipart/form-data형식으로 보내야 하기때문에 사용했다.

RequestBody requestBody = new MultipartBody.Builder()  
          .setType(MultipartBody.FORM)  
          .addFormDataPart("files", file.getName(), RequestBody.create(MultipartBody.FORM, file))  
          .build();

requestBody부분에서 addFormDataPart()이부분을 여러개 반복한다면 사진을 여러개를 한번에 보내는 것도 가능하다.
아래는 코드는 예시이다.

RequestBody requestBody = new MultipartBody.Builder()  
          .setType(MultipartBody.FORM)  
          .addFormDataPart("files", file.getName(), RequestBody.create(MultipartBody.FORM, file))
          .addFormDataPart("files1", file.getName(), RequestBody.create(MultipartBody.FORM, file))
          .build();

이만 글 작성을 마치겠습니다.
아래 주소는 안드로이드 코드와 파이썬코드를 참고했던 사이트 링크 입니다.

https://derveljunit.tistory.com/302

https://velog.io/@oneofakindscene/Flask%EB%A1%9C-REST-API-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-1.-Flask-RESTX

https://jaeheonit.tistory.com/44

profile
누군가에게 빛이 되길...

0개의 댓글