0. 제일 어려운건 회고록 작성이다.
나의 얕은 지식으론 사전 프로젝트도, 미니 프로젝트도 만만치 않았다. 정말 많은 도움을 받았고 덕분에 무사히 마무리를 할 수 있었다. 멀리 저멀리 던져두었던 javascript도, 다시 봐도 하나도 모르겠는 html도, 처음 프로그램을 짜보는 python도 어렵고 조금은 버거웠다.
하지만 단언컨데 회고록 작성이 나에게 가장 큰 장벽이다.
어떻게 접근해야할지, 무엇을 어떤 식으로 남겨야하는지 사실 이 문장을 쓰고 있는 중에도 알 수가 없다. 다른 분들의 블로그 등을 참고해봐도 어렵다.처음 쓰는 velog는 결과물이 좋지만 친절하진 않은 느낌🥲
그래서 그냥 냅다 갈겨보는 회고록 #이게맞나싶어
1. 미니 프로젝트
"Travle Sparta 여행갈래?"
아주 멋진 팀원들과 함께할 수 있었던 프로젝트였다.
소통은 원활 했고, 서로에 대한 배려도 돋보였다. 취직을 해서 개발자가 된다면 이런 팀 분위기에서 일하고 싶을만큼! 모두가 비전공자였기 때문에 부딪히고 깨지는 순간들이 많았는데, 그 순간을 모두 함께 고민해주던 점이 더 좋았던 것 같다.
뛰어난 능력자가 있는 팀이 아니었기에 우리의 기획은 아주 간단하고 심플하고 배운 것에 기반해있었어야했다. 최대한 제공되는 강의 내에서 해결가능한 범위 내의 프로젝트를 기획하다보니 결국 간단한 이미지형 게시판 형태가 되었다. 크롤링과 댓글 기능을 구현하지 못한 점은 아쉬웠다.
2. JWT
Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token
기존에 Spring boot에서 배웠던 것은 session을 활용한 로그인 기능이었다. 대체로 이해를 하지 못하고 그저 코드를 베껴쓰는 정도였던 것 같다. 그리고 아주 복잡했던 기억이 난다.
그에 비해서 JWT는 서버에 토큰을 저장할 필요없이 클라이언트에서 Json형식으로 주고받을 수 있기 때문에 훨씬 가벼운 느낌이었다.
로그인 유효성 검사를 위한 코드
#토큰을 받아오기 token_receive = request.cookies.get('mytoken') try: #토큰을 생성하기 payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256']) user_info = db.users.find_one({"username": payload["id"]}) return render_template('index.html', nickname=user_info["nickname"], user_info=user_info, boardlist=boardList)
내가 담당했던 상세 페이지의 코드
# 단일객체 렌더링 @app.route('/ObjectView/<num>') def view(num): token_receive = request.cookies.get('mytoken') try: # 쿠키에 있는 유저의 정보를 읽어옴 payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256']) # 읽어온 유저의 id를 통해서 db에서 나머지 정보 찾기 user_info = db.users.find_one({"username": payload["id"]}) # board db에서 해당 num값에 해당하는 dic 찾아오기 post = db.board.find_one({'num': num}, {'_id': False}) # 쿠키에 있는 유저의 아이디와 board에 있는 게시물의 id가 같으면 Ture status = post["nickname"] == user_info['nickname'] # 좋아요 현황 heart = { "count_heart": db.likes.count_documents({"num": num}), "heart_by_me": bool(db.likes.find_one({"num": num, "username": user_info["username"]})) } return render_template('ObjectView.html', user_info=user_info, post=post, num=num, status=status, heart=heart) except jwt.ExpiredSignatureError: return redirect(url_for("login", msg="로그인 시간이 만료되었습니다.")) except jwt.exceptions.DecodeError: return redirect(url_for("login", msg="로그인 정보가 존재하지 않습니다."))
모든 페이지에서 로그인한 유저의 토큰이 필요했다. 특히 상세페이지에서는 상세페이지를 열람하고 있는 사용자가 글의 작성자인지를 확인하는 점, 좋아요의 개수와 여부를 확인할 때도 유용하게 사용했다.
3. API
API는 프로그램들이 서로 상호작용하는 것을 도와주는 매개체
내가 주로 구현했던 기능은 상세페이지, 좋아요 기능이었다. 덧붙여 상세 페이지 내에서 글을 수정하고 삭제하는 기능까지 구현했다. 조회(READ)에 관한 코드가 상술한 내용에 있고, 아래는 수정과 삭제 기능의 코드다.
상세페이지에서 수정페이지로 연결하는 API
# 포스트 수정 @app.route('/update_post/<num>') def update_post(num): token_receive = request.cookies.get('mytoken') try: # 쿠키에 있는 유저의 정보를 읽어옴 payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256']) # 읽어온 유저의 id를 통해서 db에서 나머지 정보 찾기 user_info = db.users.find_one({"username": payload["id"]}) # board db에서 해당 num값에 해당하는 dic 찾아오기 post = db.board.find_one({'num': num}, {'_id': False}) # file에서 num을 빼고 원본 파일명으로 되돌리는 일 filename = post['file'].split('.')[1] extention = post['file'].split('.')[-1] file = f'{filename}.{extention}' status = True return render_template('writeForm.html', user_info=user_info, status=status, post=post, file=file) except jwt.ExpiredSignatureError: return redirect(url_for("login", msg="로그인 시간이 만료되었습니다.")) except jwt.exceptions.DecodeError: return redirect(url_for("login", msg="로그인 정보가 존재하지 않습니다."))
상세페이지에서 해당포스트를 삭제하는 API
# 포스트 삭제 @app.route('/delete_post', methods=['POST']) def delete_word(): num_receive = request.form["num_give"] db.board.delete_one({"num": num_receive}) return jsonify({'result': 'success', 'msg': '삭제 완료!'})
삭제는 훨씬 쉬웠다. 제일 어려웠던건 좋아요 기능 구현이었는데, 사실 서버단에서 구현보다 클라이언트 화면에서의 구현이 제일 어려웠던 것 같다.
가장 어려웠던 클라이언트 화면에서 구동하는 js 코드
function toggle_like(num){ console.log(num) let $a_like = $(`a[aria-label='heart']`) let $i_like = $a_like.find("i") if($i_like.hasClass("fa-solid")){ $.ajax({ type: "POST", url: "/update_like", data: { num_give: num, action_give: "unlike" }, success: function (response) { console.log("unlike") $i_like.addClass('fa-regular').removeClass('fa-solid') $a_like.find("span.like-num").text(response["count"]) } }) }else{ $.ajax({ type: "POST", url: "/update_like", data: { num_give: num, action_give: "like" }, success: function (response) { console.log("like") $i_like.addClass("fa-solid").removeClass("fa-regular") $a_like.find("span.like-num").text(response["count"]) } }) } }
_P.S_
velog도 너무너무 어렵다...^^
알고리즘 어렵다고 아래 더 추가 감상같은거 쓰고 싶었는데
왠지 알 수는 없지만 아주 이상하게 보여지고 있다.
더이상 어떻게 남겨야하는지 알 수 없어 이번 주는 여기까지!ㅠㅠ