※ 기획서 - https://www.notion.so/2-1-Mini-Project-eb4f6367a5e74ccf891f2bf336e21112

① 주제 : 카타르 월드컵 일정/응원 ⚽

② 구현해야하는 기능

③ CSS

  1. head 폰트 :
  1. 세부 폰트 : https://fonts.google.com/specimen/Do+Hyeon?subset=korean
  2. bootswatch https://bootswatch.com/united/ (dark 버건디 색상 , secondary 그레이 색상 참고)
  3. 버건디 색상 번호 : #772953

④  page url

  • login.html
  • signup.html
  • main.html
  • main/name_of_match
  • review.html

 

1. 와이어 프레임 

<< 플로우 차트 >>
1. 로그인 페이지
2. 회원가입 페이지
3. 메인 페이지
4. 응원댓글 페이지 하단
5. 응원댓글 페이지 하단

 

2. 미니 프로젝트 화면단 

 

1. 로그인 페이지
2. 회원가입
3. 메인페이지
4. 댓글 페이지 (상단)
5. 댓글 페이지 (하단)

 

 

항해 99 입학시험이 코앞으로 다가왔다. 바로 내일 ! 10시부터 17시 !!! 

매니저님들이 시험이 쉽다고 걱정하지 말라고 하시면서 예제 링크를 하나 보여주셨다. 

네? 쉽다고요 ....? 전 왜 어렵죠 ....? ㅎ

 

구현되어있는 페이지 소스코드에서 힌트를 얻어 어찌저찌 구현을 하긴 했다.

페이지 html 소스코드 덕분에 구현한거라 내일 새로운 문제를 풀고 구현을 해야 한다면 과연 할 수 있을지 모르겠다.

뭐... 7시간인데 구글링하면 어떻게든 하겠지 !!!


 

 

 

[ 구현해야 하는 부분 ]

 

1. 취소버튼 만들기

2. 취소 누르면 다시 완료버튼이 되도록 하기

 

어쨌든 성공 ! :)

 

1.  BE 부분

 

 

 

2.  FE 부분

 

 

오늘은 11월 9일에 있을 사전 입학시험에 대비하여 웹종합반 강의를 복습해 보았다.

오랜만에 봤더니 여전히 헷갈리는 부분이 있어서 복습하는 동안 헷갈렸던 부분의 코드를 정리해 보았다.

시간이 여유가 있다면 간단한 웹페이지를 하나 만들어 보면 좋을텐데 아쉬움이 남는다.

사전시험 제발 아무런 이슈없이 통과하기를 ! :)

 


 

1. 로그인 박스 배경 이미지 설정 기본값

background-image: url("https://www.ancient-origins.net/sites/default/files/field/image/Agesilaus-II-cover.jpg");
background-position: center;
background-size: cover;

 

2. 화면 중앙으로 로그인 박스 옮기기

//<style> 태그 부분 -> 일단 가로사이즈를 주고, margin값으로 중간으로 옮기기.

.wrap{
            width:300px;
            margin: auto;
        }
        
//<body> 태그 부분 -> 옮기고자 하는 부분 class="wrap"으로 전체 묶어주기.

 <div class="wrap">
        <div class="login_box">
            <h1>로그인 페이지</h1>
            <h5>아이디, 비밀번호를 입력해주세요</h5>
        </div>
        <div>
            <p>ID: <input type="text"/></p>
            <p>PW: <input type="text"/></p>
            <button>로그인하기</button>
        </div>
</div>

 

3. style.css 파일을 같은 폴더에 만들고, head 태그에서 불러오기. <head>태그 안에 아래 코드를 넣어주면 된다.

<link rel="stylesheet" type="text/css" href = "(css파일이름).css">

 

4. 스파르타피디아 헤드부분 제목과 버튼 정렬 코드 (박스 내 중앙으로 옮겨주는)

display: flex;
flex-direction: column;
justify-content: center;
align-items: center;

 

5. jQuery 임포트 코드. <head> 태그 안에 아래 코드를 넣어주면 된다.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

 

6. ajax 기본골격

 $.ajax({
	type: "GET",
	url: "여기에URL을입력",
	data: {},
	success: function(response){
	console.log(response)
	}
})

 

7. 로딩 후 바로 호출하기

$(document).ready(function(){
	alert('다 로딩됐다!')
});

 

8. 스파르타피디아 별점 가져오는 법 .repeat() 사용하기

let star_image = '⭐'.repeat(star)

 

9. 크롤링 부분

import requests
from bs4 import BeautifulSoup

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=pnt&date=20210829',headers=headers)

soup = BeautifulSoup(data.text, 'html.parser')

//#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
//#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img
//#old_content > table > tbody > tr:nth-child(2) > td.point


movies = soup.select('#old_content > table > tbody > tr')

for movie in movies:
    title = movie.select_one('td.title > div > a')
    if title is not None:
        title = title.text
        rank = movie.select_one('td:nth-child(1) > img')['alt']
        star = movie.select_one('td.point').text
        print(rank, title, star)

 

10. db 관련 코드 (필요에 따라 복붙하기)

from pymongo import MongoClient
import certifi

ca = certifi.where()
client = MongoClient('mongodb+srv://test:비밀번호@cluster0.몽고db개인주소.mongodb.net/?retryWrites=true&w=majority',tlsCAFile=ca)
db = client.dbsparta

# 저장 - 예시
doc = {'name':'bobby','age':21}
db.users.insert_one(doc)

# 한 개 찾기 - 예시
user = db.users.find_one({'name':'bobby'})

# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
all_users = list(db.users.find({},{'_id':False}))

# 바꾸기 - 예시
db.users.update_one({'name':'bobby'},{'$set':{'age':19}})

# 지우기 - 예시
db.users.delete_one({'name':'bobby'})

 

11. 화성땅공동구매 POST BE 코드

@app.route("/mars", methods=["POST"])
def mars_post():
    name_receive = request.form['name_give']
    address_receive = request.form['address_give']
    size_receive = request.form['size_give']

    doc = {
        'name': name_receive,
        'address': address_receive,
        'size': size_receive
    }

    db.orders.insert_one(doc)

    return jsonify({'msg': '주문 완료!'})

 

12. 화성땅공동구매 POST FE 코드

function save_order() {
    let name = $('#name').val()
    let address = $('#address').val()
    let size = $('#size').val()

    $.ajax({
        type: 'POST',
        url: '/mars',
        data: { name_give:name, address_give:address, size_give:size },
        success: function (response) {
            alert(response['msg'])
            window.location.reload()
        }
    });
}

 

 

13. 화성땅공동구매 GET BE 코드

@app.route("/mars", methods=["GET"])
def mars_get():
    orders_list = list(db.orders.find({},{'_id':False}))
    return jsonify({'orders':orders_list})

 

14. 화성땅공동구매 GET FE 코드

function show_order() {
    $('#order-box').empty()
    $.ajax({
        type: 'GET',
        url: '/mars',
        data: {},
        success: function (response) {
            let rows = response['orders']
            for (let i = 0; i < rows.length; i++) {
                let name = rows[i]['name']
                let address = rows[i]['address']
                let size = rows[i]['size']

                let temp_html = `<tr>
                                    <td>${name}</td>
                                    <td>${address}</td>
                                    <td>${size}</td>
                                  </tr>`
                $('#order-box').append(temp_html)
            }

        }
    });
}

 

5. 크롤링 조각기능 - meta tag

//select_one을 이용해 meta tag를 먼저 가져와봅니다
og_image = soup.select_one('meta[property="og:image"]')
og_title = soup.select_one('meta[property="og:title"]')
og_description = soup.select_one('meta[property="og:description"]')

print(og_image)
print(og_title)
print(og_description)

//가져온 meta tag의 content를 가져와봅시다.
image = og_image['content']
title = og_title['content']
description = og_description['content']

print(image)
print(title)
print(description)

 

16. 버킷리스트 BE POST 

@app.route("/bucket", methods=["POST"])
def bucket_post():
    bucket_receive = request.form["bucket_give"]

    count = list(db.bucket.find({},{'_id':False})) //->이부분을 유의한다 ! 넘버 만든느 법!
    num = len(count) + 1

    doc = {
        'num':num,
        'bucket': bucket_receive,
        'done':0
    }

    db.bucket.insert_one(doc)
    return jsonify({'msg':'등록 완료!'})

 

17. 버킷리스트 FE POST

function save_bucket(){
    let bucket = $('#bucket').val()
    $.ajax({
        type: "POST",
        url: "/bucket",
        data: {bucket_give:bucket},
        success: function (response) {
            alert(response["msg"])
            window.location.reload()
        }
    });
}

 18. 버킷리스트 done BE POST

@app.route("/bucket/done", methods=["POST"])
def bucket_done():
    num_receive = request.form["num_give"] //num으로 받는 점 유의, int로 데이터타입 변환 유의
    db.bucket.update_one({'num': int(num_receive)}, {'$set': {'done': 1}})
    return jsonify({'msg': '버킷 완료!'})

 

19. 버킷리스트 done FE POST

function done_bucket(num){
    $.ajax({
        type: "POST",
        url: "/bucket/done",
        data: {'num_give':num},
        success: function (response) {
            alert(response["msg"])
            window.location.reload()
        }
    });
}

웹개발 종합반 2회독을 끝낸 후 일주일 동안 항해99 사전토이프로젝트를 진행하였다. 각자 페이지를 맡아서 진행하였는데, 어쩌다 보니 내가 맡은 부분이 가장 쉬운 페이지가 되었던 것 같다. 기술적인 측면에서 JWT토큰을 이용한 로그인 페이지, 그리고 회원가입 페이지가 가장 어려웠던 부분이었는데 이 부분은 소영님과 민승님이 맡아주셔서 다른 페이지 작업들은 비교적 수월하게 되었던 것 같다 :) 


토이프로젝트 주제 : 추천하고 싶은 프로그래밍 유튜브 영상을 포스팅하고 공유하는 사이트

 

팀원 : 김현빈(랜딩페이지), 조소영(로그인페이지), 강민승(회원가입페이지), 차이진(메인페이지), 황미경(세부페이지)

 

구현 기능 :

  • JWT를 이용한 로그인/회원가입
  • 카테고리별 영상 업로드
  • 게시물 코멘트/추천도 기록
  • URL을 이용한 크롤링

 

기술 스택 :

  • HTML
  • CSS
  • JavaScript
  • Python
  • Flask
  • JWT
  • mongoDB
  • Bootstrap5.0
  • swiper.js
  • 크롤링

 

깃허브 주소 : https://github.com/1016website/1016website
토이프로젝트 주소 : http://leejincha.shop/

 


 

 

↓↓↓↓↓ 토이프로젝트 스트린샷 ↓↓↓↓↓

랜딩 페이지

 

로그인 페이지
회원가입 페이지
메인 페이지
세부 페이지 (포스팅 박스 닫힌 모습)
세부페이지 (포스팅 박스 열린 모습)

 

 


 

 

※ 후기 :  

 

1. 먼저 좋은 팀원분들을 만나 항해99 시작 전 같이 한 달여간의 시간을 게더에서 공부하고 미숙하지만 프로젝트까지 진행할 수 있어서 너무 감사한 시간이었다. 혼자였으면 막막했을 코딩의 첫걸음을 팀원분들 덕분에 그래도 그나마 수월하게 하나하나 할 수 있었던 것 같고, 궁금한 게 있거나 오류가 발생할 때마다 같이 고민하고 해결해 주셔서 너무 감사한 시간이었다. 나도 훗날 나에게 도움이 필요한 팀원이 있다면, 16조 팀원분들처럼 친절히 그리고 차근차근 알려 줄 수 있는 사람이 되고 싶다는 생각을 했다.

 

2. 우리 팀은 다행히도 너무나 커뮤니케이션이 잘 되어서 소통과 협업에 문제는 전혀 없었고, 기술 구현도 웹개발종합반을 기준으로 했기 때문에 JWT를 제외하고는 크게 어려운 부분이 없었다. 다만 의외로 힘들었던 부분은 Github 사용이었다. 

모두가 처음 깃허브를 이용하는 거라 사용법이 미숙하기도 했고, 생각보다 다양한 오류를 맞이해서 그때마다 구글링으로 명령어를 찾아보고 해결해야 했다. 아직 터미널 명령어도 생소하고 깃허브 명령어도 생소하기 때문에 시행착오가 많았는데, 결론적으로 가장 기억에 남는 부분은! 무조건! Pull 하기 전에 백업을 해놓자! 것이다. ㅎㅎㅎ

 

3. 실력으로 보자면, 난 한참 다른 분들보다 부족한 부분이 많다. 하지만, 지금은 실력에 집중해 좌절할 것이 아니라 오늘과 내일 성장에 더 집중해야 하는 때라고 생각한다. 개발자들이라면 누구나 겪는다는 가면 증후군(Imposter Syndrome)을 나도 겪을 날이 올 것이다. 그 시기에도 지금처럼 당장의 남과 비교되는 실력보다 성장하는 나의 모습에 집중해서 발전하는 개발자가 되어야겠다고 생각했다.

 

그리고 또 한 가지, 협업을 했을 때 working well 할 수 있는 사람이 되도록 노력해야겠다. 원활한 커뮤니케이션뿐만 아니라, 기술적으로도 팀에게 도움이 되는 사람이 되도록 하자! 

 

진짜 진짜 마지막으로!! 16조 팀원분들 너무 감사했습니다. 벌써 아쉬운 마음이 큰데, 앞으로 싫으시더라도 ^_^헿 계속 연락드리면서 귀찮게 굴겠습니다 헿 ㅎㅎ !! 모두 수료 끝까지 화잇팅합시다 !

 

더이상 미룰 수 없다 ! 이해하고 싶다 ! JWT 토큰을 이용한 로그인페이지 ! 나도 제발 이해하고 싶다 !! 

그래서 토이프로젝트 팀원 분의 코드를 뜯어보며 조금이라도 이해해 보려 한다. (직접 코드작성은 못함 ^_ㅠ)

 


1. 필요한 라이브러리 import 하기.

 

 

 

2. 로그인 

 

프론트엔드
백엔드

 

  • 로그인을 위해 인풋박스에 이메일과 패스워드 id를 지정하고 let data로 변수를 지정한다.
  • 그리고 ajax를 통해 제이슨 형식으로 로그인정보를 저장해 서버로 보내준다.
  • 서버에서 이메일정보와 패스워드 정보를 받아 확인하고 if 함수를 통해 이메일이 존재하지 않으면 오류 메시지를 리턴한다.
  • 이메일 정보가 맞다면 비밀번호가 일치하는지 확인하고, 비밀번호가 맞지 않으면 오류 메시지를 클라이언트쪽으로 리턴해 준다.
  • 그리고 모두 오류가 없다면 토큰을 생성한다.
  • 그 후 로그인 성공 메시지를 토큰을 담은 쿠키와 함께 리턴한다.
  • 마지막으로 서버가 요청을 제대로 처리했다는 의미로 200을 리턴해 준다.

 

 

3. 로그아웃 

 

프론트엔드
백엔드

 

  • 로그아웃 버튼이 click이 되면 이 정보를 get함수로 서버단에 전달한다.
  • 서버단에서 로그아웃 성공 메시지를 화면에 띄워주도록 하고 동시에 쿠키를 없애준다.
  • 화면단에서 화면을 새로고침하여 다시 보여준다.

 

 

4. 유효성 검사

 

프론트엔드
백엔드

 

  • 유효성 검사 사용할때는 서버단에 @jwt_required()가 있으면 된다.
  • 이메일정보와 패스워드 정보가 일치한다면, 로그인 박스를 숨겨준다.
  • 일치하지 않는다면 로그인박스를 보여준다.
  • 서버단에서는 로그인정보를 확인하여 토큰에 저장된 데이터가 일치하지 않으면 result값이 fail임을 리턴해 준다.
  • 만약에 로그인 정보가 일치한다면 토큰에 저장된 데이터를 불러온다.

 

  

5. 갱신

 

백엔드

  •  jwt 토큰은 만료를 정해주지 않으면 그대로 남기 때문에 만료와 갱신에 신경써야한다. 
  • Access_token 의 기간이 만료되면 Refresh_token을 가지고 Access_token을 재발급 받아야 한다.
  • 그래서 토큰 시간이 만료되기 전에 프런트에서 refresh 요청을 보낸다.

 

더보기

flask-bcrypt 를 임포트 하는 과정에서 파이썬 버젼이 맞지 않아 계속해서 오류가 떴다.

터미널창을 이용하여 python3 버전을 업그레이드 해주었더니 오류를 해결 할 수 있었다.

 

파이썬3 업그레이드 명령어 : pip3 install --upgrade pip

 

 

 


[출처] : https://littlezero48.tistory.com/69  (우리팀에 소영님 없으면 어쩔뻔 했나요 ..♥ 감사합니다)

 

이렇게 정리를 했는데도 이해 못하는 나. ^^ 언젠가 이해하는 날이 오겠지 ... 후

내일은 민승님이 구현하신 회원가입 코드를 뜯어봐야 겠다. 괜찮아 ... 언젠가 이해할거야 ... 괜찮아 .... ㅜ

+ Recent posts