본문 바로가기
항해99

웹개발 종합반_5주차

by Hyeon_E 2023. 4. 16.

[ AWS 가입하기 및 보안설정하기 ]

AWS 사이트: https://504836820716.signin.aws.amazon.com/console

 

https://console.aws.amazon.com/console/home

 

console.aws.amazon.com

▶ IAM

아이디를 생성하면 IAM계정을 사용

IAM은 AWS의 서비스를 안전하게 제어할 수 있는 계정 내의 계정

  • AWS 계정을 처음 가입할 때는 루트 계정이라는 하나의 아이디로 생성되는데 이것을 바로 사용하면 굉장히 위험함
    • 이유는 바로 루트 계정이 AWS에서 결제와 관련된 모든 접근 권한이 승인되어 있기 때문
    • 원래라면 다른 서비스도 마찬가지이지만 AWS는 그 서비스가 굉장히 다양하고 폭넓고 가격도 다양함
    • 그래서 루트계정으로 일상적인 작업을 하지 않는것을 AWS가 강력히 권장
  • AWS의 가이드라인에 맞춰 IAM계정을 생성하고, 관리하는 것으로 큰 과금을 막고, 해킹당하더라도 적은 피해와 구제받을 수 있는 초석을 갖추자(당하지 않더라도 예방을 철저하게)

보안 자격증명에 들어가 액세스 관리 사용자 그룹에서 권한 정책을 AdministratorAccess으로 하여 사용자 그룹을 만듬

액세스 관리 사용자에서

  1. 사용자 이름을 입력
  2. AWS 자격 증명 유형 선택에서 암호-AWS 관리 콘솔 액세스를 선택
  3. 콘솔 비밀번호를 사용자 지정 비밀 번호로 선택하고 입력
  4. 비밀번호 재설정 필요에 체크를 해제하고 다음:권한을 클릭
  5. 생성한 그룹에 체크한 후 다음 클릭
  6. 태그 추가 항목 바로 다음 클릭
  7. 검토에서 이름과 그룹을 확인한 후 다음 클릭
  8. 사용자 생성에 성공하면 링크를 복사후 링크로 들어가면 이름과 비밀번호를 입력하고 로그인

[ 버킷리스트 ]

▶ 프로젝트 세팅

Flask 폴더 구조 만들기

  • templates 폴더는 반드시 고정
  • app.py는 변경해도 좋지만, 라이브러리 이름과 같은 것을 이름으로 사용하면 안됨
  • index.html은 변경해도 좋지만, 첫 페이지는 일반적으로 index.html을 사용

▶ 가상환경 생성, 활성화, 패키지 설치

  • 화면 상단 Terminal > New Terminal 을 클릭
  • python -m venv venv 입력 후 엔터
  • 화면 오른쪽 아래의 파이썬 버전을 선택! venv로 골라주기
  • 터미널 오른쪽의 십자버튼을 클릭
  • (venv) 라고 뜨면 활성화까지 완료
  • pip을 이용하여 패키지 설치. 여러개를 설치할 때는 띄어쓰기로 구분
    • pip install flask pymongo dnspython

▶ 뼈대 준비하기

  • 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", 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() {
              fetch('/bucket').then(res => res.json()).then(data => {
                      console.log(data)
      alert(data["msg"]);
                  })
            }

            function save_bucket() {
              let formData = new FormData();
              formData.append("sample_give", "샘플데이터");

              fetch('/bucket', {method: "POST",body: formData,}).then((response) => response.json()).then((data) => {
                  alert(data["msg"]);
                  window.location.reload();
                });
            }
            
          </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>
            </li>
          </div>
        </body>
      </html>
  • mongoDB Atlas창 띄어두기

▶ POST 연습하기(버킷리스트 기록API, Create → POST)

1. 데이터 명세

  1. 요청 정보 : URL= /bucket, 요청 방식 = POST
  2. 클라(fetch) → 서버(flask) : bucket
  3. 서버(flask) → 클라(fetch) : 메시지를 보냄 (버킷리스트 저장 완료!)

2. 클라이언트와 서버 연결 확인하기

  • 서버코드 - 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() {
        let formData = new FormData();
        formData.append("sample_give", "샘플데이터");

        fetch('/bucket', {method: "POST",body: formData,}).then((response) => response.json()).then((data) => {
            alert(data['msg'])
          });
      }

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

3. 서버부터 만들기

  • 데이터베이스 연결
    • 더보기
      from pymongo import MongoClient

      client = MongoClient('내 URL')
      db = client.dbsparta
  • bucket 정보를 받아서, 저장
    • 더보기
      @app.route("/bucket", methods=["POST"])
      def bucket_post():
          bucket_receive = request.form['bucket_give']
          doc = {
              'bucket' : bucket_receive
          }
          db.bucket.insert_one(doc)
          return jsonify({'msg': '저장 완료!'})

4. 클라이언트 만들기

  • bucket 정보를 formData에 넣고 보내줌. 저장되면, 새로고침(reload)
    • 더보기
      function save_bucket() {
              let bucket = $("#bucket").val();

              let formData = new FormData();
              formData.append("bucket_give", bucket);

              fetch('/bucket', {method: "POST", body: formData,}).then((res) => res.json()).then((data) => {
                  alert(data["msg"]);
                  window.location.reload();
                });
            }

5. 완성 확인하기

  • 데이터를 입력하고 DB에 잘 들어갔는지 확인

▶ GET 연습하기(버킷리스트 조회 API, Read→ GET)

1. 데이터 명세

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

2. 클라이언트와 서버 연결 확인하기

  • 서버코드 - app.py
    • 더보기
      @app.route("/bucket", methods=["GET"])
      def bucket_get():
          return jsonify({'msg': 'GET 연결 완료!'})
  • 클라이언트코드 - index.html
    • 더보기
      $(document).ready(function () {
        show_bucket();
      });
      function show_bucket() {
        fetch('/bucket').then(res => res.json()).then(data => {
      console.log(data)
      alert(data['msg'])
            })
      }

3. 서버로부터 만들기

  • bucket에 버킷리스트를 담아서 내려주기
    • 더보기
      @app.route("/bucket", methods=["GET"])
      def bucket_get():
          all_buckets = list(db.bucket.find({}, {'_id': False}))
          return jsonify({'result': all_buckets})

4. 클라이언트 만들기

  • 버킷리스트는 리스트 형식임으로 forEach문으로 반복하면서 데이터를 뽑아낸후 제이쿼리로 append, 기존코드 지우기로 empty()사용
    • 더보기
      function show_bucket() {
        fetch('/bucket').then(res => res.json()).then(data => {
      let rows = data['result']
      $('#bucket-list').empty()
                rows.forEach((a) => {
                    let bucket = a['bucket']
                    let temp_html = `<li>
                                        <h2>✅ ${bucket}</h2>
                                    </li>`
                    $('#bucket-list').append(temp_html)
                })
            })
      }

5. 완성 확인하기

  • 동작 테스트: 화면을 새로고침 했을 때, DB에 저장된 리뷰가 화면에 올바르게 나타나는지 확인

▶ 전체 완성 코드

  • app.py -  버킷리스트 서버
    • 더보기
      from flask import Flask, render_template, request, jsonify
      app = Flask(__name__)

      from pymongo import MongoClient

      client = MongoClient('내 mongoDB URL')
      db = client.dbsparta

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

      @app.route("/bucket", methods=["POST"])
      def bucket_post():
          bucket_receive = request.form['bucket_give']
          doc = {
              'bucket' : bucket_receive
          }
          db.bucket.insert_one(doc)
          return jsonify({'msg': '저장 완료!'})
          
      @app.route("/bucket", methods=["GET"])
      def bucket_get():
          all_buckets = list(db.bucket.find({}, {'_id': False}))
          return jsonify({'result': all_buckets})

      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() {
              fetch('/bucket').then(res => res.json()).then(data => {
      let rows = data['result']
      $('#bucket-list').empty()
                rows.forEach((a) => {
                    let bucket = a['bucket']
                    let temp_html = `<li>
                                        <h2>✅ ${bucket}</h2>
                                    </li>`
                    $('#bucket-list').append(temp_html)
                })
            })
      }

            function save_bucket() {
              let bucket = $("#bucket").val();

              let formData = new FormData();
              formData.append("bucket_give", bucket);

              fetch('/bucket', {method: "POST", body: formData,}).then((res) => res.json()).then((data) => {
                  alert(data["msg"]);
                  window.location.reload();
                });
            }

          </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>
            </li>
          </div>
        </body>
      </html>

[ 팬명록]

▶ 프로젝트 세팅

Flask 폴더 구조 만들기

  • templates 폴더는 반드시 고정
  • app.py는 변경해도 좋지만, 라이브러리 이름과 같은 것을 이름으로 사용하면 안됨
  • index.html은 변경해도 좋지만, 첫 페이지는 일반적으로 index.html을 사용

▶ 가상환경 생성, 활성화, 패키지 설치

  • 화면 상단 Terminal > New Terminal 을 클릭
  • python -m venv venv 입력 후 엔터
  • 화면 오른쪽 아래의 파이썬 버전을 선택! venv로 골라주기
  • 터미널 오른쪽의 십자버튼을 클릭
  • (venv) 라고 뜨면 활성화까지 완료
  • pip을 이용하여 패키지 설치. 여러개를 설치할 때는 띄어쓰기로 구분
    • pip install flask pymongo dnspython

▶ 뼈대 준비하기

  • app.py 준비
    • 더보기
      from flask import Flask, render_template, request, jsonify
      app = Flask(__name__)

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

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

      @app.route("/guestbook", methods=["GET"])
      def guestbook_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>

          <title>초미니홈피 - 팬명록</title>

          <link
            href=" https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200;300;400;500;600;700;900&display=swap "
            rel="stylesheet"
          />
          <style>
            * {
              font-family: "Noto Serif KR", serif;
            }
            .mypic {
              width: 100%;
              height: 300px;

              background-image: linear-gradient(
                  0deg,
                  rgba(0, 0, 0, 0.5),
                  rgba(0, 0, 0, 0.5)
                ),
                url("https://cdn.topstarnews.net/news/photo/201807/456143_108614_510.jpg");
              background-position: center 30%;
              background-size: cover;

              color: white;

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

            .mypost {
              width: 95%;
              max-width: 500px;
              margin: 20px auto 20px auto;

              box-shadow: 0px 0px 3px 0px black;
              padding: 20px;
            }

            .mypost > button {
              margin-top: 15px;
            }

            .mycards {
              width: 95%;
              max-width: 500px;
              margin: auto;
            }

            .mycards > .card {
              margin-top: 10px;
              margin-bottom: 10px;
            }
          </style>
          <script>
            $(document).ready(function () {
              set_temp();
              show_comment();
            });
            function set_temp() {
              fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
      console.log(data)
                });
            }
            function save_comment() {
              let formData = new FormData();
              formData.append("sample_give", "샘플데이터");

              fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
                  //console.log(data)
                  alert(data["msg"]);
                });
            }
            function show_comment() {
              fetch('/guestbook').then((res) => res.json()).then((data) => {
      alert(data["msg"])
      })
            }
          </script>
        </head>
        <body>
          <div class="mypic">
            <h1>십센치(10cm) 팬명록</h1>
            <p>현재기온: <span id="temp">36</span>도</p>
          </div>
          <div class="mypost">
            <div class="form-floating mb-3">
              <input type="text" class="form-control" id="name" placeholder="url" />
              <label for="floatingInput">닉네임</label>
            </div>
            <div class="form-floating">
              <textarea
                class="form-control"
                placeholder="Leave a comment here"
                id="comment"
                style="height: 100px"
              ></textarea>
              <label for="floatingTextarea2">응원댓글</label>
            </div>
            <button onclick="save_comment()" type="button" class="btn btn-dark">
              댓글 남기기
            </button>
          </div>
          <div class="mycards" id="comment-list">
            <div class="card">
              <div class="card-body">
                <blockquote class="blockquote mb-0">
                  <p>새로운 앨범 너무 멋져요!</p>
                  <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
              </div>
            </div>
            <div class="card">
              <div class="card-body">
                <blockquote class="blockquote mb-0">
                  <p>새로운 앨범 너무 멋져요!</p>
                  <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
              </div>
            </div>
            <div class="card">
              <div class="card-body">
                <blockquote class="blockquote mb-0">
                  <p>새로운 앨범 너무 멋져요!</p>
                  <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
              </div>
            </div>
          </div>
        </body>
      </html>
  • mongoDB Atlas창 띄어두기

▶ 조각기능. 날씨 API 적용하기

1. OpenAPI를 활용하여 조각기능 구현하기

2. OpenAPI도 API이므로 6가지 스텝밟아 사용하기

6가지 스텝이란

  • 데이터명세
  • 클라이언트와 서버 연결확인
    • console.log()로 접속하는 데이터가 잘 오는지 확인
  • 서버만들기?
    • OpenAPI는 이미 DB가 구축된 서버이기 때문에 가져다가 보여줄 클라이언트만 만들면 됨
  • 클라이언트 만들기
  • 완성 확인하기
    • 동작 테스트: 화면을 새로고침 했을 때, 화면에 올바르게 나타나는지 확인

▶ POST 연습하기(응원 게시하기 API, Create → POST)

1. 데이터 명세

  1. 요청 정보 : URL= /guestbook, 요청 방식 = POST
  2. 클라(fetch) → 서버(flask) : name, comment
  3. 서버(flask) → 클라(fetch) : 메시지를 보냄 (응원 완료!)

2. 클라이언트와 서버 연결 확인하기

  • 서버코드 - app.py
    • 더보기
      @app.route("/guestbook", methods=["POST"])
      def guestbook_post():
          sample_receive = request.form['sample_give']
          print(sample_receive)
          return jsonify({'msg': 'POST 연결 완료!'})
  • 클라이언트 코드 - index.html
    • 더보기
      function save_comment() {
        let formData = new FormData();
        formData.append("sample_give", "샘플데이터");

        fetch('/guestbook', {method: "POST",body: formData,}).then((response) => response.json()).then((data) => {
            alert(data['msg'])
          });
      }

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

3. 서버부터 만들기

  • 데이터베이스 연결
    • 더보기
      from pymongo import MongoClient

      client = MongoClient('내 URL')
      db = client.dbsparta
  • name, comment 정보를 받아서, 저장
    • 더보기
      @app.route("/guestbook", methods=["POST"])
      def guestbook_post():
          name_receive = request.form["name_give"]
          comment_receive = request.form["comment_give"]

          doc = {
              'name': name_receive,
              'comment': comment_receive
          }

          db.fan.insert_one(doc)
          return jsonify({'msg':'응원 완료!'})

4. 클라이언트 만들기

  • name, comment 정보를 formData에 넣고 보내줌. 저장되면, 새로고침(reload)
    • 더보기
      function save_comment() {
              let name = $("#name").val();
              let comment = $("#comment").val();

              let formData = new FormData();
              formData.append("name_give", name);
              formData.append("comment_give", comment);

              fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
                  alert(data["msg"]);
                  window.location.reload();
                });
            }

5. 완성 확인하기

  • 데이터를 입력하고 DB에 잘 들어갔는지 확인

▶ GET 연습하기(응원리스트 조회 API, Read→ GET)

1. 데이터 명세

  1. 요청 정보 : URL= /guestbook, 요청 방식 = GET
  2. 클라(fetch) → 서버(flask) : 없음
  3. 서버(flask) → 클라(fetch) : 전체 응원 목록을 보여주기

2. 클라이언트와 서버 연결 확인하기

  • 서버코드 - app.py
    • 더보기
      @app.route("/guestbook", methods=["GET"])
      def guestbook_get():
          return jsonify({'msg': 'GET 연결 완료!'})
  • 클라이언트코드 - index.html
    • 더보기
      $(document).ready(function () {
        set_temp()
        show_bucket()
      });
      function show_comment() {
        fetch('/guestbook').then(res => res.json()).then(data => {
      console.log(data)
      alert(data['msg'])
            })
      }

3. 서버로부터 만들기

  • fan에 name, comment를 담아서 내려주기
    • 더보기
      @app.route("/guestbook", methods=["GET"])
      def guestbook_get():
          all_comments = list(db.fan.find({},{'_id':False}))
          return jsonify({'result':all_comments})

4. 클라이언트 만들기

  • 응원 목록을 forEach문으로 반복하면서 데이터를 뽑아낸후 제이쿼리로 append, 기존코드 지우기로 empty()사용
    • 더보기
      function show_comment() {
              fetch('/guestbook').then((res) => res.json()).then((data) => {
                  let rows = data['result']
              $("#comment-list").empty()
                  rows.forEach((a) => {
                    let name = a['name']
                    let comment = a['comment']

                    let temp_html = `<div class="card">
                                  <div class="card-body">
                                      <blockquote class="blockquote mb-0">
                                          <p>${comment}</p>
                                          <footer class="blockquote-footer">${name}</footer>
                                      </blockquote>
                                  </div>
                              </div>`
                    $("#comment-list").append(temp_html)
                  })
                })
            }

5. 완성 확인하기

  • 동작 테스트: 화면을 새로고침 했을 때, DB에 저장된 리뷰가 화면에 올바르게 나타나는지 확인

▶ 전체 완성 코드

  • app.py -  팬명록 서버
    • 더보기
      from flask import Flask, render_template, request, jsonify
      app = Flask(__name__)

      from pymongo import MongoClient

      client = MongoClient('내 mongodb URL')
      db = client.dbsparta

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

      @app.route("/guestbook", methods=["POST"])
      def guestbook_post():
          name_receive = request.form["name_give"]
          comment_receive = request.form["comment_give"]

          doc = {
              'name': name_receive,
              'comment': comment_receive
          }

          db.fan.insert_one(doc)
          return jsonify({'msg':'응원 완료!'})

      @app.route("/guestbook", methods=["GET"])
      def guestbook_get():
          all_comments = list(db.fan.find({},{'_id':False}))
          return jsonify({'result':all_comments})

      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>

          <title>초미니홈피 - 팬명록</title>

          <link
            href=" https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200;300;400;500;600;700;900&display=swap "
            rel="stylesheet"
          />
          <style>
            * {
              font-family: "Noto Serif KR", serif;
            }
            .mypic {
              width: 100%;
              height: 300px;

              background-image: linear-gradient(
                  0deg,
                  rgba(0, 0, 0, 0.5),
                  rgba(0, 0, 0, 0.5)
                ),
                url("https://cdn.topstarnews.net/news/photo/201807/456143_108614_510.jpg");
              background-position: center 30%;
              background-size: cover;

              color: white;

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

            .mypost {
              width: 95%;
              max-width: 500px;
              margin: 20px auto 20px auto;

              box-shadow: 0px 0px 3px 0px black;
              padding: 20px;
            }

            .mypost > button {
              margin-top: 15px;
            }

            .mycards {
              width: 95%;
              max-width: 500px;
              margin: auto;
            }

            .mycards > .card {
              margin-top: 10px;
              margin-bottom: 10px;
            }
          </style>
          <script>
            $(document).ready(function () {
              set_temp();
              show_comment();
            });
            function set_temp() {
              fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
              let temp = data['temp']
              $("#temp").text(temp)
            })
          }
            function save_comment() {
              let name = $("#name").val();
              let comment = $("#comment").val();

              let formData = new FormData();
              formData.append("name_give", name);
              formData.append("comment_give", comment);

              fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
                  alert(data["msg"]);
                  window.location.reload();
                });
            }
            function show_comment() {
              fetch('/guestbook').then((res) => res.json()).then((data) => {
                  let rows = data['result']
              $("#comment-list").empty()
                  rows.forEach((a) => {
                    let name = a['name']
                    let comment = a['comment']

                    let temp_html = `<div class="card">
                                  <div class="card-body">
                                      <blockquote class="blockquote mb-0">
                                          <p>${comment}</p>
                                          <footer class="blockquote-footer">${name}</footer>
                                      </blockquote>
                                  </div>
                              </div>`
                    $("#comment-list").append(temp_html)
                  })
                })
            }
          </script>
        </head>
        <body>
          <div class="mypic">
            <h1>십센치(10cm) 팬명록</h1>
            <p>현재기온: <span id="temp">36</span>도</p>
          </div>
          <div class="mypost">
            <div class="form-floating mb-3">
              <input type="text" class="form-control" id="name" placeholder="url" />
              <label for="floatingInput">닉네임</label>
            </div>
            <div class="form-floating">
              <textarea
                class="form-control"
                placeholder="Leave a comment here"
                id="comment"
                style="height: 100px"
              ></textarea>
              <label for="floatingTextarea2">응원댓글</label>
            </div>
            <button onclick="save_comment()" type="button" class="btn btn-dark">
              댓글 남기기
            </button>
          </div>
          <div class="mycards" id="comment-list">
            <div class="card">
              <div class="card-body">
                <blockquote class="blockquote mb-0">
                  <p>새로운 앨범 너무 멋져요!</p>
                  <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
              </div>
            </div>
            <div class="card">
              <div class="card-body">
                <blockquote class="blockquote mb-0">
                  <p>새로운 앨범 너무 멋져요!</p>
                  <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
              </div>
            </div>
            <div class="card">
              <div class="card-body">
                <blockquote class="blockquote mb-0">
                  <p>새로운 앨범 너무 멋져요!</p>
                  <footer class="blockquote-footer">호빵맨</footer>
                </blockquote>
              </div>
            </div>
          </div>
        </body>
      </html>

[ og 태그 ]

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

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

[ 내 프로젝트를 서버에 올리기 ]

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

1. 로컬 서버에서 클라우드 서버로

컴퓨터가 한개니깐 서버와 클라이언트를 하나의 컴퓨터에서 동작시켰음

하지만 이젠 내 컴퓨터를 켜놓지 않아도 접근할 수 있는 웹 서비스를 목표

웹 서비스를 런칭하기 위해 클라이언트의 요청에 항상 응답해줄 수 있는 서버에 프로젝트를 실행시켜줄 것임

 

언제나 요청에 응답하려면

  • 컴퓨터가 항상 켜져있고 프로그램이 실행되어 있어야 함
  • 모두가 접근할 수 있는 공개 주소인 공개 IP주소(Public IP Address)로 나의 웹 서비스에 접근 할 수 있도록 해야함

서버는 그냥 컴퓨터이기 때문에 외부 접속이 가능하게 설정한 다음에 내 컴퓨터를 서버로 사용할 수도 있음

 

2. 컴퓨터 구매하기

내 컴퓨터 대신 계속 켜놓을 컴퓨터를 구매해야함 그것을 '서버'라고 부름

우리는 컴퓨터를 직접 사는 것이 아닌 AWS라는 클라우드 서비스에서 컴퓨터를 빌릴 것임

AWS(Amazon Web Service)는 우리가 배포할 수 있도록 컴퓨터를 빌려주는 곳

Amazon이 구축해놓은 데이터센터의 컴퓨터 한개를 빌려서 배포를 하는 것

 

3. 업로드 하기

마지막으로 만든 코딩 파일들을 업로드하고 실행시켜두면 끝

▶ AWS Elastic Beanstalk

AWS는 컴퓨터를 빌려주는 서비스부터 배포와 관련된 정말 많은 서비스를 제공

그렇지만 배포는 초보자가 하기에 쉽지 않음(신경써야 하는 내용이 많고 복잡하기 때문)

그래서 초보자를 위해서 빠르게 배포할 수 있는 서비스를 제공

그것이 바로 AWS Elastic Beanstalk

 

엘라스틱 빈스톡의 장점

  1. AWS에서 제공하는 쉬운 배포 서비스
  2. 코드를 압축하여 업로드하고, AWS의 다양한 서비스를 알아서 연결해줌
  3. 배포링크를 통해 쉽게 공유가 가능하고, 코드 업데이트 기능까지 제공해줌

[ AWS Elastic Beanstalk으로 배포하기]

▶ 배포 명령어 모음

- 터미널 준비하기 - 
mkdir deploy
cp app.py deploy/application.py
cp -r templates deploy/templates
pip freeze > deploy/requirements.txt
cd deploy

- application.py 세팅하기 - 
application = app = Flask(__name__)
app.run()

- 패키지 설치하기 - 
pip install awsebcli

- 보안 자격증명 - 
eb init

- 초기 설정 - 
eb create myweb

- 코드 수정 & 업데이트 - 
eb deploy myweb

▶ 배포하기

1. 액세스 키 가져오기

AWS Elastic Beanstalk: https://ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2#/welcome 

 

https://ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2#/welcome

 

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

내 컴퓨터에서 로그인을 하려면 보안 자격이 필요함

  1. AWS 콘솔에 들어가 , 오른쪽 위 부분의 계정이름을 클릭
  2. 보안 자격 증명을 클릭
  3. 보안 자격 증명에서 액세스 키를 열고, 새 엑세스 키 만들기 클릭
  4. 액세스 키 보기를 눌러 액세스 키 ID와 보안 액세스 키를 복사하여 보관

2. 터미널 명령어로 준비완료하기

  1. mkdir deploy: deploy라는 폴더를 하나 만듬
  2. cp app.py deploy/application.py: app.py라는 파일을 deploy 폴더에 application.py라는 이름으로 바꿔서 복제함
  3. cp -r templates deploy/templates: templates라는 폴더를 deploy 폴더 안에 통째로 복제함
  4. pip freeze > deploy/requirements.txt: 내가 pip 명령어로 설치한 라이브러리들의 목록을 deploy 폴더 안에 requirements.txt 파일에 기록함
  5. cd deploy: deploy 폴더 안으로 들어감(폴더 더블클릭과 똑같은 기능)

3. 약간의 파일 설정 바꿔주기

AWS 공식문서 참조: https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/create-deploy-python-flask.html

 

Elastic Beanstalk에 Flask 애플리케이션 배포 - AWS Elastic Beanstalk

애플리케이션을 실행하기 전 application.debug = True를 추가하여 오류가 발생하는 경우 디버그 출력을 활성화합니다. 개발할 때는 이렇게 하는 것이 좋지만, 디버그 출력을 통해 애플리케이션의 내

docs.aws.amazon.com

Elastic Beanstalk 배포를 위해 필요한 것이 있음

  • application.py ← app.py에서 이름을 바꿔줘야 함
  • templates폴더와 index.html
  • requirements.txt ← 우리가 설치한 패키지들의 이름이 담긴 txt파일이에요!
  • 폴더 안에 venv가 있으면 안됨!

application.py 설정(그대로 파일을 가져다 쓴다면)

  • app.py를 application.py로 바꿔줘야 함
  • application을 읽을 수 있도록 코드를 바꿔줘야 함
  • app.run() 내용을 지움
더보기

from flask import Flask, render_template, request, jsonify
application = app = Flask(__name__)

from pymongo import MongoClient

client = MongoClient('내 mongodb URL')
db = client.dbsparta

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

@app.route("/guestbook", methods=["POST"])
def guestbook_post():
    name_receive = request.form["name_give"]
    comment_receive = request.form["comment_give"]

    doc = {
        'name': name_receive,
        'comment': comment_receive
    }

    db.fan.insert_one(doc)
    return jsonify({'msg':'응원 완료!'})

@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    all_comments = list(db.fan.find({},{'_id':False}))
    return jsonify({'result':all_comments})

if __name__ == '__main__':
   app.run()

 

4. awsebcli 패키지 설치하기

터미널을 여러 

pip install awsebcli

을 입력하고 엔터

 

5. awsebcli로 AWS Elastic Beanstalk 배포하기

  • 1. Eb init 
    • 내 컴퓨터에서 Elastic Veanstalk을 초기 설정을 진행
    • 다운로드가 완료되었다면, eb init을 입력하고 엔터
    • 아래와 같이 따라 하면 됨
    • 더보기
      Select a default region : 10 (seoul)

      AWS Access Key ID [None]: 발급된 액세스 키 ID (복사 붙여넣기)
      AWS Secret Access Key [None]: 발급된 비밀 액세스 키 (복사 붙여넣기)

      Enter Application Name (default is "deploy") : enter
      It appears you are using Python. Is this correct? : Y
      Select a platform branch (default is 1) : enter

      Do you want use Codecommit? : N
      ---
      Cannot setup CodeCommit because there is no Source Control setup, continuing with initialization
      Do you want to set up SSH for your instances? : Y

      Select a keypair : [Create new Keypair]

      Type a keypair name : enter
      Enter passphrase : enter
      Enter same passphrase again : enter
  • 2. Eb create
    • 명령어를 입력해서 배포를 함
    • eb create 환경이름을 입력하고 엔터
    • 생성까지 몇분 걸림
  • 3. 배포 환경 접속하기
    • 화면에서 배포주소를 클릭해 내가 배포한 웹 서비스를 확인
    • AWS 접속 → AWS 콘솔 연결하기 → Elastic Beanstalk
    • 생성한 환경 일므 확인 → OK 표시가 되어있는지 확인
  • 4. Eb deploy
    • 코드를 수정하고 쉽게 업데이트
    • deploy 폴더에서 변경할 코드를 적고 저장
    • 터미널을 열고 eb deploy 환경이름을 입력하고 엔터
    • 조금 기다리면 적용됨

▶ 주의사항

1. eb create를 할때마다 서버를 구매한다는 사실

Elastic Beanstalk은 eb create 환경이름 명령어를 입력할 때 마다 서버를 구매

  • 실수로 잘못 만들었다면, 서버를 여러 개를 빌린 것이 되는 것
  • 서버를 한 번에 두 개 이상 구매하고 놔두면, 요금이 발생하게 됨
  • 혹시라도 설정이 달라 제대로 배포가 되지 않았다면, create 명령어를 여러 번 입력했다면 꼭! 환경을 종료해주어야 함

2. Elastic Beanstalk 환경 종료하기

Elastic Beanstalk 환경을 종료하면, 배포 종료와 동시에 서버도 반납함

  1. AWS접속 → AWS 콘솔 접속 → Elastic Veanstalk에 들어감
  2. 종료하고 싶은 환경의 체크박스를 클릭하고, 오른쪽 위의 작업 환경 종료하기 클릭
  3. 종료할 환경의 이름을 다시 한번 입력하고 확인

'항해99' 카테고리의 다른 글

JavaScript 문법 종합반 1주차  (0) 2023.05.22
JavaScript 문법 뽀개기  (0) 2023.04.18
웹개발 종합반_4주차  (0) 2023.04.10
웹개발 종합반_3주차  (0) 2023.04.07
웹개발 종합반_2주차  (0) 2023.04.03

댓글