본문 바로가기

스파르타코딩클럽/웹개발 종합반

스파르타 코딩클럽 웹개발 5주차

[수업 목표]

  1. Flask 프레임워크를 활용해서 API를 만들 수 있다.
  2. '버킷리스트'를 완성한다.
  3. EC2에 내 프로젝트를 올리고, 자랑한다!

01. 버킷리스트 프로젝트 세팅

1) 문제 분석 - 완성작부터 보기 :  [ http://spartacodingclub.shopweb/bucket  ]

2) 프로젝트 설정 - flask 폴더 구조 만들기 : static, templates 폴더 + app.py

3) 패키지 설치하기 : flask, pymongo, dnspython

 

01 - 1. 뼈대 준비하기

app. py

더보기
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

@app.route('/')
def home():
   return render_template('index.html')

@app.route("/bucket", methods=["POST"])
def bucket_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST(기록) 연결 완료!'})

@app.route("/bucket/done", methods=["POST"])
def bucket_done():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST(완료) 연결 완료!'})

@app.route("/bucket", methods=["GET"])
def bucket_get():
    return jsonify({'msg': 'GET 연결 완료!'})

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

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap" rel="stylesheet">

    <title>인생 버킷리스트</title>

    <style>
        * {
            font-family: 'Gowun Dodum', sans-serif;
        }
        .mypic {
            width: 100%;
            height: 200px;

            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://images.unsplash.com/photo-1601024445121-e5b82f020549?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1189&q=80');
            background-position: center;
            background-size: cover;

            color: white;

            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }
        .mypic > h1 {
            font-size: 30px;
        }
        .mybox {
            width: 95%;
            max-width: 700px;
            padding: 20px;
            box-shadow: 0px 0px 10px 0px lightblue;
            margin: 20px auto;
        }
        .mybucket {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: space-between;
        }

        .mybucket > input {
            width: 70%;
        }
        .mybox > li {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;

            margin-bottom: 10px;
            min-height: 48px;
        }
        .mybox > li > h2 {
            max-width: 75%;
            font-size: 20px;
            font-weight: 500;
            margin-right: auto;
            margin-bottom: 0px;
        }
        .mybox > li > h2.done {
            text-decoration:line-through
        }
    </style>
    <script>
        $(document).ready(function () {
            show_bucket();
        });
        function show_bucket(){
            $.ajax({
                type: "GET",
                url: "/bucket",
                data: {},
                success: function (response) {
                    alert(response["msg"])
                }
            });
        }
        function save_bucket(){
            $.ajax({
                type: "POST",
                url: "/bucket",
                data: {sameple_give:'데이터전송'},
                success: function (response) {
                    alert(response["msg"])
                }
            });
        }
        function done_bucket(num){
            $.ajax({
                type: "POST",
                url: "/bucket/done",
                data: {sameple_give:'데이터전송'},
                success: function (response) {
                    alert(response["msg"])
                }
            });
        }
    </script>
</head>
<body>
    <div class="mypic">
        <h1>나의 버킷리스트</h1>
    </div>
    <div class="mybox">
        <div class="mybucket">
            <input id="bucket" class="form-control" type="text" placeholder="이루고 싶은 것을 입력하세요">
            <button onclick="save_bucket()" type="button" class="btn btn-outline-primary">기록하기</button>
        </div>
    </div>
    <div class="mybox" id="bucket-list">
        <li>
            <h2>✅ 호주에서 스카이다이빙 하기</h2>
            <button onclick="done_bucket(5)" type="button" class="btn btn-outline-primary">완료!</button>
        </li>
        <li>
            <h2 class="done">✅ 호주에서 스카이다이빙 하기</h2>
        </li>
        <li>
            <h2>✅ 호주에서 스카이다이빙 하기</h2>
            <button type="button" class="btn btn-outline-primary">완료!</button>
        </li>
    </div>
</body>
</html>

 

mongoDB Atlas 띄우기

 

01 - 2. POST연습(기록하기)

API 만들고 사용하기 - 버킷리스트 기록 API (Create→ POST)

  1. 요청 정보 : URL= /bucket, 요청 방식 = POST
  2. 클라(ajax) → 서버(flask) : bucket
  3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (기록 완료!)

단! 서버에서 한 가지 일을 더 해야합니다. → 번호를 만들어 함께 넣어주는 것. 그래야 업데이트가 가능하겠죠!

 

1) 클라이언트와 서버 연결 확인하기

서버 코드 - app.py

@app.route("/bucket", methods=["POST"])
def bucket_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST(기록) 연결 완료!'})

클라이언트 코드 - index.html

function save_bucket(){
    $.ajax({
        type: "POST",
        url: "/bucket",
        data: {sample_give:'데이터전송'},
        success: function (response) {
            alert(response["msg"])
        }
    });
}

<button onclick="save_bucket()" type="button" class="btn btn-outline-primary">기록하기</button>

2) 서버 만들기

  • bucket 정보를 받아서, 저장하면 되겠죠?
  • 단, 한 가지 일이 더 있답니다. → 네, 버킷 번호완료여부 를 함께 넣어주는 것!
  • 우리가 일전에 만들어둔 [dbtest.py]파일도 불러와봅시다!
  • 재밌는 사실! 아래 코드도 살펴봅시다.
count = list(db.bucket.find({},{'_id':False}))
num = len(count) + 1

vs

count = db.bucket.find({},{'_id':False}).count()
num = count + 1
@app.route("/bucket", methods=["POST"])
def bucket_post():
    bucket_receive = request.form["bucket_give"]

    count = db.bucket.find({},{'_id':False}).count()
    num = count + 1

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

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

3) 클라이언트 만들기

쉬워요! bucket 정보만 보내주면 되겠죠?

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()
        }
    });
}

4) 완성 확인하기

DB에 잘 들어갔는지 확인

 

01 - 3. GET연습하기(보여주기)

API 만들고 사용하기 - 버킷리스트 조회 API (Read→ GET

  1. 요청 정보 : URL= /bucket, 요청 방식 = GET
  2. 클라(ajax) → 서버(flask) : (없음)
  3. 서버(flask) → 클라(ajax) : 전체 버킷리스트를 보여주기

1) 클라이언트와 서버 연결 확인하기

[서버 코드 - app.py]

@app.route("/bucket", methods=["GET"])
def bucket_get():
    return jsonify({'msg': 'GET 연결 완료!'})

[클라이언트 코드 - index.html]

$(document).ready(function () {
    show_bucket();
});
function show_bucket(){
    $.ajax({
        type: "GET",
        url: "/bucket",
        data: {},
        success: function (response) {
            alert(response["msg"])
        }
    });
}

2) 서버 만들기

  • 받을 것 없이 buckets에 주문정보를 담아서 내려주기만 하면 됩니다!
@app.route("/bucket", methods=["GET"])
def bucket_get():
    buckets_list = list(db.bucket.find({},{'_id':False}))
    return jsonify({'buckets':buckets_list})

3) 클라이언트 만들기

  • 응답을 잘 받아서 for 문으로! 붙여주면 끝이겠죠!
function show_bucket(){
    $('#bucket-list').empty()
    $.ajax({
        type: "GET",
        url: "/bucket",
        data: {},
        success: function (response) {
            let rows = response['buckets']
            for (let i = 0; i < rows.length; i++) {
                let bucket = rows[i]['bucket']
                let num = rows[i]['num']
                let done = rows[i]['done']

                let temp_html = ``
                if (done == 0) {
                    temp_html = `<li>
                                    <h2>✅ ${bucket}</h2>
                                    <button onclick="done_bucket(${num})" type="button" class="btn btn-outline-primary">완료!</button>
                                </li>`
                } else {
                    temp_html = `<li>
                                    <h2 class="done">✅ ${bucket}</h2>
                                </li>`
                }
                $('#bucket-list').append(temp_html)
            }
        }
    });
}

4) 완성 확인하기

 

01 - 4. POST연습하기(완료하기)

API 만들고 사용하기 - 버킷리스트 완료 API (Update→ POST)

  1. 요청 정보 : URL= /bucket/done, 요청 방식 = POST
  2. 클라(ajax) → 서버(flask) : num (버킷 넘버)
  3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (버킷 완료!)

1) 클라이언트와 서버 연결 확인하기

[서버 코드 - app.py]

@app.route("/bucket/done", methods=["POST"])
def bucket_done():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST(완료) 연결 완료!'})

[클라이언트 코드 - index.html]

function done_bucket(num){
    $.ajax({
        type: "POST",
        url: "/bucket/done",
        data: {sameple_give:'데이터전송'},
        success: function (response) {
            alert(response["msg"])
        }
    });
}

<button onclick="done_bucket(5)" type="button" class="btn btn-outline-primary">완료!</button>

2) 서버 만들기

  • 버킷 번호를 받아서, 업데이트 하면 됩니다!
  • 그.런.데! num_receive 는 문자열로 들어오니까, 숫자로 바꿔주는 것이 중요합니다!

@app.route("/bucket/done", methods=["POST"])
def bucket_done():
    num_receive = request.form["num_give"]
    db.bucket.update_one({'num': int(num_receive)}, {'$set': {'done': 1}})
    return jsonify({'msg': '버킷 완료!'})

3) 클라이언트 만들기

  • 버킷 넘버를 보여주면 됩니다! 버킷 넘버는? HTML이 만들어질 때 적히게 되죠!

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

4) 완성 확인하기

 


02. 내 프로젝트를 서버에 올리기

"웹서비스 런칭" 에 필요한 개념 소개

  • 웹 서비스를 런칭하기 위해 클라이언트의 요청에 항상 응답해줄 수 있는 서버에 프로젝트를 실행시켜줄 거에요.
  • 언제나 요청에 응답하려면,
  1. 컴퓨터가 항상 켜져있고 프로그램이 실행되어 있어야하고,
  2. 모두가 접근할 수 있는 공개 주소인 공개 IP 주소(Public IP Address)로 나의 웹 서비스에 접근할 수 있도록 해야해요.
  • 서버는 그냥 컴퓨터라는거 기억나시죠? 외부 접속이 가능하게 설정한 다음에 내 컴퓨터를 서버로 사용할 수도 있어요.
  • 우리는 AWS 라는 클라우드 서비스에서 편하게 서버를 관리하기 위해서 항상 켜 놓을 수 있는 컴퓨터인 EC2 사용권을 구입해 서버로 사용할 겁니다.
  •  

AWS E2C 서버 사기 : https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2 

 

https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2

 

ap-northeast-2.console.aws.amazon.com

AWS EC2에 접속하기

  • Window: ssh가 없으므로, git bash라는 프로그램을 이용!
  • gitbash를 실행하고, 아래를 입력!
ssh -i 받은키페어를끌어다놓기 ubuntu@AWS에적힌내아이피
  • 예) 아래와 비슷한 생김새!
ssh -i /path/my-key-pair.pem ubuntu@13.125.250.20
  • Key fingerprint 관련 메시지가 나올 경우 Yes를 입력해주세요!
  • git bash를 종료할 때는 exit 명령어를 입력하여 ssh 접속을 먼저 끊어주세요.

간단한 리눅스 명령어

더보기
  • 팁! 리눅스 커널에서 윗화살표를 누르면 바로 전에 썼던 명령어가 나옵니다.
ls: 내 위치의 모든 파일을 보여준다.

pwd: 내 위치(폴더의 경로)를 알려준다.

mkdir: 내 위치 아래에 폴더를 하나 만든다.

cd [갈 곳]: 나를 [갈 곳] 폴더로 이동시킨다.

cd .. : 나를 상위 폴더로 이동시킨다.

cp -r [복사할 것] [붙여넣기 할 것]: 복사 붙여넣기

rm -rf [지울 것]: 지우기

sudo [실행 할 명령어]: 명령어를 관리자 권한으로 실행한다.
sudo su: 관리가 권한으로 들어간다. (나올때는 exit으로 나옴)

 

02 - 1. 서버 세팅하기

서버 환경 통일하기 : 우리는 지금 막! 컴퓨터를 구매한 상태예요.

여기에 이런저런 세팅들(업그레이드, DB설치, 명령어 통일 등)을 해줘야 본격적으로 이용할 때 편리하답니다!

  • EC2 한방에 세팅하기
# python3 -> python
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10

# pip3 -> pip
sudo apt-get update
sudo apt-get install -y python3-pip
sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1

# port forwarding
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000

filezilla를 이용해서, 간단한 python 파일을 올려봅니다.

  • 서버에 업로드 할 간단한 파일을 작성합니다.
  • 파일질라 실행, 다음과 같이 설정

  • 정보들을 입력하고, ok 누르면 서버의 파일들을 볼 수 있음 (Host: 내 EC2서버의 ip // User: ubuntu 로 입력)

  • 마우스로 드래그 해서 파일을 업로드/다운로드하면 됩니다!
  • 왼쪽이 내 컴퓨터 vs 오른쪽이 내가 방금 산 컴퓨터

  • 파이썬 파일을 실행해보기
python test.py

[한 걸음 더] 서버 환경 세팅 - 한 줄씩 설명

1. 파이썬 (python3 → python)

  • python3 명령어를 python으로 사용할 수 있게 하는 명령어

2. pip (pip3 → pip)

한 줄 씩 복사 붙여넣기!

  • 1) pip3 설치
  • 2) pip3 명령어를 pip으로 사용할 수 있게 하는 명령어
  • * 한 줄 씩 복사 붙여넣기!
# pip3 설치
sudo apt-get update
sudo apt-get install -y python3-pip

# pip3 대신 pip 라고 입력하기 위한 명령어
sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1

3. 포트포워딩 (80포트 → 5000포트)

80포트로 들어오는 요청을 5000포트로 넘겨주는 명령어

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000

 

02 - 2. Flask 서버를 실행해보기

1) 팬명록 완성본을 파일질라로 EC2에 업로드

  • 파일질라에서 homework 폴더 째로 드래그 드롭으로 EC2 인스턴스의 home/ubuntu 폴더에 업로드합니다.

2) pip로 패키지 설치

pip install flask pymongo dnspython

3) 브라우저로 접속해보기

크롬 브라우저 창에 아래와 같이 입력합니다.

http://[내 EC2 IP]:5000/

아직 작동하지 않는다

 

4) AWS에서 5000포트를 열어주기

  • EC2 서버(=가상의 내 컴퓨터)에서 포트를 따로 설정하는 것 외에도, AWS EC2에서도 자체적으로 포트를 열고/닫을 수 있게 관리를 하고 있습니다.
  • → 그래서 AWS EC2 Security Group에서 인바운드 요청 포트를 열어줘야 합니다.
  • 일단, EC2 관리 콘솔로 들어갑니다. 그리고 보안그룹(영문: Security Group)을 눌러 들어갑니다. 여기선 launch-wizard-1 이라고 쓰여 있네요

  • 해당 보안그룹을 클릭합니다.

  • Edit inbound rules를 선택합니다

  • 두 가지 포트를 추가해봅니다. Anywhere-IPv4 를 클릭해주세요!→ 5000포트: flask 기본포트

→ 80포트: HTTP 접속을 위한 기본포트

→ 5000포트: flask 기본포트

어떻게 되는걸까? 포트 번호 없애기 - 기본 개념

  • 지금은 5000포트에서 웹 서비스가 실행되고 있습니다. 그래서 매번 :5000 이라고 뒤에 붙여줘야 하죠. 뒤에 붙는 포트 번호를 없애려면 어떻게 해야할까요?
  • http 요청에서는 80포트가 기본이기 때문에, 굳이 :80을 붙이지 않아도 자동으로 연결이 됩니다.
  • 포트 번호를 입력하지 않아도 자동으로 접속되기 위해, 우리는 80포트로 오는 요청을 5000 포트로 전달하게 하는 포트포워딩(port forwarding) 을 사용하겠습니다.
  • 리눅스에서 기본으로 제공해주는 포트포워딩을 사용할 것입니다. 그림으로 보면 아래와 같습니다.

다시 접속해보자 : http://내아이피 

 

02 - 3. nohup 설정하기

SSH 접속을 끊어도 서버가 계속 돌게 하기

# 아래의 명령어로 실행하면 된다
nohup python app.py &

서버 종료하기 - 강제종료하는 방법

ps -ef | grep 'python app.py' | awk '{print $2}' | xargs kill

 

02 - 4. 도메인 연결하기

  • 도메인 구입/연결
    • 도메인을 구매한다는 것은, 네임서버를 운영해주는 업체에, IP와 도메인 매칭 유지비를 내는 것입니다. 한국 또는 글로벌 업체 어디든 상관 없지만, 우리는 한국의 '가비아'라는 회사에서 구입해보겠습니다.
  • 가비아 접속하기
  • 링크: https://dns.gabia.com/
 

웹을 넘어 클라우드로. 가비아

 

dns.gabia.com

 

(DNS 설정 클릭)

(호스트 이름에 @, IP주소에 IP주소를 입력합니다)

(이렇게!)

내 IP주소로 지금 flask 서버가 잘 돌고 있나요? 먼저 확인해봅니다. : <http://내AWS아이피/>

약간의 시간을 가진 후, 내 도메인으로 접근하면, 접속이 됩니다. : <http://내도메인/>

 


3. og태그

og 태그 만들기

  • 스파르타피디아에서 배웠던 og:image, og:title, og:description 태그 기억하시나요?
  • 내 프로젝트도 카톡/페이스북/슬랙에 공유했을 때 예쁘게 나오도록, 미리 꾸며봅시다!

  • static 폴더 아래에 이미지 파일을 넣고, 각자 프로젝트 HTML의 <head>~</head> 사이에 아래 내용을 작성하면 og 태그를 개인 프로젝트에 사용할 수 있습니다.

og태그 넣기

<meta property="og:title" content="내 사이트의 제목" />
<meta property="og:description" content="보고 있는 페이지의 내용 요약" />
<meta property="og:image" content="이미지URL" />


5주차 숙제 : 내 도메인 제출하기

http://waveswaves.shop/

 

성시경 팬명록

응원 한마디 남기고 가세요!

waveswaves.shop