4주차 코딩 개발 일지(4-6~4-9)

☑️ 모두의 책 리뷰 프로젝트

  • 순서 숙지!
  1. 클라이언트와 서버 확인하기
  2. 서버부터 만들기
  3. 클라이언트 만들기.
  4. 완성 확인하기

✔︎ 만들어야 할 API 두 가지

  1. 포스팅API - 카드 생성 (Create) : 클라이언트에서 받은 url, comment를 이용해서 페이지 정보를 찾고 저장하기
  2. 리스팅API - 저장된 카드 보여주기 (Read)

✦ 모두의 책 리뷰 저장하기 (POST 연습)
제목, 저자, 리뷰 정보 저장하기(Create → POST)

  1. 클라이언트와 서버 확인하기
✽ 만들어져 있는 API 정보
1. 요청 정보 :  요청 URL= /review , 요청 방식 = POST
2. 서버가 제공할 기능 :  클라이언트에게 정해진 메시지를 보냄
3. 응답 데이터  : (JSON 형식) 'result'= 'success',
			   'msg'= '리뷰가 성공적으로 작성되었습니다.'
  • app.py (서버 코드)
from flask import Flask, render_template, jsonify, request
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta

## HTML을 주는 부분
@app.route('/')
def home():
    return render_template('index.html')

## API 역할을 하는 부분
@app.route('/review', methods=['POST'])
def write_review():

	→ 1. 클라이언트가 준 title, author, review 가져오기.
	→ 2. DB에 정보 삽입하기
	→ 3. 성공 여부 & 성공 메시지 반환하기
	
    title_receive = request.form['title_give']
    author_receive = request.form['author_give']
    review_receive = request.form['review_give']

    doc = {
        'title':title_receive,
        'author':author_receive,
        'review':review_receive
    }
    db.bookreview.insert_one(doc)




    print(sample_receive)
    return jsonify({'msg': '저장 완료'})


@app.route('/review', methods=['GET'])
def read_reviews():
    sample_receive = request.args.get('sample_give')
    print(sample_receive)
    return jsonify({'msg': '이 요청은 GET!'})


if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)
  • index.html (클라이언트 코드)
<!DOCTYPE html>
<html lang="ko">

    <head>
        <!-- Webpage Title -->
        <title>모두의 책리뷰 | 스파르타코딩클럽</title>

        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
              integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
              crossorigin="anonymous">

        <!-- JS -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
                integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
                crossorigin="anonymous"></script>

        <!-- 구글폰트 -->
        <link href="https://fonts.googleapis.com/css?family=Do+Hyeon&display=swap" rel="stylesheet">

        <script type="text/javascript">

            $(document).ready(function () {
                showReview();
            });

            function makeReview() {
                // 1. 제목, 저자, 리뷰 내용을 가져옵니다.
				// 2. 제목, 저자, 리뷰 중 하나라도 입력하지 않았을 경우 alert를 띄웁니다.
				// 3. POST /review 에 저장을 요청합니다.
                
                let title = $('#title').val()
                let author = $('#author').val()
                let review = $('#bookReview').val()


                $.ajax({
                    type: "POST",
                    url: "/review",
                    data: {title_give:title,author_give:author,review_give:review},
                    success: function (response) {
                        alert(response["msg"]);
                        window.location.reload();
                    }
                })
            }

            function showReview() {
                $.ajax({
                    type: "GET",
                    url: "/review?sample_give=샘플데이터",
                    data: {},
                    success: function (response) {
                        alert(response["msg"]);
                    }
                })
            }
        </script>

        <style type="text/css">
            * {
                font-family: "Do Hyeon", sans-serif;
            }

            h1,
            h5 {
                display: inline;
            }

            .info {
                margin-top: 20px;
                margin-bottom: 20px;
            }

            .review {
                text-align: center;
            }

            .reviews {
                margin-top: 100px;
            }
        </style>
    </head>

    <body>
        <div class="container">
            <img src="https://previews.123rf.com/images/maxxyustas/maxxyustas1511/maxxyustas151100002/47858355-education-concept-books-and-textbooks-on-the-bookshelf-3d.jpg"
                 class="img-fluid" alt="Responsive image">
            <div class="info">
                <h1>읽은 책에 대해 말씀해주세요.</h1>
                <p>다른 사람을 위해 리뷰를 남겨주세요! 다 같이 좋은 책을 읽는다면 다 함께 행복해질 수 있지 않을까요?</p>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">제목</span>
                    </div>
                    <input type="text" class="form-control" id="title">
                </div>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">저자</span>
                    </div>
                    <input type="text" class="form-control" id="author">
                </div>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">리뷰</span>
                    </div>
                    <textarea class="form-control" id="bookReview"
                              cols="30"
                              rows="5" placeholder="140자까지 입력할 수 있습니다."></textarea>
                </div>
                <div class="review">
                    <button onclick="makeReview()" type="button" class="btn btn-primary">리뷰 작성하기</button>
                </div>
            </div>
            <div class="reviews">
                <table class="table">
                    <thead>
                    <tr>
                        <th scope="col">제목</th>
                        <th scope="col">저자</th>
                        <th scope="col">리뷰</th>
                    </tr>
                    </thead>
                    <tbody id="reviews-box">
                    <tr>
                        <td>왕초보 8주 코딩</td>
                        <td>김르탄</td>
                        <td>역시 왕초보 코딩교육의 명가답군요. 따라하다보니 눈 깜짝할 사이에 8주가 지났습니다.</td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </body>

</html>


2. 서버부터 만들기

  • API= 약속

    ✔︎ 리뷰를 작성하기 위해 필요한 정보 세 가지
    -제목(title)
    -저자(author)
    -리뷰(review)

    ✔︎ 따라서 API 기능은 다음 세 단계로 구성되어야 합니다.
    1️⃣ 클라이언트가 준 title, author, review 가져오기.
    2️⃣ DB에 정보 삽입하기
    3️⃣ 성공 여부 & 성공 메시지 반환하기

  • 만들 API 정보
    A. 요청 정보
    -요청 URL= /review , 요청 방식 = POST
    -요청 데이터 : 제목(title), 저자(author), 리뷰(review)
    B. 서버가 제공할 기능 : 클라이언트에게 보낸 요청 데이터를 데이터베이스에 생성(Create)하고, 저장이 성공했다고 응답 데이터를 보냄
    C. 응답 데이터 : (JSON 형식) 'msg'= '작성 완료'
@app.route('/review', methods=['POST'])
def write_review():
    → title_receive로 클라이언트가 준 title 가져오기
    title_receive = request.form['title_give']
    → author_receive로 클라이언트가 준 author 가져오기
    author_receive = request.form['author_give']
    → review_receive로 클라이언트가 준 review 가져오기
    review_receive = request.form['review_give']

    → DB에 삽입할 review 만들기
    doc = {
        'title': title_receive,
        'author': author_receive,
        'review': review_receive
    }
    → reviews에 review 저장하기
    db.bookreview.insert_one(doc)
    → 성공 여부 & 성공 메시지 반환
    return jsonify({'msg': '리뷰가 성공적으로 작성되었습니다.'})
  1. 클라이언트 만들기
  • API
    1️⃣ input에서 title, author, review 가져오기
    2️⃣ 입력값이 하나라도 없을 때 alert 띄우기.
    3️⃣ Ajax로 서버에 저장 요청하고, 화면 다시 로딩하기
  • 사용할 API 정보
    A. 요청 정보
    -요청 URL= /review , 요청 방식 = POST
    -요청 데이터 : 제목(title), 저자(author), 리뷰(review)
    B. 서버가 제공할 기능 : 클라이언트에게 보낸 요청 데이터를 데이터베이스에 생성(Create)하고, 저장이 성공했다고 응답 데이터를 보냄
    C. 응답 데이터 : (JSON 형식) 'result'= 'success', 'msg'= '리뷰 작성 완료'
function makeReview() {
    → 화면에 입력어 있는 제목, 저자, 리뷰 내용을 가져옵니다.
    let title = $("#title").val();
    let author = $("#author").val();
    let review = $("#bookReview").val();

    → POST /review 에 저장(Create)을 요청합니다.
    $.ajax({
        type: "POST",
        url: "/review",
        data: { title_give: title, author_give: author, review_give: review },
        success: function (response) {
            alert(response["msg"]);
            window.location.reload();
        }
    })
}
  1. 완성확인
  • 동작 테스트
    제목, 저자, 리뷰를 작성하고 '리뷰 작성하기' 버튼을 눌렀을 때,
    '리뷰 작성 완료'라는 alert가 뜨는지 확인.

✦ 모두의 책 리뷰 저장하기 (GET 연습)
저장된 리뷰를 화면에 보여주기(Read → GET)

  • 순서는 POST와 동일
  1. 클라이언트와 서버 확인하기
  2. 서버부터 만들기
  3. 클라이언트 만들기
  4. 완성 확인하기
  • app.py(서버코드)
@app.route('/review', methods=['GET'])
def read_reviews():
    sample_receive = request.args.get('sample_give')
    print(sample_receive)
    return jsonify({'msg': '이 요청은 GET!'})
  • index.html(클라이언트 코드)
function showReview() {
		→ 서버의 데이터를 받아오기
		$.ajax({
        type: "GET",
        url: "/review?sample_give=샘플데이터",
        data: {},
        success: function (response) {
            alert(response["msg"]);
        }
    })
}
  1. 서버부터 만들기
  • API 기능 구성
    • DB에서 리뷰 정보 모두 가져오기
    • 성공 여부 & 리뷰 목록 반환하기
  • 만들 API 정보
    A. 요청 정보
    -요청 URL= /review , 요청 방식 = GET
    -요청 데이터 : 없음
    B. 서버가 제공할 기능 : 데이터베이스에 리뷰 정보를 조회(Read)하고, 성공 메시지와 리뷰 정보를 응답 데이터를 보냄
    C. 응답 데이터 : (JSON 형식) 'all_reviews'= 리뷰리스트
@app.route('/review', methods=['GET'])
def read_reviews():
    → 1. DB에서 리뷰 정보 모두 가져오기
    reviews = list(db.bookreview.find({}, {'_id': False}))
    → 2. 성공 여부 & 리뷰 목록 반환하기
    return jsonify({'all_reviews': reviews})

3.클라이언트 만들기

  • 제목(title), 저자(author), 리뷰(review) 추가
    1️⃣ 리뷰 목록을 서버에 요청하기
    2️⃣ 요청 성공 여부 확인하기
    3️⃣ 요청 성공했을 때 리뷰를 올바르게 화면에 나타내기
function showReview() {
                $.ajax({
                    type: "GET",
                    url: "/review",
                    data: {},
                    success: function (response) {
                        let reviews = response['all_reviews']
                        for (let i = 0; i < reviews.length; i++) {
                            let title = reviews[i]['title']
                            let author = reviews[i]['author']
                            let review = reviews[i]['review']

                            let temp_html = `<tr>
                                                <td>${title}</td>
                                                <td>${author}</td>
                                                <td>${review}</td>
                                            </tr>`
                            $('#reviews-box').append(temp_html)
                        }
                    }
                })
            }
  1. 완성 확인하기

✦ 전체 완성 코드

  • 서버코드
from flask import Flask, render_template, jsonify, request
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta

## HTML을 주는 부분
@app.route('/')
def home():
    return render_template('index.html')

## API 역할을 하는 부분
@app.route('/review', methods=['POST'])
def write_review():
    title_receive = request.form['title_give']
    author_receive = request.form['author_give']
    review_receive = request.form['review_give']

    doc = {
        'title':title_receive,
        'author':author_receive,
        'review':review_receive
    }

    db.bookreview.insert_one(doc)

    return jsonify({'msg': '저장 완료!'})


@app.route('/review', methods=['GET'])
def read_reviews():
    reviews = list(db.bookreview.find({}, {'_id': False}))
    return jsonify({'all_reviews': reviews})


if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)
  • 클라이언트 코드
<!DOCTYPE html>
<html lang="ko">

    <head>
        <!-- Webpage Title -->
        <title>모두의 책리뷰 | 스파르타코딩클럽</title>

        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
              integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
              crossorigin="anonymous">

        <!-- JS -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
                integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
                crossorigin="anonymous"></script>

        <!-- 구글폰트 -->
        <link href="https://fonts.googleapis.com/css?family=Do+Hyeon&display=swap" rel="stylesheet">

        <script type="text/javascript">

            $(document).ready(function () {
                showReview();
            });

            function makeReview() {
                let title = $('#title').val()
                let author = $('#author').val()
                let review = $('#bookReview').val()

                $.ajax({
                    type: "POST",
                    url: "/review",
                    data: {title_give:title,author_give:author,review_give:review},
                    success: function (response) {
                        alert(response["msg"]);
                        window.location.reload();
                    }
                })
            }

            function showReview() {
                $.ajax({
                    type: "GET",
                    url: "/review",
                    data: {},
                    success: function (response) {
                        let reviews = response['all_reviews']
                        for (let i = 0; i < reviews.length; i++) {
                            let title = reviews[i]['title']
                            let author = reviews[i]['author']
                            let review = reviews[i]['review']

                            let temp_html = `<tr>
                                                <td>${title}</td>
                                                <td>${author}</td>
                                                <td>${review}</td>
                                            </tr>`
                            $('#reviews-box').append(temp_html)
                        }
                    }
                })
            }

        </script>


        <style type="text/css">
            * {
                font-family: "Do Hyeon", sans-serif;
            }

            h1,
            h5 {
                display: inline;
            }

            .info {
                margin-top: 20px;
                margin-bottom: 20px;
            }

            .review {
                text-align: center;
            }

            .reviews {
                margin-top: 100px;
            }
        </style>
    </head>

    <body>
        <div class="container" style="max-width: 600px;">
            <img src="https://image.freepik.com/free-vector/large-bookcase-with-books-library-book-shelf-interior_92863-357.jpg"
                 class="img-fluid" alt="Responsive image">
            <div class="info">
                <h1>읽은 책에 대해 말씀해주세요.</h1>
                <p>다른 사람을 위해 리뷰를 남겨주세요! 다 같이 좋은 책을 읽는다면 다 함께 행복해질 수 있지 않을까요?</p>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">제목</span>
                    </div>
                    <input type="text" class="form-control" id="title">
                </div>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">저자</span>
                    </div>
                    <input type="text" class="form-control" id="author">
                </div>
                <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">리뷰</span>
                    </div>
                    <textarea class="form-control" id="bookReview"
                              cols="30"
                              rows="5" placeholder="140자까지 입력할 수 있습니다."></textarea>
                </div>
                <div class="review">
                    <button onclick="makeReview()" type="button" class="btn btn-primary">리뷰 작성하기</button>
                </div>
            </div>
            <div class="reviews">
                <table class="table">
                    <thead>
                    <tr>
                        <th scope="col">제목</th>
                        <th scope="col">저자</th>
                        <th scope="col">리뷰</th>
                    </tr>
                    </thead>
                    <tbody id="reviews-box">
                    </tbody>
                </table>
            </div>
        </div>
    </body>

</html>

리뷰작성하기 누르면 알림메세지 안 뜨네..ㅎ....ㅏ
똑같이 했는ㄷ ㅔ 왜 나만 안 되는거니..........

좋은 웹페이지 즐겨찾기