Anaconda | The World's Most Popular Data Science Platform
Anaconda is the birthplace of Python data science. We are a movement of data scientists, data-driven enterprises, and open source communities.
www.anaconda.com
Anaconda | The World's Most Popular Data Science Platform
Anaconda is the birthplace of Python data science. We are a movement of data scientists, data-driven enterprises, and open source communities.
www.anaconda.com
[php] 관리자 페이지 CRUD + 로그인 + 세션 (CSS + HTML + PHP +mysql) (0) | 2020.11.04 |
---|---|
[Vue] 원페이지 게시판 CRUD ( vue + php + mysql + 부트스트랩) (0) | 2020.11.04 |
[JSP] 단어 웹 사이트 만들기( index, login, join 폼) (0) | 2020.06.29 |
[JSP] 부트스트랩을 이용한 수강신청 게시판 만들기(글목록 출력 및 검색구현,삭제, 추천 구현,XSS 방어) (0) | 2020.06.19 |
[JSP] 부트스트랩을 이용한 수강신청 게시판 만들기(로그인 및 로그아웃 구현하기/평가등록하기/신고하기) (0) | 2020.06.18 |
[php] 회사 홈페이지 반응형 포토폴리오(PHP + mysql + CSS + JS +HTML+ jquery) + IE 버전 가능 (0) | 2020.11.04 |
---|---|
[Vue] 원페이지 게시판 CRUD ( vue + php + mysql + 부트스트랩) (0) | 2020.11.04 |
[JSP] 단어 웹 사이트 만들기( index, login, join 폼) (0) | 2020.06.29 |
[JSP] 부트스트랩을 이용한 수강신청 게시판 만들기(글목록 출력 및 검색구현,삭제, 추천 구현,XSS 방어) (0) | 2020.06.19 |
[JSP] 부트스트랩을 이용한 수강신청 게시판 만들기(로그인 및 로그아웃 구현하기/평가등록하기/신고하기) (0) | 2020.06.18 |
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<!-- CSS only -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
<script src="https://kit.fontawesome.com/42e2ecb8e0.js" crossorigin="anonymous"></script>
<style type="text/css">
#overlay {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
}
</style>
</head>
<body>
<!-- header -->
<div id="app">
<div class="container-fluid">
<div class="row bg-dark">
<div class="col-lg-12">
<p class="text-center text-light display-4 pt-2" style="font-size: 25px">
CRUD 어플리케이션 vue, PHP, mysqli
</p>
</div>
</div>
</div>
<div class="container">
<div class="row mt-3">
<div class="col-lg-6">
<h3 class="text-info">등록 된 유저들</h3>
</div>
<div class="col-lg-6">
<button class="btn btn-info float-right" @click="showAddModal=true">
<i class="fas fa-user"></i> 새롭게 추가
</button>
</div>
</div>
<hr class="bg-info" />
<div class="alert alert-danger" v-if="errorMsg">{{ errorMsg }}</div>
<div class="alert alert-success" v-if="successMsg">{{ successMsg }} </div>
<!--디스플레이 레코드-->
<div class="row">
<div class="col-lg-12">
<table class="table table-bordered table-striped">
<thead>
<tr class="text-center bg-info text-light">
<th>ID</th>
<th>이름</th>
<th>이메일</th>
<th>핸드폰</th>
<th>수정</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<tr class="text-center" v-for="user in users">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.phone }}</td>
<td>
<a href="#" class="text-success" @click="showEditModal=true; selectUser(user);"><i class="fas fa-edit"></i></a>
</td>
<td>
<a href="#" class="text-danger" @click="showDeleteModal=true; selectUser(user);"><i class="fas fa-trash-alt"></i></a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--새로운 사용자 추가 모달-->
<div id="overlay" v-if="showAddModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">새로운 사용자 추가</h5>
<button type="button" class="close" @click="showAddModal=false">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body p-4">
<form action="#" method="post">
<div class="form-group">
<input type="text" name="name" class="form-control form-control-lg" placeholder="name" v-model="newUser.name">
</div>
<div class="form-group">
<input type="text" name="email" class="form-control form-control-lg" placeholder="email" v-model="newUser.email">
</div>
<div class="form-group">
<input type="text" name="phone" class="form-control form-control-lg" placeholder="phone" v-model="newUser.phone">
</div>
<div class="form-group">
<button class="btn btn-info btn-block btn-lg" @click="showAddModal=false; addUser(); clearMsg();">사용자 추가</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!--사용자 수정 모달-->
<div id="overlay" v-if="showEditModal ">
<div class="modal-dialog ">
<div class="modal-content ">
<div class="modal-header ">
<h5 class="modal-title ">사용자 수정</h5>
<button type="button " class="close " @click="showEditModal=false ">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body p-4 ">
<form action="# " method="post ">
<div class="form-group ">
<input type="text " name="name " class="form-control form-control-lg" v-model="currentUser.name">
</div>
<div class="form-group ">
<input type="text " name="email " class="form-control form-control-lg" placeholder="이메일" v-model="currentUser.email">
</div>
<div class="form-group ">
<input type="text " name="phone " class="form-control form-control-lg" placeholder="핸드폰" v-model="currentUser.phone">
</div>
<div class="form-group ">
<button class="btn btn-info btn-block btn-lg " @click="showEditModal=false; updateUser(); clearMsg();">사용자 업데이트</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!--사용자 삭제 모달-->
<div id="overlay" v-if="showDeleteModal ">
<div class="modal-dialog ">
<div class="modal-content ">
<div class="modal-header ">
<h5 class="modal-title ">사용자 삭제</h5>
<button type="button " class="close " @click="showDeleteModal=false ">
<span aria-hidden="true ">×</span>
</button>
</div>
<div class="modal-body p-4 ">
<h4 class="text-danger ">정말 삭제하시겠습니까?</h4>
<h5>당신은 '{{ currentUser.name }}'를 삭제합니다.</h5>
<hr>
<button class="btn btn-danger btn-lg " @click="showDeleteModal=false; deleteUser(); clearMsg(); ">네</button>
<button class="btn btn-success btn-lg " @click="showDeleteModal=false ">아니오</button>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.20.0/axios.min.js "></script>
<script src="https://cdn.jsdelivr.net/npm/vue "></script>
<script>
var app = new Vue({
el: "#app ",
data: {
errorMsg: "",
successMsg: "",
showAddModal: false,
showEditModal: false,
showDeleteModal: false,
users: [],
newUser: {
name: "",
email: "",
phone: ""
},
currentUser: {}
},
mounted: function() {
this.getAllUsers();
},
methods: {
getAllUsers() {
axios.get("http://localhost/crud-vue-php/process.php?action=read").then(function(response) {
if (response.data.error) {
app.errorMsg = response.data.message;
} else {
app.users = response.data.users;
}
});
},
addUser() {
var formData = app.toFormData(app.newUser);
axios.post("http://localhost/crud-vue-php/process.php?action=create", formData).then(function(response) {
app.newUser = {
name: "",
email: "",
phone: ""
};
if (response.data.error) {
app.errorMsg = response.data.message;
} else {
app.successMsg = response.data.message;
app.getAllUsers();
}
});
},
updateUser() {
var formData = app.toFormData(app.currentUser);
axios.post("http://localhost/crud-vue-php/process.php?action=update", formData).then(function(response) {
app.currentUser = {};
if (response.data.error) {
app.errorMsg = response.data.message;
} else {
app.successMsg = response.data.message;
app.getAllUsers();
}
});
},
deleteUser() {
var formData = app.toFormData(app.currentUser);
axios.post("http://localhost/crud-vue-php/process.php?action=delete", formData).then(function(response) {
app.currentUser = {};
if (response.data.error) {
app.errorMsg = response.data.message;
} else {
app.successMsg = response.data.message;
app.getAllUsers();
}
});
},
toFormData(obj) {
var fd = new FormData();
for (var i in obj) {
fd.append(i, obj[i]);
}
return fd;
},
selectUser(user) {
app.currentUser = user;
},
clearMsg() {
app.errorMsg = "";
app.successMsg = "";
}
}
});
</script>
</body>
</html>
process.php
<?php
$conn = new mysqli("localhost", "root", "", "crud_vue");
if($conn->connect_error){
die("Connection Failed!".$conn->connect_error);
}
//echo("Success");
$result = array('error'=>false);
$action = '';
if(isset($_GET['action'])){
$action = $_GET['action'];
}
if($action == 'read'){
$sql = $conn->query("SELECT * FROM users");
$users = array();
while($row = $sql->fetch_assoc()){
array_push($users, $row);
}
$result['users'] = $users;
}
if($action == 'create'){
$name = $_POST['name'];
$email = $_POST['email'];
$phone = $_POST['phone'];
$sql = $conn->query("INSERT INTO users (name,email,phone) VALUES('$name','$email','$phone')");
if($sql){
$result['message'] = "user added successfully!";
}
else{
$result['error'] = true;
$result['message'] = "failed to add user!";
}
}
if($action == 'update'){
$id = $_POST['id'];
$name = $_POST['name'];
$email = $_POST['email'];
$phone = $_POST['phone'];
$sql = $conn->query("UPDATE users SET name='$name', email='$email', phone='$phone' WHERE id='$id'");
if($sql){
$result['message'] = "user update successfully";
}
else{
$result['error'] = true;
$result['message'] = "failed to update user!";
}
}
if($action == 'delete'){
$id = $_POST['id'];
$sql = $conn->query("DELETE FROM users WHERE id='$id'");
if($sql){
$result['message'] = "유저 삭제 성공했다!";
}
else{
$result['error'] = true;
$result['message'] = "유저 삭제 실패 ㅠㅠ!";
}
}
$conn->close();
echo json_encode($result);
?>
[php] 회사 홈페이지 반응형 포토폴리오(PHP + mysql + CSS + JS +HTML+ jquery) + IE 버전 가능 (0) | 2020.11.04 |
---|---|
[php] 관리자 페이지 CRUD + 로그인 + 세션 (CSS + HTML + PHP +mysql) (0) | 2020.11.04 |
[JSP] 단어 웹 사이트 만들기( index, login, join 폼) (0) | 2020.06.29 |
[JSP] 부트스트랩을 이용한 수강신청 게시판 만들기(글목록 출력 및 검색구현,삭제, 추천 구현,XSS 방어) (0) | 2020.06.19 |
[JSP] 부트스트랩을 이용한 수강신청 게시판 만들기(로그인 및 로그아웃 구현하기/평가등록하기/신고하기) (0) | 2020.06.18 |
Welcome to The Apache Software Foundation!
Reports Official ASF reports and statements, including Quarterly and Annual Reports, Vision Statement, "Apache is Open", 5-Year Strategic Plan, and more.
www.apache.org
Apache Tomcat® - Welcome!
The Apache Tomcat® software is an open source implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies. The Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket specifications ar
tomcat.apache.org
하지만 톰캣(WAS)를 쓰면 동적인 데이터 처리가 가능하다. DB연결,데이터 조작, 다른 응용프로그램과 상호 작용이 가능하다. 톰캣은 8080포트로 처리한다
nginx
nginx nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev. For a long time, it has been running on many heavily loaded Russian sites including Yandex, Mail.Ru, VK,
nginx.org
더 적은 자원으로 더 빠르게 데이터를 서비스 할 수 있다.
opentutorials.org/module/384/3462
NGINX 소개 - NGINX
Web 웹이란 World Wide Web의 약자로 인터넷이라는 네트워크 체계 위에서 동작하는 통신 규약 중의 하나다. 아래의 그림은 인터넷과 웹의 관계를 보여준다. 웹이 인터넷과 같은 의미처럼 사용된 이유
opentutorials.org
Nginx 이해하기 및 기본 환경설정 세팅하기
NGINX Nginx의 개요 엔진엑스(Nginx)는 Igor Sysoev라는 러시아 개발자가 동시접속 처리에 특화된 웹 서버 프로그램이다. Apache 보다 동작이 단순하고, 전달자 역할만 하기 때문에 동시접속 처리에 특화��
whatisthenext.tistory.com
웹 개발을 할 때 form으로부터 전송 받은 값으 숫자인지 체크해야 할 때가 있다.
이럴 때는 간단하게 숫자체크를 하는 메소드를 공통 클래스에 포함 시켜 필요할 때마다 호출하여 사용한다.
익셉션을 이용한 숫자 체크 방법
숫자를 체크하는 방식은 Double.parseDouble 또는 Integer.parseInt를 활용하여 Exception을 통해 숫자여부를 판별
public class StringNumberCheck {
public static void main(String[] args) {
String str_1 = "가나다라" ;
String str_2 = "523" ;
String str_3 = "5.7" ;
String str_4 = "-5" ;
String str_5 = "-5.9" ;
System.out.println(isNumber(str_1)) ;
System.out.println(isNumber(str_2)) ;
System.out.println(isNumber(str_3)) ;
System.out.println(isNumber(str_4)) ;
System.out.println(isNumber(str_5)) ;
}
// 익셉션에 걸린 다는 것은 잘못된 코드라는 뜻, 반대로 활용하면 숫자인지 아닌지 가려낸다.
public static boolean isNumber(String str){
boolean result = false;
try{
Double.parseDouble(str) ;
result = true ;
}catch(Exception e){}
return result ;
}
}
// 숫자 : true 아닐 경우 :false
출처: https://fruitdev.tistory.com/84 [과일가게 개발자]
https://fruitdev.tistory.com/84
[Java] 간단한 숫자체크
웹 개발을 할때 form 으로부터 전송받은 값이 숫자인지 체크해야 할 일이 종종 있다. 이럴때는 간단하게 숫자체크하는 메소드를 공통 클래스에 포함시켜 필요할때마다 호출해서 사용하면 편하다
fruitdev.tistory.com
20200115[JAVA] 파일을 읽고 DB저장 후 HTML로 전환 (0) | 2020.03.28 |
---|---|
20200114 [JAVA] mysql 조회하여 HTML 로 전환 (0) | 2020.03.28 |
20200113[JAVA] mysql 메소드, DB접속 및 쿼리 실행 (0) | 2020.03.28 |
20200113[JAVA] 파일 다루기, 예외처리, 웹 문서파일 만들기 (0) | 2020.03.28 |
20200108~9 [JAVA] extend, 상속, 접근제한자, 오버라이드 (0) | 2020.03.28 |
Flask(웹 어플리케이션)과 Nginx(웹 서버)를 uWSGI(WSGI 인터페이스)를 이용하여 서로 연결하여 서비스를 할 수 있습니다.
WSGI(Web Server Gateway Interface)
- 웹서버와 웹 어플리케이션이 어떤 방식으로 통신하는가에 관한 인터페이스를 의미
- 웹서버와 웹어플리케이션 간의 소통을 정의해 어플리케이션과 서버가 독립적으로 운영될 수 있게 돕는다.
- WSGI 어플리케이션은 uWSGI라는 컨테이너에 담아 어플리케이션을 실행하게 되며, uWSGI가 각각의 웹서버와 소통하도록 설정하면 끝이다. Flask, django와 같은 프레임워크는 이미 WSGI 표준을 따르고 있기 때문에 바로 웹서버에 연결해 사용할 수 있다.
- WSGI는 파이썬 표준이며, 서버에서 들어온 요청에 맞춰서 파이썬 웹 어플리케이션에 미리 등록된 로직을 콜백 함수로 서버에 응답해줍니다. 여기서 WSGI 인터페이스에 맞춰서 제작된 프레임워크가 uWSGI입니다.
오래된 uwsgi를 삭제한다.
mv /usr/bin/uwsgi /usr/bin/uwsgi-old
새롭게 uwsgi를 설치해준다.
pip install uwsgi
ln -s /usr/local/bin/uwsgi /usr/bin/uwsgi
uwsgi로 해당 어플리케이션을 실행한다.
uwsgi -s /tmp/uwsgi.sock --module yourapplication --callable app --venv .venv
파라미터를 매번 입력하기 번거로우므로 다음과 같으 ini파일을 작성해 저장해 놓고 실행 할 수 있다.
[uwsgi]
chdir=/home/ubuntu/helloWorld
chmod-socket=666
callable=app
module=app
socket=/tmp/uwsgi.sock
virtualenv=/home/ubuntu/helloWorld/.venv
윗 처럼 작성한 후 다음 명령어로 실행한다.
uwsgi <filename> &
https://edykim.com/ko/post/connecting-flask-uwsgi-to-nginx/(출처)
nginx
- nginx는 기존의 apache같은 웹 서버입니다. 기존 apache 서버와 다른 점은 nginx 는 비동기 이벤트 기반으로 만들어졌고, apache 서버는 동기식, 프로세스 또는 쓰레드 기반으로 만들어졌습니다.
apache서버에 비해서메모리를 적게가져간다는 장점이 있습니다.
apt-get을 통해 설치
apt-get install nginx-full
/etc/nginx/sites-available/default 파일을 열어 설정을 해준다.
server {
listen 8080;
server_name helloworld.haruair.com;
location / {
try_files $uri @helloworld;
}
location @helloworld {
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
}
}
위 설정을 통해 nginx로 들어오는 모든 요청을 uWSGI로 보내고
또 돌려받아 nginx를 통해 클라이언트에 전달하게 된다. nginx를 재구동하면 적용된다.
/etc/init.d/nginx restart
https://medium.com/sunhyoups-story/flask-nginx-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-258b979d2de3
Flask + Nginx 설치 방법
Flask와 Nginx를 uWSGI를 이용하여 연결해봅시다
medium.com
차이점 Apache vs Nginx
https://youngmind.tistory.com/entry/Apache-vs-Nginx
Apache vs Nginx
Apache vs Nginx Apache와 Nginx는 현재까지 가장 폭넓게 사용되는 2가지의 오픈소스 웹서버이다. 2가지 솔루션들은 현재 전체 웹서비스의 50% 이상을 차지할 정도로 프론트엔드에서 사랑받고 있다. 이�
youngmind.tistory.com
https://presmarymethuen.org/ko/dictionary/what-is-the-difference-between-static-and-dynamic-content/
정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까
집 / 질문 / 정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까 정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까 대답 1: 정적 콘텐츠는 사이트를 방문하는 모든 사람에게 동일한 콘텐츠입니��
presmarymethuen.org
sqlarchemy
- Python의 객체에 데이터 모델을 정의하고 이를 데이터베이스와 매핑해주는 것을 ORM(Object Relaition Model)이라고 합니다. 덕분에 코드는 특정 데이터베이스에 종속되지 않고, 기본 객체 만으로 데이터를 기술할 수 있기 때문에 조금 더 OOP 스러운 코드를 작성할 수 있습니다.
Python에서 ORM으로 많이 쓰이는 것 중 SQLAlchemy가 있는데, 이를 Flask에서 플러그인 처럼 사용하기 쉽게 만들어진 Flask-SQLALchemy가 있습니다.
패키지 설치
(venv) PS flask_blog> pip install flask_sqlalchemy
https://opentutorials.org/module/3669/22070
데이터베이스 - Flask로 만드는 블로그
이전 시간에 우리는 부트스트랩을 이용해서 어플리케이션의 디자인을 조금 세련되게 변경했습니다. 이번에는 사용자와 게시물에 대한 정보를 저장하기 위한 데이터베이스를 만들어보도록 하��
opentutorials.org
[flask] Flask-Login (0) | 2020.08.05 |
---|---|
[flask] jinja2 {% include %} 활용 (0) | 2020.07.23 |
[flack] aws : CURRENT_USER/HTTP 요청 전후에 호출되는 데코레이터/ is_authenticated 소개 및 예시/render_template 사용법 (0) | 2020.07.22 |
[flask] 내부 링크 만들기 -url_for() (0) | 2020.07.22 |
소프트웨어의 내부 구조나 작동 원리를 모르는 상태에서 동작을 검사하는 방식이다.
사용자가 직접 특정 App이나 Device를 가지고 이리저리 작동시키는 과정이 블랙박스 테스트와 동일하다.
즉, 내부에 어떤 내용이 있는지 하나도 모른 채, 내가 원하는 기능이 예측한대로 정상 동작 하는지를 확인하는 방식이다.
즉, 사용자가 소프트웨어 또는 제품에 대한 요구사항과 결과물이 일치하는 지 확인하기 위한 테스트 기법
(사용자 관점의 테스트 방법)
응용 프로그램의 내부 구조, 동작을 디테일하게 검사하는 테스트 방식이다.
디테일하게라는 의미는 내부 소스 코드를 테스트 하는 기법이며 사용자가 들여다 볼 수 없는 구간의 코드 단위들을 테스트 할 수 있다.(ex : private variable or method etc...)
즉, 개발자가 소프트웨어 또는 컴포넌트 등의 로직에 대한 테스트를 수행하기 위해 설계 단계에서 요구된 사항을 확인하는 테스트 기법 (개발자 관점의 단위 테스팅 기법)
**예제 코드** from flask import Flask, render_template #... @app.route('/user/<name>') def user(name): return render_template('user_html', name=name)
예제 코드
from flask import Flask, render_template
#...
@app.route('/user/<name>')
def user(name):
return render_template('user_html', name=name)
템플릿 엔진 설명의 예시
재사용성이 높다.
웹페이지 혹은 웹앱을 만들 때 똑같은 디자인의 페이지에서 보이는 데이터만 바뀌는 경우가 많다.한 페이지를 템플릿 엔진 문법으로 만들어 놓고 여기에 데이터를 바꿔가면서 렌더링을 해주면 수 백의 페이지들을 나타낼수 있다.
유지보수에 용이하다
템플릿 엔진을 사용하면 동일한 템플릿을 사용한다는 전제하에 템플릿과 넘겨주는 데이터만 수정하면 된다.
코드를 많이 줄일 수 있다.
대부분의 템플릿 엔진은 기존의 HTML에 비해서 간단한 문법을 사용한다. 코드가 길어지면 길어질 수록 템플릿 엔진을 사용하면 좋다.
템플릿 사용의 예시
변수 나 표현식
**{{ . . . }} 사용의 예시** **변수의 예시** {% for head in table['thead'] %} <th>{{ head }}</th> {% endfor %} **표현식의 예시** <h1 class="h3 mb-2 text-gray-800">{{ page['manager.index'].get('title') }}</h1> <p class="mb-4">{{ page['manager.index'].get('sub_title') }}</p>
{{ . . . }} 사용의 예시
변수의 예시
{% for head in table['thead'] %}
<th>{{ head }}</th>
{% endfor %}
표현식의 예시
<h1 class="h3 mb-2 text-gray-800">{{ page['manager.index'].get('title') }}</h1>
<p class="mb-4">{{ page['manager.index'].get('sub_title') }}</p>
if나 for 같은 제어문
**{%. . . %} 사용의 예시** {% for i in range(body|length) %} <tr> {% set index = body[0] %} {% for i in range(body|length) %} {% if i == 1 %} <td> <a href="{{ url_for('manager.item', id=[index]) }}"> {{ body[i] }} </a> </td> {% else %} <td> {% if body[i] == '' %} - {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %} </td> {% endif %} {% endfor %} </tr> {% endfor %}
{%. . . %} 사용의 예시
{% for i in range(body|length) %}
<tr>
{% set index = body[0] %}
{% for i in range(body|length) %}
{% if i == 1 %}
<td>
<a href="{{ url_for('manager.item', id=[index]) }}">
{{ body[i] }}
</a>
</td>
{% else %}
<td>
{% if body[i] == '' %}
-
{% else %}
{{ body[i]|replace('\n', '<br>')|safe }}
{% endif %}
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
주석문
{# . . . #} **사용의 예시** <head> {# 주석문입니다 #} {% block header %} {% include '_common/header.html' %} {% endblock %} </head>
{# . . . #} 사용의 예시
<head>
{# 주석문입니다 #}
{% block header %}
{% include '_common/header.html' %}
{% endblock %}
</head>
필터 사용의 예시
**safe의 예시** <label class="col-sm-{{ label_size }} col-form-label {% if is_required %}required{% endif %}"> {{ label|safe }} </label> **replace와 safe의 예시** {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %} **length의 예시** {%for i in range(body|length)%} {% if i == 0 %}
safe의 예시
<label class="col-sm-{{ label_size }} col-form-label {% if is_required %}required{% endif %}">
{{ label|safe }}
</label>
replace와 safe의 예시
{% else %}
{{ body[i]|replace('\n', '<br>')|safe }}
{% endif %}
length의 예시
{%for i in range(body|length)%}
{% if i == 0 %}
**if문의 구조** {% if <조건> %} <실행코드> {% elif <조건> %} <실행코드> {% else %} <실행코드> {% endif %} **if문의 예시** {% if body[i] == '' %} - {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %}
if문의 구조
{% if <조건> %}
<실행코드>
{% elif <조건> %}
<실행코드>
{% else %}
<실행코드>
{% endif %}
if문의 예시
{% if body[i] == '' %}
-
{% else %}
{{ body[i]|replace('\n', '<br>')|safe }}
{% endif %}
**for문의 구조** {% for <개별요소> in <리스트> %} <실행코드> {% endfor %} **for문의 예시** {% for body in table['tbody'] %} <tr> {% set index = body[0] %} {% for i in range(body|length) %} {% if i == 1 %} <td> <a href="{{ url_for('manager.item', id=[index]) }}"> {{ body[i] }} </a> </td> {% else %} <td> {% if body[i] == '' %} - {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %} </td> {% endif %} {% endfor %} </tr> {% endfor %}
for문의 구조
{% for <개별요소> in <리스트> %}
<실행코드>
{% endfor %}
for문의 예시
{% for body in table['tbody'] %}
<tr>
{% set index = body[0] %}
{% for i in range(body|length) %}
{% if i == 1 %}
<td>
<a href="{{ url_for('manager.item', id=[index]) }}">
{{ body[i] }}
</a>
</td>
{% else %}
<td>
{% if body[i] == '' %}
-
{% else %}
{{ body[i]|replace('\n', '<br>')|safe }}
{% endif %}
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
css 나, 자바스크립트를 가져오는 header의 부분이나 상단의 navigation 부분, 하단의 footer 부분이 그러한데 일일히 모든 템플릿에 넣어 주기는 힘들다. 그래서 jinja2 에서는{% include %} 를 통해서 하나의 html 에서 다른 html 을 가져 올 수 있도록 해준다. 단순히 가져오는 것이라고 생각 할 수 있지만 내부적으로는 랜더링된 결과를 리턴한다고 한다.
리스트의 형태로 template를 지정할 수 있다. 첫번째 HTML파일을 찾지 못하면 두번째 HTML 파일을 보여주고 두번째 파일도 없고 ignore missing 이라는 옵션이 켜져있으면 에러를 내뱉지 않는다.
{% include ['첫번째.html', '두번째.html'] %} {% include ['첫번째.html', '두번째.html'] ignore missing %}
{% include ['첫번째.html', '두번째.html'] %}
{% include ['첫번째.html', '두번째.html'] ignore missing %}
flask 템플릿은 계층 구조를 지원한다. 하나의 웹사이트는 일반적으로 동일한 테마를 갖는다. 각각의 페이지는 동일한 구성요소를 갖는데 이를 매번 html 파일에 삽입하게 되면 구성요소를 변경할 때, 모든 파일에 수정사항을 반영해야 한다.
사용되는 동일한 구성요소는 base.html파일에 넣어두고, 나머지 페이지들은 이를 상속(extends) 받아서 사용하도록 하였다. 이를 통해 base.html 파일 하나를 변경함으로써 전 페이지에 변경사항을 적용할 수 있다.
에러에 대해 커스텀 핸들러를 제공하는 예제 코드는 아래와 같다.
**기본형태** @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404
아래는 BS Traders의 응용코드의 예시이다. 404.html을 만들어 404에러시 띄울 수 있다.
**응용 형태** @web.app_errorhandler(404) def page_not_found(e): if request.accept_mimetypes.accept_json and \\ not request.accept_mimetypes.accept_html: response = jsonify({'error': 'not found'}) response.status_code = 404 return response return render_template('error/layout.html', contents='error/404.html'), 404 **404.html** <!-- 404 Error Text --> <div class="text-center"> <div class="error mx-auto" data-text="404">404</div> <p class="lead text-gray-800 mb-5">Page Not Found</p> <p class="text-gray-500 mb-0">{{ info }}</p> <a href="/">← Back to Home</a> </div>
기본형태
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
응용 형태
@web.app_errorhandler(404)
def page_not_found(e):
if request.accept_mimetypes.accept_json and \
not request.accept_mimetypes.accept_html:
response = jsonify({'error': 'not found'})
response.status_code = 404
return response
return render_template('error/layout.html',
contents='error/404.html'), 404
404.html
<!-- 404 Error Text -->
<div class="text-center">
<div class="error mx-auto" data-text="404">404</div>
<p class="lead text-gray-800 mb-5">Page Not Found</p>
<p class="text-gray-500 mb-0">{{ info }}</p>
<a href="/">← Back to Home</a>
</div>
url_for()
템플릿에 직접 링크하는 것 처럼 URL을 작성하는 것은 간단한 라우팅 방법이지만 , 이는 원하지 않는 의존성을 생성하여 링크가 깨질 수 있다. 이러한 문제를 해결하기 위해 플라스크에서는 url_for() 헬퍼 함수를 제공하여 애플리케이션 URL맵에 저장된 정보를 통해 URL을 생성한다.
**기본형태** url_for('index') # '/' url_for('index', _external=True) # '<http://localhost:5000>' url_for('user', name='john', _external=True) # '<http://localhost:5000/user/john>' url_for('index', page=2) # '/?page=2' **예시** <form method="post" action="{{ url_for('buyer.new') }}"> ***정적인 파일도 url_for()을 사용해 불러 올 수 있다.** <link href="{{ url_for('static', filename='vendor/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet">
기본형태
url_for('index') # '/'
url_for('index', _external=True) # 'http://localhost:5000'
url_for('user', name='john', _external=True) # 'http://localhost:5000/user/john'
url_for('index', page=2) # '/?page=2'
예시
<form method="post" action="{{ url_for('buyer.new') }}">
*정적인 파일도 url_for()을 사용해 불러 올 수 있다.
<link href="{{ url_for('static', filename='vendor/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet">
위의 만화에 대해 설명하자면, 저 학교에서 입력한 명령은 다음과 같을 것이다.
여기서 "Robert'); DROP TABLE students;--"학생을 "학생 이름" 자리에 넣을 경우 다음과 같은 명령문이 된다.
첫 번째 줄에서는 Robert라는 학생이 입력되었지만, 두 번째 줄에서 학생들의 데이터가 있는 테이블을 제거한다. 그리고 세 번째에서는 뒤에 오는 내용을 모두 주석 처리한다. 결과적으로 ‘모든 학생 기록을 삭제한다.’라는 뜻의 명령문이 완성된다.
다음의 사례가 대표적인 취약점 사례이다.
사용자 인증 정보가 저장될 때 해시 혹은 암호화를 사용하여 보호되지 않을 때
세션 ID가 성공적인 로그인 이후에 교체되지 않을 때
아이디, 비밀번호, 세션 ID 등이 암호화되지 않은 연결을 통해서 전송될 때
세션 ID가 URL에 노출될 때
다음 사례가 대표적인 취약점 사례이다.
SQL> CREATE **UNIQUE** INDEX idx_ukempno_emp ON emp(empno);
SQL> CREATE INDEX idx_ukempno_emp ON emp(empno);
SQL> CREATE INDEX idx_dept_com ON index_dept(deptno, dname);
SQL> CREATE INDEX idx_annsal_emp ON emp(sal*12);
- 인덱스 설계시 중요한 두 가지 선택 기준 1. 조건절에 항상 사용되거나, 자주 등장하는 컬럼들을 선정한다. 2. '='조건으로 자주 조회되는 칼럼들을 앞쪽에 둔다.
수행할 때 참조하는 테이블의 순서가
FROM A INNER JOIN B
일 때, 조인 작업을 위해 먼저 A테이블을 읽고 B 테이블을 읽는 작업을 수행한다면 조인 순서는 A -> B이다.
(논리적으로 가능한 조인순서는 n! 만큼 존재, n 은 FROM 절 다음에 나온 테이블 수)
두 개의 테이블을 조인할 때 사용할 수 있는 방법
NL Join, Hash Join, Sort Merge Join 등이 존재
하나의 테이블을 액세스할 때 사용할 수 있는 방법
인덱스를 이용하는 인덱스 스캔(Index Scan)과 테이블 전체를 모두 읽는 전체 테이블 스캔(Full Table Scan) 등이 존재
옵티마이저가 실행계획의 각 단계마다 예상되는 비용 사항을 표시한 것
최적화 정보에는 Cost, Card, Bytes가 존재
Cost : 상대적인 비용 정보
Card : Cardinality의 약자로서 주어진 조건을 만족한 결과 집합 혹은 조인 조건을 만족한 결과 집합의 건수를 의미
Bytes: 결과 집합이 차지하는 메모리 양을 바이트로 표시한 것
여러 가지 조작을 통해서 원하는 결과를 얻어내는 일련의 작업
연산에는 조인 기법, 액세스 기법, 필터, 정렬, 집계, 뷰 등 다양한 종류가 존재
SW 테스트 방법론 (0) | 2020.08.10 |
---|---|
웹개발2 (0) | 2020.08.10 |
웹개발 (0) | 2020.08.10 |
파이썬 개발 (0) | 2020.08.10 |
[기술면접] 데브옵스 (0) | 2020.07.31 |
기존의 웹브라우저는 전자 문서를 염두에 두고 고안된 시스템이기 때문에 내용이 바뀌면 페이지 새로고침을 해서 내용을 새롭게 변경해야 되는 정적인 시스템이였다.
그러다 Ajax 개념이 도입되면서 모든 것이 바뀌었다. Ajax는 웹브라우저와 웹서버가 내부적으로 데이터 통신을 하게 된다. 그리고 변경된 결과를 웹페이지에 프로그래밍적으로 반영함으로써 웹페이지의 로딩 없이 서비스를 사용할 수 있게 한다.
Ajax는 Asynchronous JavaScript and XML의 약자다. 한국어로는 비동기적 자바스크립트와 XML 정도로 직역할 수 있는데 자바스크립트를 이용해서 비동기적으로 서버와 브라우저가 데이터를 주고 받는 방식을 의미한다. 이 때 사용하는 API가 XMLHttpRequest이다. 그렇다고 꼭 XML을 사용해서 통신해야 하는 것은 아니다. 사실 XML 보다는 JSON을 더 많이 사용한다.
RESTful은 위의 제약 조건의 집합(아키텍처 스타일, 아키텍처 원칙)을 모두 만족하는 것을 의미한다.
REST라는 아키텍처 스타일이 있는거고 RESTful API라는 말은 REST 아키텍처 원칙을 모두 만족하는 API라는 뜻이다.
서브쿼리의 반환값에 따른 서브쿼리
단일 행 서브쿼리 : 서브쿼리의 결과가 1행
다중 행 서브쿼리 : 서브쿼리의 결과가 여러 행
다중 컬럼 서브쿼리 : 서브쿼리의 결과가 여러 컬럼
두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색한다.
보통 primary key 혹은 Foreign key로 두 테이블을 연결한다.
연결하려면 적어도 하나의 컬럼은 서로 공유 되고 있어야한다.
교집합. 기존 테이블과 조인한 테이블의 중복 값을 보여주는데 결과값은 교집합만 검색
Sele
ct <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Inner Join <조인테이블 별칭> On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> 예) Select A.NAME, B.AGE From EX_TABLE A Inner Join JOIN_TABLE B On A.NO_EMP = B.NO_EMP And A.NO_DEPT = B.NO_DEPT
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Inner Join <조인테이블 별칭>
On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
예)
Select
A.NAME, B.AGE From EX_TABLE A
Inner Join JOIN_TABLE B
On A.NO_EMP = B.NO_EMP
And A.NO_DEPT = B.NO_DEPT
기존 테이블 값 + 교집합
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Left Outer Join <조인테이블 별칭> On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> 예) Select A.NAME, B.AGE From EX_TABLE A Left Outer Join JOIN_TABLE B On A.NO_EMP = B.NO_EMP And A.NO_DEPT = B.NO_DEPT
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Left Outer Join <조인테이블 별칭>
On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
예)
Select
A.NAME, B.AGE From EX_TABLE A
Left Outer Join JOIN_TABLE B
On A.NO_EMP = B.NO_EMP
And A.NO_DEPT = B.NO_DEPT
합집합
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Full Outer Join <조인테이블 별칭> On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> 예) Select A.NAME, B.AGE From EX_TABLE A Full Outer Join JOIN_TABLE B On A.NO_EMP = B.NO_EMP And A.NO_DEPT = B.NO_DEPT
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Full Outer Join <조인테이블 별칭>
On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
예)
Select
A.NAME, B.AGE From EX_TABLE A
Full Outer Join JOIN_TABLE B
On A.NO_EMP = B.NO_EMP
And A.NO_DEPT = B.NO_DEPT
모든 경우의 수(N*M)
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Cross Join <조인테이블 별칭> 예) Select A.NAME, B.AGE From EX_TABLE A Cross Join JOIN_TABLE B
Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Cross Join <조인테이블 별칭>
예)
Select
A.NAME, B.AGE From EX_TABLE A
Cross Join JOIN_TABLE B
하나의 테이블을 여러번 복사해서 조인
Select <별칭.칼럼>, <별칭.칼럼> From <테이블명 별칭1>, <테이블명 별칭2>
Select <별칭.칼럼>, <별칭.칼럼> From <테이블명 별칭1>, <테이블명 별칭2>
MySQL: CREATE TABLE Orders ( OrderID int NOT NULL, OrderNumber int NOT NULL, PersonID int, PRIMARY KEY (OrderID), FOREIGN KEY (PersonID) REFERENCES Persons(PersonID) ); SQL Server / Oracle / MS Access: CREATE TABLE Orders ( OrderID int NOT NULL PRIMARY KEY, OrderNumber int NOT NULL, PersonID int FOREIGN KEY REFERENCES Persons(PersonID) );
MySQL:
CREATE TABLE Orders (
OrderID int NOT NULL,
OrderNumber int NOT NULL,
PersonID int,
PRIMARY KEY (OrderID),
FOREIGN KEY (PersonID) REFERENCES Persons(PersonID)
);
SQL Server / Oracle / MS Access:
CREATE TABLE Orders (
OrderID int NOT NULL PRIMARY KEY,
OrderNumber int NOT NULL,
PersonID int FOREIGN KEY REFERENCES Persons(PersonID)
);
SW 테스트 방법론 (0) | 2020.08.10 |
---|---|
웹개발3 (0) | 2020.08.10 |
웹개발 (0) | 2020.08.10 |
파이썬 개발 (0) | 2020.08.10 |
[기술면접] 데브옵스 (0) | 2020.07.31 |
HTTP 프로토콜을 이용하게 되는 웹 사이트에서는 웹 페이지에 특정 방문자가 머무르고 있는 동안에 그 방문자의 상태를 지속시키기 위해 쿠키와 세션을 이용한다.
예) 안녕하세요 %ec%95%88%eb%85%95%ed%95%98%ec%84%b8%ec%9a%94
{ "name": "식빵", "family": "웰시코기", "age": 1, "weight": 2.14 }
웹개발3 (0) | 2020.08.10 |
---|---|
웹개발2 (0) | 2020.08.10 |
파이썬 개발 (0) | 2020.08.10 |
[기술면접] 데브옵스 (0) | 2020.07.31 |
[기술면접] 운영체제 (0) | 2020.07.31 |