2023. 4. 9. 14:56ㆍ항해99
스파르타 코딩클럽 웹개발 종합반 수업내용을 정리한 것입니다.
이전 수업들의 복습이 메인인 수업들이었습니다.
버킷리스트
- 가상 환경 및 패키지 설치
python3 -m venv venv
pip install flask pymongo dnspython
코드
<!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 formData = new FormData();
let bucket = $("#bucket").val();
formData.append("bucket_give", bucket);
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>
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://이름:비밀번호@cluster0.2xxwxhc.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
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.buckets.insert_one(doc)
return jsonify({'msg': '저장완료'})
@app.route("/bucket", methods=["GET"])
def bucket_get():
allbucket = list(db.buckets.find({}, {'_id':False}))
return jsonify({'result': allbucket})
if __name__ == '__main__':
app.run('0.0.0.0', port=5001, debug=True)
팬명록
마찬가지로 가상환경 및 패키지 설치
코드
<!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>
<meta property="og:title" content="뜨또 팬명록" />
<meta
property="og:description"
content="밉지만 노래는 잘하는 미운 우리 뜨또에게 응원 한마디!"
/>
<meta
property="og:image"
content="data:image/jpeg;base64,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"
/>
<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("data:image/jpeg;base64,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");
/* 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)
// 내가 한 답
$("#temp").empty();
$("#temp").append(temp);
});
}
function save_comment() {
let formData = new FormData();
let name = $("#name").val();
let comment = $("#comment").val();
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>뜨또 팬명록</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>
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://이름:비밀번호@cluster0.2xxwxhc.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
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.guestbooks.insert_one(doc)
return jsonify({'msg': '저장 완료!'})
@app.route("/guestbook", methods=["GET"])
def guestbook_get():
allguestbook = list(db.guestbooks.find({}, {'_id':False}))
return jsonify({'result': allguestbook})
if __name__ == '__main__':
app.run('0.0.0.0', port=5001, debug=True)
AWS
- 아마존에서 운영하는 클라우드 서비스
1) 웹 서비스 런칭에 대한 개념
- 나의 컴퓨터에 localhost 로 돌아가고 있다.
- 누군가에 요청이 올때마다 대기를 해야하는데 항상 컴퓨터를 켜놓을 수는 없다.
- 내 컴퓨터 대신 계속 켜놓을 컴퓨터를 사야하는데 그것이 서버이다.
- 인터넷 환경에서 컴퓨터를 대여한다. 대여한 컴퓨터에 내 파일을 올려놓는 것
- 이것이 클라우드 환경이다.
2) 초보자를 위한 배포서비스 AWS Elastic Beanstalk
- 배포는 초보자가 하기에 쉽지 않기 때문에 쉽게 배포할 수 있는 서비스를 제공해야 한다.
3) 배포하기
- 위 링크로 접속해 로그인
- 사이트 오른쪽 위 내아이디를 클릭하고 보안자격증명 클릭
- Mac 의 경우 command + 클릭 하면 새 창으로 브라우저가 열린다.
- 엑세스키 클릭 > 엑세스 키 만들기 클릭
- 메모장에 엑세스키와 비밀 엑세스키 ( 시크릿키 ) 를 적어놓는다.
- 아래를 메모장에 적어놓는다.
- 터미널 준비하기 -
mkdir deploy
cp app.py deploy/application.py
cp -r templates deploy/templates
pip freeze > deploy/requirements.txt
cd deploy
- appication.py 세팅하기 -
application = app = Flask(__name__)
app.run()
- 패키지 설치하기 -
pip install awsebcli
- 보안 자격증명 -
eb init
- 초기 설정 - 설치가 다 되면 사이트에 어플리케이션 텝을 클릭하면 볼 수 있다.
eb create myweb
- 코드 수정 & 업데이트 -
eb deploy myweb
- VSC 터미널에서 위 코드 순서대로 진행할 것
application.py 세팅
from flask import Flask, render_template, request, jsonify
application = app = Flask(__name__)
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://이름:비밀번호@cluster0.2xxwxhc.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
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.guestbooks.insert_one(doc)
return jsonify({'msg': '저장 완료!'})
@app.route("/guestbook", methods=["GET"])
def guestbook_get():
allguestbook = list(db.guestbooks.find({}, {'_id':False}))
return jsonify({'result': allguestbook})
if __name__ == '__main__':
app.run()
보안자격증명
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
- 여기까지가 컴퓨터를 인터넷에서 이제 하나 산 것이다.
완성된 팬명록 링크 : http://myweb.eba-skxrkycc.ap-northeast-2.elasticbeanstalk.com/
4) 배포한 코드 수정하기
- deploy 폴더 안에있는 것이 배포되는 것이기 때문에 원본 파일인 app.py 를 수정하면된다.
- 가상환경 세팅
- 바뀐부분을 그대로 복사해서 deploy 안에있는 같은 파일에 바뀐부분을 붙여넣는다. 또는 전체 복붙
- 이제 업로드를 해야한다.
- deploy 폴더로 이동한 다음에 업로드 해야한다.
eb deploy myweb
- 기다리면 업로드가 된다.
주의점
- eb create 를 자주하면 안된다. eb create 를 할 때마다 서버를 구매한다.
- 만약 여러개가 있다면 사이트에 애플리케이션텝 > 작업 클릭후 애플리케이션 삭제를 누른다.
- 또 1년이 지나면 삭제할 것
5주차 소감
우선 4번 연속으로 같은부분을 복습하는 부분이 좋았다. 두번정도는 따라했고 이후 두번은 결과물만보고 따라서 구현하며 학습했더니 더 잘 이해되었고 모르는 부분이 어디인지 알 수 있었다.
배포를 경험하는 것도 좋았다. 과거에 heroku 나 s3 에 배포 했었을 때보다 훨씬 편한방법이었다.
편한방법이었음에도 고맙게도 에러를 만났는데 pip 업데이트 문제였다. 오류를 만날때마다 성장하는 느낌이다.
이제는 강의를 전체적으로 한번더 회독하며 기능같은걸 추가해볼 계획이다.
'항해99' 카테고리의 다른 글
엑셀보다 쉬운 SQL 2주차 (2) | 2023.06.01 |
---|---|
엑셀보다 쉬운 SQL 1주차 (0) | 2023.06.01 |
웹개발 종합반 4주차 (0) | 2023.04.08 |
웹개발 종합반 3주차 (0) | 2023.04.08 |
웹개발 종합반 2주차 (0) | 2023.04.08 |