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

  Products 메뉴에서 해당 메뉴 선택

 

윈도우 bit 확인하는 법 ->  속성을 눌러준다.
아래로 내려가 윈도우에서 파이썬 3버전을 다운로드 받아준다.(파이썬 2와 파이썬 3은 문법이 조금 다르다.)

 

다운 받은 실행파일 실행

 

전체 피씨에서 아나콘다를 사용할 수 있도록 하는 옵션을 선택한다.
설치 완료 후 윈도우에서 아나콘다 네이게이터를 실행한다.

 

주피터 노트북 런치를 눌러서 실행한다.(실행되는데 시간이 걸리는 편)

 

 

주피터 노트북 실행시 브라우저에서 확인 할 수 있다.

www.businessplus.co.kr/

로그인 페이지
네비바와 리스트페이지
토글형 메뉴 게시판
토글형 상세게시판과 리스트게시판
갤러리형 게시판

 

글쓰기 페이지
상세보기 페이지
수정게시판
배너 페이지 수정 게시판(수정만 가능)
테이블 
공지사항 테이블
미디어/갤러리 테이블
배너 테이블
로그인 테이블

 

vue 리스트 게시판 모습
새로운 사용자를 추가시 모달창을 불러온다.
DB저장 성공시 뜨는 메세지.(오류 메세지로 출력가능)

 

수정시 모달창이 뜨면서 수정 가능
성공시 뜨는 메세지(오류 메세지도 출력가능)
유저 삭제시 뜨는 모달창
성공시 뜨는 메시지(오류도 출력가능)

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> &nbsp;  &nbsp; 새롭게 추가
            </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">&times;</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">&times;</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 ">&times;</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> &nbsp;&nbsp;&nbsp;&nbsp;
                        <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);
    
?>

서버의 내부 동작 방법

아파치(Apache) 개요

www.apache.org/

 

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

  • 오픈 소스 라이선스에 따라 배포되어 마음대로 쓸 수 있는 HTTP 웹 서버
  • 웹 서버 : 80번 포트로 클라이언트의 요청(POST,GET,DELETE)을 기다리고 요청에 대한 데이터를 만들어서 응답하는 역할. 이때 데이터는 정적인 데이터(html, css, 이미지등)로 한정 된다.
  • 스레드/프로세스 기반 구조

톰캣(Tomcat) 개요

tomcat.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

  • **dynamic(동적)**인 웹을 만들기 위한 웹 컨테이너, 서블릿 컨테이너라고 불리며, 웹서버에서 정적으로 처리해야할 데이터를 제외한 JSP, ASP, PHP 등은 웹 컨테이너(톰캣)에게 전달한다.
  • WAS(Web Application Server)
    • 컨테이너, 웹 컨테이너, 서블릿 컨테이너라고 부름
    • JSP,서블릿처리,HTTP요청 수신 및 응답
    • 아파치만 쓰면 정적인 웹페이지만 처리하므로 처리속도가 매우 빠르고 안정적이다.

하지만 톰캣(WAS)를 쓰면 동적인 데이터 처리가 가능하다. DB연결,데이터 조작, 다른 응용프로그램과 상호 작용이 가능하다. 톰캣은 8080포트로 처리한다

아파치 톰캣(Apache+Tomcat) 개요

  • 톰캣이 아파치의 기능 일부를 가져와서 제공해주는 형태이기 때문에 같이 합쳐서 부른다.

아파치 톰캣의 처리방법

  • 아파치와 톰캣을 같이 쓰면 아파치는 정적인 데이터만 처리하고, JSP 처리는 Web Container(톰캣의 일부)로 보내주어 분산처리 할 수 있다.

엔진엑스(NGINX) 개요

nginx.org/en/

 

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

  • 차세대 웹서버

더 적은 자원으로 더 빠르게 데이터를 서비스 할 수 있다.

  • 동시접속 처리에 특화 된 웹서버 프로그램이다. 아파치보다 동작이 단순하고, 전달자 역할만 하기 때문에 동시접속 처리에 특화 되어있다.
  • 동시접속자(약 700명) 이상이라면 서버를 증설하거나 Nginx 환경을 권장한다고 한다. 지금은 아파치가 시장 점유율이 압도적(?)이지만, 아마존웹서비스(AWS) 상에서는 시장 점유율 44%에 달할정도로 가볍고, 성능이 좋은 엔진이라고 한다.
  • Nginx는 비동기 처리 방식(Event-Drive) 방식을 채택하고 있다.
    • 동기(Synchronous) : A가 B에게 데이터를 요청했을 때, 이 요청에 따른 응답을 주어야만 A가 다시 작업 처리가 가능 (하나의 요청, 하나의 작업에 충실)
    • 비동기(Asynchronous) : A의 요청을 B가 즉시 주지 않아도, A의 유휴시간으로 또 다른 작업 처리가 가능한 방식

NGINX와 Apache의 관계

  • 아파치는 오픈소스이고, 무료로 사용할 수 있는 소프트웨어이기에 웹을 지탱하고 있다고 할 수 있다 하지만, 아파치는 오래전에 만들어진 소프트웨어이기에 과거의 요구사항과 새로운 요구사항간의 충돌하는 것이 있다.
  • 엔진엑스는 새로운 시대의 요청에 부응해서 만들어진 웹서버이다. 개발의 모든 목적이 높은 성능에 맞춰져있다. 잘 사용하지 않는 기능은 과감하게 제외했다. 덕분에 폭팔적인 증가세에 있는 인터넷 서비스를 지탱하는데 적합하다.

참고 자료 링크

opentutorials.org/module/384/3462

 

NGINX 소개 - NGINX

Web 웹이란 World Wide Web의 약자로 인터넷이라는 네트워크 체계 위에서 동작하는 통신 규약 중의 하나다. 아래의 그림은 인터넷과 웹의 관계를 보여준다. 웹이 인터넷과 같은 의미처럼 사용된 이유

opentutorials.org

whatisthenext.tistory.com/123

 

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

 

 

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

 

개념 정의

  • 소프트웨어의 기획 의도나 목적에 따라 올바르게 구동하는가를 테스팅하여 제품의 이슈와 결함을 발견하고 제품의 품질을 높이는 것
  • 단계 : 테스트 계획 수립 > 분석 > 테스트케이스 작성 > 시행

테스트 분류

블랙박스 테스트 설명

소프트웨어의 내부 구조나 작동 원리를 모르는 상태에서 동작을 검사하는 방식이다.

사용자가 직접 특정 App이나 Device를 가지고 이리저리 작동시키는 과정이 블랙박스 테스트와 동일하다.

즉, 내부에 어떤 내용이 있는지 하나도 모른 채, 내가 원하는 기능이 예측한대로 정상 동작 하는지를 확인하는 방식이다.

즉, 사용자가 소프트웨어 또는 제품에 대한 요구사항과 결과물이 일치하는 지 확인하기 위한 테스트 기법

(사용자 관점의 테스트 방법)

화이트박스 테스트 설명

응용 프로그램의 내부 구조, 동작을 디테일하게 검사하는 테스트 방식이다.

디테일하게라는 의미는 내부 소스 코드를 테스트 하는 기법이며 사용자가 들여다 볼 수 없는 구간의 코드 단위들을 테스트 할 수 있다.(ex : private variable or method etc...)

즉, 개발자가 소프트웨어 또는 컴포넌트 등의 로직에 대한 테스트를 수행하기 위해 설계 단계에서 요구된 사항을 확인하는 테스트 기법 (개발자 관점의 단위 테스팅 기법)

블랙박스 테스트 vs 화이트박스 테스트

':: IT > 기술면접' 카테고리의 다른 글

웹개발3  (0) 2020.08.10
웹개발2  (0) 2020.08.10
웹개발  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31

Jinja2의 정의

  • Jinja2는 파이썬에서 가장 많이 사용되는 템플릿 엔진 중 하나입니다. Django의 템플릿 시스템에서 영감을 얻었지만 템플릿 작상자에게 더 강력한 도구 세트를 제공하는 표현 언어로 확장했습니다. 또한 보안이 중요한 애플리케이션을 위해 샌드박스 실행 및 선택적 자동 이스케이프를 추가합니다.

Flask 템플릿 렌더링 방법

  • 기본적으로 Flask는 애플리케이션 폴더 안에 위치한 templates 서브폴더에서 템플릿을 검색한다.
  • 그 곳에 위치한 HTML 파일을 이용하여 렌더링 한다.

**예제 코드** 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)

템플릿 엔진의 정의

  • 서버에서 받아온 데이터를 효과적으로 보여줄 중간 매체
  • 템플릿 엔진을 사용하면 비교적 간략한 표현(조건문, 변수 , 반복문)을 통해 효과적으로 데이터를 가공하여 웹페이지를 보여 줄 수 있다.

템플릿 엔진 설명의 예시

 

템플릿 엔진을 사용하는 이유

  1. 재사용성이 높다.

    웹페이지 혹은 웹앱을 만들 때 똑같은 디자인의 페이지에서 보이는 데이터만 바뀌는 경우가 많다.한 페이지를 템플릿 엔진 문법으로 만들어 놓고 여기에 데이터를 바꿔가면서 렌더링을 해주면 수 백의 페이지들을 나타낼수 있다.

  2. 유지보수에 용이하다

    템플릿 엔진을 사용하면 동일한 템플릿을 사용한다는 전제하에 템플릿과 넘겨주는 데이터만 수정하면 된다.

  3. 코드를 많이 줄일 수 있다.

    대부분의 템플릿 엔진은 기존의 HTML에 비해서 간단한 문법을 사용한다. 코드가 길어지면 길어질 수록 템플릿 엔진을 사용하면 좋다.

템플릿 사용의 예시

 

Jinja2의 기본 문법

{{ . . . }}

변수 나 표현식

**{{ . . . }} 사용의 예시** **변수의 예시** {% 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>

필터

  • Jinja2는 어떠한 타입의 변수라도 인식한다. (예 :리스트, 딕셔너리, 오브젝트 등)
  • 변수는 필터를 사용하여 수정 할 수 있으며 | 기호를 분리자로 하여 추가한다.

필터 관련 정보

필터 사용의 예시

**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문의 구조** {% 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문의 구조** {% 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 %}

include

css 나, 자바스크립트를 가져오는 header의 부분이나 상단의 navigation 부분, 하단의 footer 부분이 그러한데 일일히 모든 템플릿에 넣어 주기는 힘들다. 그래서 jinja2 에서는{% include %} 를 통해서 하나의 html 에서 다른 html 을 가져 올 수 있도록 해준다. 단순히 가져오는 것이라고 생각 할 수 있지만 내부적으로는 랜더링된 결과를 리턴한다고 한다.

  • include의 다른 형태

리스트의 형태로 template를 지정할 수 있다. 첫번째 HTML파일을 찾지 못하면 두번째 HTML 파일을 보여주고 두번째 파일도 없고 ignore missing 이라는 옵션이 켜져있으면 에러를 내뱉지 않는다.

{% include ['첫번째.html', '두번째.html'] %} {% include ['첫번째.html', '두번째.html'] ignore missing %}

{% include ['첫번째.html', '두번째.html'] %}

{% include ['첫번째.html', '두번째.html'] ignore missing %}

 

block/extends(템플릿의 상속)

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="/">&larr; 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="/">&larr; 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">

 

물리계층(Layer 1)

  • 물리적 매체를 통해서 데이터 비트를 전송하기 위해 요구 되는 기능들을 정의하며 케이블 연결 장치 등 전송에 필요한 두 장치 간의 실제 접촉과 같은 기계적, 전기적 특성에 대한 규칙을 정의 한다.
    • 전송 단위 : 프레임(Frame) 프로토콜 : 이더넷, MAC, PPP 등 장비 : 브릿지 스위치

데이터 링크 계층(Layer 2)

  • 두 개의 개방 시스템들 간의 효율적이고 신뢰성 있는 정보 전송을 할 수 있도록 하며 오류의 검출과 회복을 위한 오류 제어 기능을 수행한다. 또한, 송신측과 수신측의 속도 차이를 해결하기 위해 흐름 제어(stop-and-wait & sliding window 방식으로 처리할 수 있는 패킷의 양보다 많은 경우) 기능을 하며 프레임의 시작과 끝을 구분하기 위한 프레임의 동기화 기능을 수행한다.
    • 전송단위 : 프레임(Frame) 프로토콜 : 이더넷, MAC, PPP 등 장비 : 브릿지, 스위치

네트워크 계층(Layer 3)

  • 다중 네트워크 링크에서 발신자로부터 목적지까지 책임을 가진다. 이전 계층인 데이터 계층은 노드 vs 노드 전달을 감독하는 것이고 네트워크 계층은 시작점에서 목적지까지 성공적으로 전달 되도록 하는 역할을 수행한다.
    • 전송단위 : 패킷(Packet) 프로토콜 : IP, ICMP 등 장비 : 라우터, L3 스위치

전송 계층(Layer 4)

  • 전체 메시지를 종단 vs 종단(End-to-End, 발신지에서 목적지)간 제어와 에러를 관리한다. 패킷의 전송이 유효한지 확인하고 전송에 실패된 패킷을 다시 보내는 것과 같은 신뢰성있는 통신을 보장한다. 주소 설정, 오류 및 흐름 제어, 다중화를 수행한다.
    • 전송단위 : 세그먼트(Segment) 프로토콜 : TCP, UDP 등 장비 : 게이트웨이, L4 스위치

세션 계층(Layer 5)

  • 양 끝단의 응용 프로세스가 통신을 관리하기 위한 방법을 제공한다. 동시송수신(Duplex), 반이중(Half-Duplex), 전이중(Full-Duplex) 방식의 통신과 함께 체크 포인팅과 유후, 종료, 다시 시작 과정 등을 수행한다. 통신 세션을 구성하며 포트 번호를 기반으로 연결한다.
    • 프로토콜 : NetBIOS, SSH, TLS

표현 계층(Layer 6)

  • 응용 계층으로부터 받은 데이터를 하위 계층인 세션 계층에 보내기 전에 통신에 적당한 형태로 변환하고 세션 계층에서 받은 데이터는 응용 계층에 맞게 변환하는 역할을 수행한다. 코드 변환, 구문 검색, 데이터 압축 및 암호화 등의 기능을 담당한다.
    • 프로토콜 : JPG, MPEG, SMB, AFP

응용 계층(Layer 7)

  • 응용 프로세스와 직접 관계하여 일반적인 응용 서비스를 수행한다. 응용 프로세스 간의 정보 교환, 전자메일, 파일전송 등의 서비스를 제공한다.
    • 프로토콜 : DNS, FTP, HTTP
  •  

HTTPS 프로토콜이란?

  • 웹 브라우저와 웹서버 간에 메세지 교환 프로토콜. 즉, 일종의 대화 규칙이며, 교환 방식은 복잡한 바이너리 데이터가 아닌 단순 텍스트를 통해 이루어진다.
  • HTTP의 취약점(보안문제)을 보완하기 위해 주고받는 모든 메시지를 SSL 프로토콜로 암호화하며, 암호화 방식에 쓰이는 Key의 종류로는 크게 대칭과 비대칭 둘로 나뉘게 된다.

대표적인 웹 보안 취약점


1. 인젝션(Injection)

  • SQL 인젝션, OS 인젝션 등의 취약점은 신뢰할 수 없는 데이터가 서버로 전달되는 명령어의 일부로서 보내질 때 발생할 수 있다. 공격자의 악의적인 데이터는 예상하지 못하는 결과를 초래할 수 있다. 예를 들어 데이터베이스에서 회원 정보를 전부 가져오도록 인젝션을 날릴 수도 있다.
  •  

위의 만화에 대해 설명하자면, 저 학교에서 입력한 명령은 다음과 같을 것이다.

INSERT INTO students (이름) VALUES ('학생 이름');

여기서 "Robert'); DROP TABLE students;--"학생을 "학생 이름" 자리에 넣을 경우 다음과 같은 명령문이 된다.

INSERT INTO students (이름) VALUES ('Robert');DROP TABLE students;--');

첫 번째 줄에서는 Robert라는 학생이 입력되었지만, 두 번째 줄에서 학생들의 데이터가 있는 테이블을 제거한다. 그리고 세 번째에서는 뒤에 오는 내용을 모두 주석 처리한다. 결과적으로 ‘모든 학생 기록을 삭제한다.’라는 뜻의 명령문이 완성된다.

  • 인젝션 공격 같은 경우는 공격 난이도가 낮은 데 반해서 공격 피해가 심각하다는 점에서 굉장히 중요하다.

2. 인증 및 세션관리 취약점

  • 인증이나 세션 관리가 제대로 되어 있지 않은 웹 애플리케이션의 경우 공격자에게 취약한 세션 값을 제공하여 다른 사람의 권한을 얻도록 할 수 있다. 예를 들어 인증 관리에서 실수를 하여 쿠키 값을 변조했더니 다른 사람의 아이디로 로그인이 되거나 하는 경우가 실제로도 비일비재한다. 다른 사용자의 권한을 얻을 수 있다는 점에서 개인 정보 등의 측면에서 굉장히 위협적인 공격이 될 수 있다.

다음의 사례가 대표적인 취약점 사례이다.

  1. 사용자 인증 정보가 저장될 때 해시 혹은 암호화를 사용하여 보호되지 않을 때

  2. 세션 ID가 성공적인 로그인 이후에 교체되지 않을 때

  3. 아이디, 비밀번호, 세션 ID 등이 암호화되지 않은 연결을 통해서 전송될 때

  4. 세션 ID가 URL에 노출될 때

  • 예를 들어 URL에 자신의 세션 ID가 그대로 노출되어 있는 상황이지만 클라이언트는 이를 인지하지 못하고 친구에게 해당 URL 정보를 보낼 수 있습니다. 이 때 친구는 URL을 확인하고 해당 세션으로 로그인을 할 수도 있는 것이다.
  • 공격의 난이도는 평균적인 수준이지만 영향도는 인젝션(Injection) 공격과 마찬가지로 심각한 수준에 이른다.

3. 크로스 사이트 스크립팅(XSS)

  • XSS 공격은 웹 사이트에서 서버와 통신하는 부분에서 스크립트 문장을 심어서 공격을 하는 해킹 유형이다. 대표적으로 게시판의 게시글을 작성했을 때 서버 단에서 사용자가 입력한 게시글의 정보를 제대로 필터링 하지 않거나 아예 필터링을 하지 않는 경우 다양한 특수 문자를 포함한 스크립트 문장을 심어서 서버로 전송할 수 있다. 이러한 방법을 악용하여 다양한 공격이 가능하다.

다음 사례가 대표적인 취약점 사례이다.

**String page += request.getParameter("boardContent");**

  • 위와 같은 경우 사용자는 boardContent라는 이름의 파라미터 변수에 스크립트 문장을 심어서 전송할 수 있고 서버는 제대로 이것을 필터링하지 않기 때문에 해킹이 제대로 적용될 수 있다. 대표적인 예시로 사용자는

 

데이터베이스의 정규화와 역정규화


정규화

  • 관계형 데이터베이스의 설계에서 중복을 최소화하게 데이터를 구조화하는 프로세스를 정규화(Normalization)라고 한다.

역정규화

  • 정규화된 데이터베이스에서 성능을 개선하기 위해 사용되는 전략을 역정규화(Denormalization)라고 한다.

데이터베이스의 인덱스 종류


1. 고유 인덱스(Unique Index)

  • 고유 인덱스는 유일한 값을 갖는 컬럼에 대해서 생성하는 인덱스로 고유 인덱스를 지정하려면 UNIQUE 옵션을 지정해야 한다.

SQL> CREATE **UNIQUE** INDEX idx_ukempno_emp ON emp(empno);

2. 단일 인덱스(Single Index)

  • 단일 인덱스는 한 개의 컬럼으로 구성한 인덱스를 말한다.

SQL> CREATE INDEX idx_ukempno_emp ON emp(empno);

3. 결합 인덱스(Composite Index)

  • 결합 인덱스는 두 개 이상의 컬럼으로 인덱스를 구성하는 것을 말합니다. 부서 번호와 부서명을 결합하여 인덱스를 설정 해 보도록 하겠다.

SQL> CREATE INDEX idx_dept_com ON index_dept(deptno, dname);

4. 함수 기반 인덱스(Function Based Index)

  • 함수 기반 인덱스는 SAL*12와 같이 컬럼에 어떠한 산술식을 수행했을때를 말한다.
  • SAL컬럼에 INDEX가 걸려있다해도 SAL*12은 INDEX를 타지 못합니다. 이럴때 함수 기반 인덱스를 생성한다.

SQL> CREATE INDEX idx_annsal_emp ON emp(sal*12);

데이터베이스의 좋은 인덱스 설계란?


- 인덱스 설계시 중요한 두 가지 선택 기준 1. 조건절에 항상 사용되거나, 자주 등장하는 컬럼들을 선정한다. 2. '='조건으로 자주 조회되는 칼럼들을 앞쪽에 둔다.

데이터베이스 실행 계획이란?


실행 계획의 정의

  • 실행계획(Execution Plan)이란 SQL에서 요구한 사항을 처리하기 위한 절차와 방법을 의미한다.
  • 동일한 SQL에 대해 결과를 낼 수 있는 다양한 처리 방법(실행계획)이 존재할 수 있지만 각 처리 방법마다 실행 시간(성능)은 서로 다를 수 있다.
  • 옵티마이저는 다양한 처리 방법들 중에서 가장 효율적인 방법을 찾아준다.(최적의 실행계획을 생성)

실행 계획의 구성 요소

  1. 조인순서(Join Order)

수행할 때 참조하는 테이블의 순서가

FROM A INNER JOIN B

일 때, 조인 작업을 위해 먼저 A테이블을 읽고 B 테이블을 읽는 작업을 수행한다면 조인 순서는 A -> B이다.

(논리적으로 가능한 조인순서는 n! 만큼 존재, n 은 FROM 절 다음에 나온 테이블 수)

  1. 조인 기법(Join Method)

두 개의 테이블을 조인할 때 사용할 수 있는 방법

NL Join, Hash Join, Sort Merge Join 등이 존재

  1. 액세스 기법(Access Method)

하나의 테이블을 액세스할 때 사용할 수 있는 방법

인덱스를 이용하는 인덱스 스캔(Index Scan)과 테이블 전체를 모두 읽는 전체 테이블 스캔(Full Table Scan) 등이 존재

  1. 최적화 정보(Optimization Information)

옵티마이저가 실행계획의 각 단계마다 예상되는 비용 사항을 표시한 것

최적화 정보에는 Cost, Card, Bytes가 존재

Cost : 상대적인 비용 정보

Card : Cardinality의 약자로서 주어진 조건을 만족한 결과 집합 혹은 조인 조건을 만족한 결과 집합의 건수를 의미

Bytes: 결과 집합이 차지하는 메모리 양을 바이트로 표시한 것

  1. 연산(Operation)

여러 가지 조작을 통해서 원하는 결과를 얻어내는 일련의 작업

연산에는 조인 기법, 액세스 기법, 필터, 정렬, 집계, 뷰 등 다양한 종류가 존재

':: IT > 기술면접' 카테고리의 다른 글

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는 웹브라우저와 웹서버가 내부적으로 데이터 통신을 하게 된다. 그리고 변경된 결과를 웹페이지에 프로그래밍적으로 반영함으로써 웹페이지의 로딩 없이 서비스를 사용할 수 있게 한다.

    Ajax는 Asynchronous JavaScript and XML의 약자다. 한국어로는 비동기적 자바스크립트와 XML 정도로 직역할 수 있는데 자바스크립트를 이용해서 비동기적으로 서버와 브라우저가 데이터를 주고 받는 방식을 의미한다. 이 때 사용하는 API가 XMLHttpRequest이다. 그렇다고 꼭 XML을 사용해서 통신해야 하는 것은 아니다. 사실 XML 보다는 JSON을 더 많이 사용한다.

HTTP 프로토콜이란?


  • 인터넷상에서 데이터를 주고 받기 위한 서버/클라이언트 모델을 따르는 프로토콜(상호 간에 정의한 규칙)이다.
  • 데이터를 주고 받기 위한 각각의 데이터 요청이 서로 독립적으로 관리가 된다. 즉 이전 데이터 요청과 다음 데이터 요청이 서로 관련이 없다.
  • 이러한 특징 덕택에 서버는 세션과 같은 별도의 추가 정보를 관리하지 않아도 되고, 다수의 요청 처리 및 서버의 부하를 줄일 수 있는 성능 상의 이점이 생긴다.
  • HTTP 프로토콜은 일반적으로 TCP/IP 통신 위에서 동작하며 기본 포트는 80번이다.

HTTP 접근 제어(CORS)란?


CORS는 무엇인가?

  • 다른 도메인으로부터 요청될 경우, 일반적인 HTTP 요청이 아닌 cross-origin HTTP 요청으로 처리하게 된다.
  • 브라우저는 보안상의 이유로 cross-origin HTTP 요청을 제한하게 된다.
  • 이유는 단순히 same-origin 정책이다.
  • 이러한 불편함으로 인해, 시간이 지나 W3C에서 대안으로 CORS 메커니즘을 내놓은 것이다.

CORS는 어떻게 동작되는 건가?

  • CORS는 라이브러리 혹은 구현 기술이 아닌 방침이라고 보면된다.
  • CORS는 브라우저의 정보를 읽을 수 있도록 서버에게 알려주도록 허용하는 HTTP 헤더를 추가함으로써 동작한다.

RESTful 설계란?


REST가 무엇인가?

  • REST는 분산 시스템 설계를 위한 아키텍처 스타일이다.
  • 아키텍처 스타일이라는건 쉽게 말하면 제약 조건의 집합이라고 보면 된다.
  • REST는 URI를 통해 자원을 표시하고, HTTP METHO를 이용하여 해당 자원의 행위를 정해주며 그 결과를 받는 것을 말한다.

RESTful은 무엇인가?

RESTful은 위의 제약 조건의 집합(아키텍처 스타일, 아키텍처 원칙)을 모두 만족하는 것을 의미한다.

REST라는 아키텍처 스타일이 있는거고 RESTful API라는 말은 REST 아키텍처 원칙을 모두 만족하는 API라는 뜻이다.

SQL Subquery란?


  • 쿼리 안에 있는 쿼리. Where/From/Select 절 안에 들어가는 쿼리.
  • 서브쿼리는 하나의 쿼리문 안에 포함된 또 하나의 쿼리문으로(중첩문) 메인쿼리가 서브쿼리를 포함하는 종속적 관계
  • 문법은 서브쿼리를 괄호로 묶어서 사용한다.
  • Order By절은 사용불가하며 연산자 오른쪽에 사용해야 한다.

서브쿼리의 반환값에 따른 서브쿼리

단일 행 서브쿼리 : 서브쿼리의 결과가 1행

다중 행 서브쿼리 : 서브쿼리의 결과가 여러 행

다중 컬럼 서브쿼리 : 서브쿼리의 결과가 여러 컬럼

SQL Join의 종류


두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색한다.

보통 primary key 혹은 Foreign key로 두 테이블을 연결한다.

연결하려면 적어도 하나의 컬럼은 서로 공유 되고 있어야한다.

 

1) 이너 조인(Inner Join)

교집합. 기존 테이블과 조인한 테이블의 중복 값을 보여주는데 결과값은 교집합만 검색

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

2) 아우터 조인(Left/Right Outer Join)

기존 테이블 값 + 교집합

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

3) 풀 아우터 조인(Full Outer Join)

합집합

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

4) 크로스 조인(Cross Join)

모든 경우의 수(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 

5) 셀프 조인(Self Join)

하나의 테이블을 여러번 복사해서 조인

Select <별칭.칼럼>, <별칭.칼럼> From <테이블명 별칭1>, <테이블명 별칭2>

Select <별칭.칼럼>, <별칭.칼럼> From <테이블명 별칭1>, <테이블명 별칭2>

데이터베이스 트랜젝션이란?


  • 데이터베이스의 상태를 바꾸는 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미
  • 모든 명령어의 성공 또는 실패를 한번에 처리 흔한 예로 계좌입금에서 일어날 수 있는 오류등을 생각해보면 좋다.
  • 하나의 트랜잭션으로 관리하면 계좌에 입금하는 기능이 실패 했을 경우, 철수의 계좌에서 돈이 다시 입금되어야한다.(이를 Rollback이라고 한다.)

데이터베이스의 외래키와 무결성 제약 조건


데이터베이스의 외래키

  • 외래키는 두 테이블을 서로 연결하는 데 사용되는 키
  • 외래키가 포함된 테이블을 자식 테이블이라고 하고 외래키 값을 제공하는 테이블을 부모 테이블이라한다.

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

무결성의 제약조건

  • 개체 : 테이블에 있는 모든 행들이 유일한 식별자를 가질 것을 요구한다.(같은 값 X)
  • 참조 : 외래키 값은 NULL이거나 참조 테이블의 PK값이여야함
  • 영역 : 한 칼럼에 대해 NULL 허용 여부와 자료형 , 규칙으로 타당한 데이터 값을 지정

':: IT > 기술면접' 카테고리의 다른 글

SW 테스트 방법론  (0) 2020.08.10
웹개발3  (0) 2020.08.10
웹개발  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31

세션과 쿠키의 차이점


HTTP 프로토콜을 이용하게 되는 웹 사이트에서는 웹 페이지에 특정 방문자가 머무르고 있는 동안에 그 방문자의 상태를 지속시키기 위해 쿠키와 세션을 이용한다.

세션

  1. 특정 웹사이트에서 사용자가 머무르는 기간 또는 한명의 사용자의 한번의 방문을 의미한다.
  2. 세션에 관련된 데이터는 서버에 저장된다.
  3. 웹 브라우저의 캐시에 저정되어 브라우저가 닫히거나 서버에서 삭제 시, 사라진다.
  4. 쿠키에 비해 보안성이 좋다.

쿠키

  1. 사용자 정보를 유지할 수 없다는 HTTP의 한계를 극복 할 수 있는 방법이다.
  2. 인터넷 웹 사이트의 방문 기록을 남겨 사용자와 웹 사이트 사이를 매개해주는 정보이다.
  3. 쿠키는 인터넷 사용자가 특정 웹서버에 접속할 때, 생성되는 개인 아이디와 비밀번호, 방문한 사이트의 정보를 담은 임시파일로써, 서버가 아닌 클라이언트에 텍스트 파일로 저장되어 다음에 해당 웹서버를 찾을 경우 웹 서버에서는 그가 누구인지 어떤 정보를 주로 찾았는지 등을 파악할 때 사용 된다.
  4. 쿠키는 클라이언트 PC에 저장되는 정보이기 때문에, 다른 사용자에 의해서 임의로 변경이 가능하다.(정보유출 가능, 세션 보다 보안성이 낮은 이유)

Get과 Post의 차이점


Get

  • 클라이언트에서 서버로 데이터를 전달할 때, 주소 뒤에 "이름"과 "값"이 결합된 쿼리 스트링 형태로 전달한다.
  • 주소창에 쿼리 스트링이 그대로 보여지기 때문에 보안성이 떨어진다.
  • 길이에 제한이 있다.(전송 데이터에 한계가 있다.)
  • Post 방식보다 상대적으로 전송 속도가 빠르다.

Post

  • 일정크기 이상의 데이터를 보내야 할 때 사용한다.
  • 서버로 보내기 전에 인코딩하고, 전송 후 서버에는 다시 디코딩 작업을 한다.
  • 주소창에 전송하는 데이터의 정보가 노출 되지 않아 Get방식에 비해 보안성이 높다.
  • 속도가 Get방식보다 느리다.
  • 쿼리 스트링(문자열)데이터 뿐만 아니라, 라디오 버튼, 텍스트박스 같은 객체들의 값도 전송 가능하다.

차이점

  • Get은 주로 웹 브라우저가 웹 서버에 데이터를 요청 할 때 사용한다.
  • Post는 웹 브라우저가 웹 서버에 데이터를 전달하기 위 해 사용한다.
  • Get을 사용하면 웹 브라어저에서 웹서버로 전달되는 데이터가 인코딩 되어 URL에 붙는다.
  • Post 방식은 전달되는 데이터가 보이지 않는다.
  • Get 방식은 전달되는 데이터가 255개의 문자를 초과하면 문제가 발생할 수 있다.
  • 웹 서버에 많은 데이터를 전달하기 위해서는 Post방식을 사용하는 것이 바람직하다.

URL Encoding이란?


  • 문자나 특수문자를 웹 서버와 브라우저에서 보편적으로 허용되는 형식으로 변화하는 메커니즘이다.
  • URL은 ASCII 문자 집합을 사용하여 인터넷을 통해서만 전송할 수 있다.
  • URL은 종종 ASCII 세트 외부의 문자를 포함하기 때문에 URL은 유효한 ASCII 형식으로 변환되어야 한다.
  • URL 인코딩은 안전하지 않은 ASCII 문자를 "%" 다음에 두 개의 16진수로 대체한다.
  • URL은 공백을 포함할 수 없다. URL 인코딩은 일반적으로 공백을 더하기 (+) 기호 또는 % 20으로 바꾼다.
  • 고로, 아스키 이외의 문자는 다 인코딩 해야된다. (한글, 일본어, 중국어, 독일어, ... )

예) 안녕하세요 %ec%95%88%eb%85%95%ed%95%98%ec%84%b8%ec%9a%94

JSON이란?


  • JSON(JavaScript Object Notation)의 약자로 JavaScript에서 객체를 만들 때 사용하는 표현식을 의미한다. 이 표현식은 사람도 이해하기 쉽고 기계도 이해하기 쉬우면서 데이터의 용량이 작다. 이런 이유로 최근에는 JSON이 XML을 대체해서 설정의 저장이나 데이터를 전송등에 많이 사용된다.

{ "name": "식빵", "family": "웰시코기", "age": 1, "weight": 2.14 }

Jquery란?


  • 자바스크립트의 생산성을 향상시켜주는 자바스크립트 라이브러리이다.
  • 라이브러리란 자주 사용되는 로직들을 재활용, 유통 가능하도록 만든 로직들의 묶음을 의미합니다. 자바스크립트의 세계에는 많은 라이브러리들이 있다. prototype, jQuery, YUI 등등 구글트랜드로 검색을 해보면 현재는 jQuery가 가장 많은 사용자를 가지고 있다. jQuery를 이용하면 순수한 자바스크립트로 코딩하는 것 보다 10배 이상 생산성을 높일 수 있다. 또 jQuery는 파생된 라이브러리들을 가지고 있다. jQuery UI는 jQuery기반의 GUI 라이브러리이다. 이것을 이용해서 윈도우 에플리케이션과 같은 기능성의 UI를 만들 수 있다.
  • 최근에는 jQuery Mobile라는 이름의 모바일 라이브러리를 출시해서 모바일용 웹에플리케이션을 만드는데도 많은 도움을 주고 있다.

CSS의 미디어쿼리란?


  • 미디어 쿼리(mediaqueri)는 사이트에 접속하는 장치에 따라 특정한 CSS 스타일을 사용하도록 도와주는 소프트웨어 모듈이다. 미디어 쿼리를 이용한 사이트는 웹 사이트에 접속하는 기기에 따라서 레이아웃이 바뀌게 된다. 즉, PC로 접속하면 모니터 화면에 맞게, 스마트폰으로 접속하면 스마트폰 화면에 맞게 레이아웃이 변경되는 것이다. 웹 문서의 스타일을 정의할 때, 즉 CSS 코드를 작성할 때 미디어쿼리 모듈을 사용해 주는 것이 일반적인 사용 방법이다.

':: IT > 기술면접' 카테고리의 다른 글

웹개발3  (0) 2020.08.10
웹개발2  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31
[기술면접] 운영체제  (0) 2020.07.31

+ Recent posts