처음에 플라스크로 이미지 업로드 하는 부분에서는 예제가 많이 나와 있어 큰 문제는 없었다. 하지만 안드로이드 부분에서 multipart/form-data 형식으로 이미지를 보내야 하는데 있어 엄청나게 삽질을 많이 했다. Retrofit2, HttpUrlConnection, Volley 등 엄청나게 많은 예제를 시도 해보았지만 모두가 안드로이드에서 지원을 안하는것인지 우리 팀 코드와 맞지 않은 것인지 모르겠지만 접속이 안되거나 접속이 되도 request부분에 null값이 들어가있는 현상이 나타났다. 혹시나 우리 팀과 같은 시도를 할 사람들을 위해 고생을 하지 않았으면 해서 남긴다. 파이썬과 안드로이드가 http통신을 하며 파일을 주고 받는 예제는 많이 없기 때문에 엄청 고생을 하였다.
> 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 코드이다.
두 파일을 실행 시켜 보면
파일 선택에서 파일선택 후 제출을 누르면
파이썬 파일이 저장되어 있는 폴더에 사진이 저장되어 있는 것을 확인 할 수 있다.
<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로 하자.
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();
이만 글 작성을 마치겠습니다.
아래 주소는 안드로이드 코드와 파이썬코드를 참고했던 사이트 링크 입니다.