[React + Flask] 간단한 탑스터 웹페이지 (3)

[React + Flask] 간단한 탑스터 웹페이지 (3)

이미지 업로드

SNS 피드처럼 업로드한 이미지들을 볼 수 있도록 했다. 이미지를 서버쪽에 저장하려고 했지만 어디다 저장할지가 고민. 개인적인 공부를 위해 하는 프로젝트라, 아마존s3 같은 스토리지 서비스를 쓰기엔 굳이 라는 느낌이 들었다. 서버의 로컬 디렉토리에 파일을 저장하기로 했다.

@app.route('/api/upload', methods=['POST']) def post_topster(): now = datetime.now() now2 = now.strftime("%D_%H%M_%S") date = now2.replace('/', '-') try: data = request.get_json() userid = request.args.get('user') absolute_path = os.path.abspath(__file__) path = os.path.dirname(absolute_path) path_root = os.path.dirname(path) path_user = path_root + '/images/' + userid if not os.path.exists(path_user): os.makedirs(path_user) dataValue = str(data['topsterimage']) dataBin=dataValue.split(',')[1] imgdata = base64.b64decode(dataBin) filename = path_user + '/' + date +'.png' data = {"userid":userid, "filename":filename, "like":0,"likeuser": [None], "date":now} db.posts.insert_one(data) with open(filename, 'wb') as f: f.write(imgdata) return jsonify({'msg':"upload succeeded"}) except: return jsonify({'msg':"error"})

images/'유저id'/'올린시간'.png 디렉토리에 파일을 저장한다. 폴더가 없으면 생성한 후에 저장한다. 자꾸 데이터가 바이너리 형태로 받아져서 (왠지 모르겠다..) 다시 base64로 인코딩해서 저장한다.

이미지 가져오기

const getPost = async () => { let userid; try { . . . const response = await axios({ method: "GET", url: `http://***:5000/api/feed?user=${userid}&search;=all&offset;=${offset}&limit;=5`, }); const results = response.data.feedData; results.map((result, index) => { . . . ); //더 불러오기 if (results.length === 5) { setOffset((prev) => prev + 5); } else { setOffset(false); } } catch (error) { console.log(error); } };

프론트에서 offset과 limit 값을 쿼리파라미터로 넘겨준다. 값을 성공적으로 받아오면 offset을 limit만큼 키워서 넘겨줌.

#-------피드 가져오기------- @app.route('/api/feed', methods=['GET']) def get_feed(): user = request.args.get('user') search = request.args.get('search', None) offset = request.args.get('offset', None) limit = request.args.get('limit', None) print("user:", user,"search:", search,"offset:", offset, "limit:", limit) if search : if search == "all": #전체 피드 data = list(db.posts.find({}).sort("_id",-1).skip(int(offset)).limit(int(limit))) else: #내가 쓴 피드 data = list(db.posts.find({'userid':search}).sort("_id",-1)) #새거부터 맨 위로 newdata = list() for i in data: #이미지 파일 가져오기 with open(i['filename'], "rb") as f: filedata = f.read() encoded = base64.b64encode(filedata) topsterimage = "data:image/png;base64," + encoded.decode('utf-8') #피드 좋아요 여부 가져오기 likeuser = i['likeuser'] if user in likeuser: likebool = 1 else: likebool = 0 doc = {'userid':i['userid'], 'topsterImage':topsterimage, 'date':i['date'], '_id':str(i["_id"]), "like":i['like'], "likebool":likebool } newdata.append(doc) return jsonify({"feedData":newdata}) return jsonify({'msg':"received"})

모달

내 포스트를 삭제하기 전에 한번 더 물어보는 모달 창을 만들었다.

const openModal = (e) => { this_modal.current.classList.remove("hidden"); const data = e.currentTarget.getAttribute("postid"); setDelPostID(data); }; const closeModal = () => { this_modal.current.classList.add("hidden"); }; . . .

해당 버튼을 누르면 모달창이 보여지고, 보여지는 컴포넌트 안에 로그아웃 함수를 넣어 놨다.

/*모달*/ .modal { border: 1px solid black; position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 100; display: flex; justify-content: center; align-items: center; } .modal_overlay { background-color: rgba(0, 0, 0, 0.6); width: 100%; height: 100%; position: absolute; } .modal_content { background-color: white; position: relative; top: 0px; width: 270px; height: 120px; text-align: center; border-radius: 20px; } .hidden { display: none; }

from http://9yujin.tistory.com/12 by ccl(A) rewrite - 2021-12-28 17:27:03