bookmark_border지식은 절대적인가, 상대적인가?

지식은 절대적인가, 상대적인가?

과거와 현재의 끊임없는 대화 : E. H. 카 : 역사란 무엇인가?(feat. 라쇼몽)

  • 역사를 바라보는 두 가지 관점
    • 절대주의적 역사관 : 과거에 있는 사실을 있는 그대로 객과적으로 기술
    • 상대주의적 역사관 : 과거에 일어난 사실을 기술할 때 자신의 주관이 들어갈 수밖에 없다
  • E.H.카의 ‘역사란 무엇인가’
    • 역사란 과거와 현재의 끊임없는 대화이다.
    • 라쇼몽(일본영화, 1950년)
      • 도적, 사무라이, 사무라이 아내, 나무꾼(목격자) 의 각각 입장에 따른 진술
      • 이 진술 중 하나만 남겨진다면 역사는 그 증언을 토대로 사건을 기록할 것임.

내 이론은 틀릴 수 없어 : 포퍼 : 반증 가능성

  • 과학을 바라보는 입장
    • 절대주의적 과학관
      • 과학적 지식은 합리적이고 객관적
      • 슐리크, 카르납, 포퍼
    • 상대주의적 과학관
      • 과학적 지식도 상대적이고 주관적
      • 헨슨, 쿤, 파이어아벤트

논리실증주의

  • 프레게와 아이슈타인에 의해 논리학, 수학, 물리학이 혁명적으로 발전하자, 이에 자극받아 슐리크, 카르납 등의 논리실증주의자들은 철학에서도 이와 같은 변화가 있어야 한다고 주장
  • 비엔나 서클
  • 경험론의 후예
  • 귀납법
    • 관찰과 경험을 통해 검증 가능한 명제만이 의미가 있고, 검증 불가능한 명제는 의미가 없다.
    • 검증 가능한 과학만이 진짜 학문이고, 검증불가능한 명제(형이상학, 윤리학, 미학, 종교)는 비과학이다.

포퍼의 반증주의

  • 논리실증주의의 두가지 문제점
    • 귀납법의 한계
      • 모든 백조는 하얗다.
    • 구획의 문제
      • 너도 나도 과학. 인문과학, 사회과학, 창조과학, 타로, 침대도 과학.
      • 검증 가능하면 모두 과학인가?
  • 포퍼
    • 오스트리아 출신 과학철학자 및 사회철학자
    • 논리실증주의에 반대
  • 과학이론은 귀납법이 아닌 가설-연역법
    • 귀납법
      • 개별사실 관찰 -> 일반화 -> 과학이론
    • 가설-연역법
      • 가설1 -> 반례1 -> 가설2 -> 반례2 -> 가설3 -> 반증되지 않을때 과학이론
      • 독일 화학자 케쿨레의 벤젠의 구조
  • 검증이 되더라도 과학이 아닐 수 있다.
    • 아들러 심리학
    • 마르크시즘
    • 사이비 과학
  • 틀릴 수 있는 가능성이 있는 이론만이 과학이론이 될 수 있다.
    • 반증 가능성
    • 포퍼의 반증주의

반증주의에 대한 반론

  • 반증할 수 없는 것 천지다
    • 확률에 대한 가설
      • 주사위를 던졌을때 3이 나올 확률은 6분의 1이다. 반증 불가
    • 존재에 대한 가설
      • 외계인이 존재하지 않는다.
    • 반증주의 자체도 반증 가능해야 한다.
  • 뒤엠-콰인 논제
    • 석촌호수 황금색 백조
    • 어떤 가설을 포기해야할지 결정 필요

공통점

  • 관찰과 경험을 통한 과학적 방법론이 친리를 찾는 가장 확실한 방법이라는 점
  • 과학이 모든 학문의 왕좌라는 점

과학, 너마저… : 토머스 쿤 : 패러다임의 전환

  • 과학을 바라보는 두가지 입장
    • 절대주의적 과학관
      • 과학적 지식은 합리적이고 객관적
    • 상대주의적 과학관
      • 과학적 지식도 주관적이고 경험적
  • 토머스 문
    • 1922~1996
    • 과학혁명의 구조
  • 아리스토텔레스는 물질은 불.공기.물.흙의 4원소로 이루어져 있고, 불과 공기의 고향은 하늘이고, 물과 흙의 고향은 땅이어서, 사과가 땅으로 떨어지는 이유는 고향인 땅으로 가려는 것이다.
    • 당시 패러다임은 ‘물질은 자기가 원래 속해 있었던 자리로 돌아가려는 성질이 있다’고 믿음.
  • 과학혁명은 종교의 개종과 같다.
  • 과학혁명이 일어나는 과정
    • 힘과 권위를 가진 나이든 과학자와 젊은 과학자
    • 나이든 과학자들이 죽으면 새로운 패러다임이 힘을 얻음.
  • 과학자들의 반격
    • 과학의 합리성을 완전히 무시
    • 쿤은 한발 물러서서 과학자들이 어느 정도 합리성을 가지고 더 우수한 패러다임을 선택

원치 않는 결과는 거부한다 : 핸슨 : 관찰의 이론 의존성

  • 오리일까, 토끼일까?
  • 관찰의 이론 의존성
    • 관찰 -> 가설 -> 실험 -> 이론
    • 관찰과 실험의 결과가 관찰자의 배경지식에 따라 왜곡될 수 있다.
    • 관찰의 이론 의존성
  • 원하지 않는 관측 결과를 거부한다.
  • 이미 관측한 결과도 왜곡한다.
    • 자동차 사고영상. 50km/h(그냥 사고) vs. 60km/h (사망한 사고)

과연 그게 당연할까? : 푸코 : 말, 지식, 광기

  • 미셸 푸코
    • 프랑스 철학자 (1926~1984)
    • 지식, 권력, 억압에 관한 많은 이론 제시
    • 지식의 문제, 권력의 문제, 종교의 문제
  • 스웨덴 린네의 생물 분류 vs. 중국 청나라의 분류

플라톤의 에피스테메

동굴안 동굴밖
현실세계
감각으로 경험하는 가시계(Visible)
사물을 눈에 비치는 대로
잘못된 인식
이데아 세계
이성으로 인식하는 가지계(Intelligible)
사물을 있는 그대로
참된 인식
독사(Doxa) 에피스테메(Episteme)
  절대적 보편적 진리

푸코의 에피스테메

  • 지식의 고고학
    • 지식도 신석기 시대에는 신석기 시대형 지식이 있었고, 청동기 시대에는 청동기 시대형, 철기 시대에는 철기 시대형 지식이 있으며, 그 지식들 사이에는 불연속적인 단절이 있었다.
    • 또한 유럽과 아시아에서 나오는 유물이 다르듯, 같은 시대라도 지역에 따라 통용되는 지식이 다르다.
  • 푸코의 시대별 구분
    • 16세기에는 ‘유사성’이라는 키워드로 지식을 구성
      • 호두를 먹으면 머리가 좋아진다.
    • 17세기 ‘표상’, 19세기 ‘주체’
    • 플라톤의 에피스테메는 절대적 지식이지만, 푸코에게 절대적 보편적 지식이나 진리는 없다.
    • 푸코의 에피스테메는 특정지역, 특정시기에 지식을 구성하는 키워드 즉 무의식적 인식체계이다.
  • 광기의 역사
    • 광기의 개념이 시대에 따라 달라졌다.
    • 주체, 이성, 합리성의 개념 등도 시대의 산물로 어느 시대나 통용되는 개념이 아니다.
    • 즉, 보편적인 것, 자연스러운 것, 우리가 당연하다고 생각하는 것들이 사실 아니다.
쿤의 패러다임 푸코의 에피스테메

과학(물리학)에 적용

과학, 철학, 문화 등 모든분야에 적용되는 인식 체계
의식적 작용 무의식 속에서 작동 (알아채지 못함)
나름 합리적 기준으로 선택 합리적 기준 없음
  • 권력의 은밀한 지배
    • 「감시와 처벌」
    • 18세기 후반 감금형과 강제노등 등이 도입
    • 죄수들은 불안과 공포를 느끼며 권력의 시선을 내면화하고 스스로 자기검열을 하게 됨
    • “감옥이 학교나 공장, 병원과 비슷하고, 이들이 감옥과 닮았다고 해서 놀라운 일인가.”
    • 우리 자신이 학교에서, 직장에서 일상생활에서조차 권력의 시선을 내면화해서 스스로 자기검열을 하고 있다는 것.

비슷한 동물끼리 묶기

고양이과 동물 vs. 사육가능한 동물

bookmark_borderOpenfire

Openfire 설치

  • 시놀로지 도커에 설치
  • gizmotronic/openfire
  • 볼륨 설정 (파일 : 마운트)
    • /volume1/docker/openfire : var/lib/openfire
    • /volume1/log/openfire : /var/log/openfire
  • 포트설정
    • 5222, 5223, 9090, 9091, 7070, 7443, 7777
9090 : http web administration
9091 : the secured administration respectively
5222 : Client Port
5223 : Client SSL Port
5269 : s2s, Remote servers can exchange packets with this server on port
5229 : for SparkWeb
7070 : HTTP binding Port
7443 : HTTP binding SSL Port
7777 : File transfer proxy
5347 : External Component
  • http://192.168.219.150:9090/
    • 관리자 계정 : admin
  • 사용자 추가 페이지
    • Registration 플러그인 추가
    • Users/Groups > Users > Registration Properties > Enable users to register via a web page at http://xmpp.kr:9090/plugins/registration/sign-up.jsp

bookmark_borderCordova Todo List

Cordova Todo List 프로젝트

mytodolist 프로젝트 생성 및 시험

D:\cordova>
> cordova create mytodolist com.example.mytodolist MyTodoList
> cd mytodolist
> cordova platform add android
> cordova run android

NodeJS 서버

index.js

var todos = [];

클라이언트

mytodolist.js

var todos = [];

$.ajax("http://localhost:3000/todos").done(function(result) {
    console.log(result);

    todos = result;
    for (const todo of todos) {
        $(".contents ul").append(liTemplate(todo.text, todo.checked));
    }
});

$("#addButton").click(function() {
    var text = $("#inputBox").val();
    todos.push({ text: text, checked: false });
    $("#inputBox").val("");
    console.log(todos);

    $(".contents ul").append(liTemplate(text, false));
    saveTodos();
});

function liTemplate(text, checked) {    
    var li = $('<li></li>');

    alert(text);
    li.attr('value', text);
    li.append(inputTemplate(text, checked));
    li.append(text);
    li.append(buttonTemplate());

    li.click(function(event) {
        var el = $(event.target);
        var index = el.index("li");
        console.log(index);
    
        if (el.is("button")) {
            todos.splice(index, 1);
            $("li")[index].remove();
        }
        else if (el.is("input[type='checkbox']")) {
            var isChecked = el.is(":checked");
            if (isChecked) {
                $($("li")[index]).addClass("checked");
                todos[index].checked = true;
            } else {
                $($("li")[index]).removeClass("checked");
                todos[index].checked = false;
            }
        }

        saveTodos();
    });    

    return li;
}

function inputTemplate(text, checked) {
    var inputTag = $('<input type="checkbox" id="checkBox">');
    inputTag.attr('checked', checked);
    return inputTag;
}

function buttonTemplate(text) {
    var buttonTag = $('<button id="delButton">X</button>');
    return buttonTag;
}

빌드 및 시험

> npm run start

npm ERR! Missing script: "start"
==>
package.json
"scripts": {
    "start": "node index.js"
  },

Error: Cannot find module 'express'
==>
> npm install -save express

> cordova run android

플러그인 설치

날짜선택 플러그인

알림 플러그인

function onSuccess(date) {
    var text = $("#inputBox").val();
    todos.push({ text: text, checked: false, date: date });
    $("#inputBox").val("");
    console.log(todos);

    $(".contents ul").append(liTemplate(text, false, date));
    saveTodos();
}

$("#addButton").click(function() {
    datePicker.show(options, onSuccess, onError);
});

bookmark_borderCordova

Cordova

  • 오픈소스 하이브리드 앱 개발 도구
  • 웹 기술을 이용해 개발
  • 윈도우, OS X, 리눅스에서 사용 가능
  • 안드로이드, iOS, Mac OS X, 윈도우 등 멀티 플랫폼 지원
  • 플러그인을 통한 확장
  • Cordova 의 한계
    • 네이티브 앱에 비해 성능이 떨어짐
    • 플러그인 개발의 어려움

Cordova의 작동원리

Cordova 개발환경

  • NodeJS / Cordova
  • 플랫폼 별 요구사항
    • 안드로이드: JDK, 안드로이드 SDK
  • JDK 다운로드 및 설치
  • 안드로이드 스튜디오 설치
  • Cordova 설치
    • > npm install –g cordova
    • > cordova –version
  • 새 Cordova 프로젝트 생성
    • > cordova create hello com.example.hello HelloWord
    • > cd hello
  • 안드로이드 에뮬레이터 생성
    • > More Actions > Virtual Device Manager > Create virtual device > Pixcel2 > download >
    • > cordova platform add android@8.0.0
    • > cordova run android
      • Android SDK의 경로를 찾지 못하는 문제
        • ANDROID_SDK_ROOT=undefined (recommended setting)
        • > More Actions > SDK Manager > Android SDK Location 확인
        • set ANDROID_SDK_ROOT=C:\Users\user\AppData\Local\Android\Sdk
      • Gradle 을 찾지 못하는 문제
      • javac 를 찾지 못하는 문제
        • Failed to run “javac -version”, make sure that you have a JDK version 8 installed.
        • set PATH=%PATH%;C:\SDK\jdk1.8.0_321\bin;
    • Android Emulator가 띄워져 있는 상태에서 실행
    • 영구적 PATH 등록 : 설정 > 정보 > 고급 시스템 설정 > 환경 변수 > 시스템 변수 > path 에 추가
      • C:\SDK\gradle-7.2\bin
      • C:\SDK\jdk1.8.0_321\bin

코도바 플러그인 설치 및 사용

Cordova 플러그인 설치

Cordova 플러그인

  • NodeJS 의 NPM 과 같이 Cordova 의 기능을 확장
  • 웹 앱에서 OS 기능을 사용하려면 플러그인이 필요
  • OS 종속 코드와 자바스크립트 인터페이스로 이루어짐

Cordova 플러그인 설치 및 삭제

Cordova 배터리 상태 플러그인

  • 디바이스의 배터리 잔량 확인
    • batterystatus 이벤트 -> status.level
  • 디바이스의 충전상태 확인
    • batterystatus 이벤트 -> status.isPlugged
  • 디바이스의 배터리 경고 확인
    • batterylow 이벤트
    • batterycritical 이벤트
  • 플러그인 설치
    > cordova plugin add –save cordova-plugin-battery-status

index.html

    <body>
        <div>
            <span id="battery">100</span>%
        </div>
        <script src="cordova.js"></script>
        <script src="js/jquery-3.4.1.min.js"></script>
        <script src="js/index.js"></script>
    </body>

deviceready 이벤트

  • Cordova 플러그인이 모두 로드 된 후 발생
  • window.addEventListener 함수를 통해 등록
  • 플러그인은 deviceready 이벤트 발생 이후 사용하여야 함

index.js

var battery = $("#battery");

window.addEventListener('deviceready', function() {
    window.addEventListener('batterystatus', function(status) {
        battery.text(status.level);
    }, true);
}, true);
  • Virtual Device Manager > AVD 실행
  • > cordova run android

Cordova 카메라 플러그인

  • 디바이스의 카메라로 사진을 찍어 불러오기
  • 디바이스의 이미지 라이브러리에서 사진 불러오기
    • getPicture 함수
      camera.getPicture(success, error, options)
      • success : 사진을 불러오는데 성공했을 때 실행되는 콜백함수
      • error : 사진 불러오기에 실패했을 때 실행되는 콜백함수
      • options : 사진을 가져오기 위한 option 객체
  • 카메라 플러그인 설치
    > cordova plugin add –save cordova-plugin-camera
  • 설치 플러그인 확인
    > cordova plugin list
        <button id="btnTakePic">사진 찍기</button>
        <button id="btnLoadPic">사진 불러오기</button>
        <div>
            <img id="image"/>
        </div>

index.js

var battery = $("#battery");
var image = $("#image");

options = {
    quality: 80,
    correctOrientation: true
}

window.addEventListener('deviceready', function() {
    window.addEventListener('batterystatus', function(status) {
        battery.text(status.level);
    }, true);

    $("#btnTakePic").click(load(1));
    $("#btnLoadPic").click(load(2));
}, true);

function load(sourceNum) {
    return function() {
        navigator.camera.getPicture(
            function(imageUri) {
                image.attr('src', imageUri);
            },
            function(error) {
                alert('에러발생!');
            },
            {
                sourceType: sourceNum,
                ...options,
            }
        );
    }
}

펼침연산자

            {
                sourceType: sourceNum,
                ...options,
            }
아래와 동일
            {
                sourceType: sourceNum,
                quality: 80,
                correctOrientation: true
            }
  • 배열이나 객체를 피연산자로 받음
  • 피연산자로 전달된 배열이나 객체를 펼침
  • 다른 배열이나 객체에 값을 복사해 추가할 경우 사용
var arr = [1, 2, 3];
console.log([...arr, 4, 5]);

var obj = { a:0, b:2 }
console.log({...obj, c:5});

bookmark_border동시통역 채팅 프로그램 만들기

네이버 파파고 번역 API

Papago NMT API

네이버 API 이용신청

Request 모듈

  • NodeJS 앱에서 HTTP 요청 기능
    • Jquery 의 .ajax 함수와 비슷
  • my_littlechat> npm install –save request
# request 사용법

var request = require("request");

request.get('/books', function(error, response, body) {
    
});

request.post('/books', { body: { key: value } }, function(error, response, body) {
    
});

request.put('/books', { body: { key: value } }, function(error, response, body) {
    
});

request.delete('/books', function(error, response, body) {
    
});
app.post('/send', function(req, res) {
    var message = {
        sender: req.body.sender,
        ko: req.body.ko,
        en: req.body.en
    };
    console.log(message);

    messages.push(message);
    res.status(200).send({ message: "Success" });
});

서버 구현

app.post('/send', function(req, res) {
    var message = {
        sender: req.body.sender,
        ko: req.body.ko,
        en: req.body.en
    };
    console.log(message);

    var options = {
        url: "https://openapi.naver.com/v1/papago/n2mt",
        form: {
            source: message.ko.length == 0 ? "en" : "ko",
            target: message.ko.length == 0 ? "ko" : "en",
            text: message.ko.length == 0 ? message.en : message.ko
        },
        headers: {
            "X-Naver-Client-Id": "ID",
            "X-Naver-Client-Secret": "KEY",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
        }
    };

    request.post(options, function(error, response) {
        var result = JSON.parse(response.body).message.result;
        message.ko = message.ko.length == 0 ? result.translatedText : message.ko;
        message.en = message.en.length == 0 ? result.translatedText : message.en;

        console.log(message);
        messages.push(message);
        res.status(200).send({ message: "Success" });
    });    
});

app.get("/receive", function(req, res) {
    var result = { total: messages.length, messages: [] };

    if (messages.length > req.query.from) {
        result.messages = messages.slice(req.query.from);
    }

    res.status(200).send(result);
});

클라이언트 구현

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>my little chat</title>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <style>
      .messages {
        width: 500px;
        height: 500px;
        overflow: scroll;
        background: #eeeeee;
      }
    </style>
  </head>
  <body>
    <div class="messages" id="messages"></div>
    <div>
      <select id="selectBox">
        <option value="ko">한국어</option>
        <option value="en">영어</option>
      </select>
      아이디: <input type="text" id="senderId" />
      내용: <input type="text" id="chatInput" />
      <button id="sendButton">전송</button>
    </div>
    <script src="./chat.js"></script>
  </body>
</html>
var curIndex = 0;
var language = "ko";
var messages = [];

setInterval(function() {
    $.ajax(`http://localhost:3000/receive?from=${curIndex}`).done(function(data) {
        for (const message of data.messages) {
            console.log(message);

            $("#messages").append(
                message.sender + " : " + (language == "ko" ? message.ko : message.en)
            );
            $("#messages").append("<br/>")
        }

        curIndex = data.total;
    });
}, 1000);

$("#sendButton").click(function() {
    var message = {
        ko: "",
        en: "",
        sender: $("#senderId").val()
    }

    if (language == "ko") message.ko = $("#chatInput").val();
    else message.en = $("#chatInput").val();

    console.log(message);

    $.ajax({
        url: "http://localhost:3000/send",
        method: "POST",
        data: JSON.stringify(message),
        dataType: "json",
        contentType: "application/json"
    }).done(function() {
        console.log("POST done");
        $("#chatInput").val("");
    });
});

$("#selectBox").change(function() {
    language = $("#selectBox").val();
    console.log(language);
    $("messages").html("");
    curIndex = 0;
});

bookmark_bordernodeJS Todo list 프로그램

NodeJS Todo list

  • todo list 웹 페이지를 NodeJS 서버를 통해 호스팅
  • todo list 저장 및 불러오기 API 구현

Todo list API

# index.js

var express = require('express');
var app = express();

//var todos = {};
var todos = { "자바스크립트 공부하기": true };

app.use(express.json());
app.use(express.static("public"));

app.post("/todos", function(req, res) {
    todos = req.body.todos;
    console.log(req.body);
    res.status(200).send({ message: "success" });
});

app.get("/todos", function(req, res) {
    res.status(200).send(todos);
})

app.listen(3000, function() {
    console.log("3000 포트로 웹서버 실행!");
});
  • http://localhost:3000/todos
    • 응답 : { “자바스크립트 공부하기”: true }
  • app.use(express.static(“public”));
    • 웹 시작 디렉토리 : D:\…\my_todolist\public
    • 여기에 클라이언트 html, css, js 파일 위치
  • 메서도 체인(Method Chaining)
    • res.status(200).send({ message: “success” });
    • 함수를 연속해서 호출
    • 각 함수들이 자신을 리턴해서 가능 ( return this; )

Todo 클라이언트

  • 저장함수
function saveTodos() {
    $.ajax({
        url: "http://localhost:3000/todos",
        method: "POST",
        data: JSON.stringify({ todos: todos }),
        dataType: "json",
        contentType: "application/json"
    }).done(function() {
        console.log("POST done");
    })
}
  • 체크박스 정보 추가
function inputTemplate(text, checked) {
    var inputTag = $('<input type="checkbox" id="checkBox">');
    inputTag.data('value', text);
    inputTag.attr('checked', checked);
    return inputTag;
}
  • 추가버튼, 체크박스, 삭제버튼 클릭시 저장함수 saveTodos(); 호출
  • 시작시 서버에 저장된 메모정보 로드
$.ajax("http://localhost:3000/todos").done(function(result) {
    console.log(result);

    todos = result;
    for (const todo of Object.keys(todos)) {
        $(".contents ul").append(liTemplate(todo, todos[todo]));
    }
});

bookmark_borderRESTful API

RESTful API

  • REST 란?
  • Representational State Transfer 의 약자
  • api 에 대한 상세 스펙을 보지 않아도 HTTP요청의 여러 정보를 통해 API가 하는 일을 알 수 있도록 설계된 api
  • REST API가 표현하는 것
    • 자원과 자원에 대한 행위
    • 자원 : 서버에 저장되어 있는 데이터들
      • 쇼핑몰 서비스에서의 자원 : 상품 목록,주문 목록,회원 목록 등
      • 도서관리 서비스에서의 자원 : 도서 자체
  • REST API를 통해 사용하려는 자원을 HTTP uri 로 명시
  • HTTP메서드로 자원에 대한 행위를 명시

CRUD

  • Create : 생성(POST)
  • Read : 조회(GET)
  • Update : 수정(PUT)
  • Delete : 삭제(DELETE)

REST API 작성 규칙

  • 자원은 URI에 영문 소문자, 명사 복수형으로 표현
  • 파일 확장자는 URI에 포함하지 않음
  • 자원의 계층구조는 /(슬래쉬)로 표현

RESTAPI 예시

CRUD HTTP 메서드 URI
책들의 목록을 표시 GET /books
책 한권의 정보를 표시 GET /books/{id}
새 책을 생성 POST /books
책을 수정 PUT /books/{id}
책을 삭제 DELETE /books/{id}

RESTful API를 사용하는 이유

  • HTTP프로토콜 상에서 동작
  • 특정 언어나 플랫폼에 종속되지 않음
  • API 의 의도를 API사용자가 쉽게 파악할 수 있음

Express.js로 RESTful API 만들기

  • Express로 HTTP 메서드 처리
  • Express로 URI 처리
  • Express로 HTTP 바디 처리

Express Router

  • 미들웨어의 한 종류
  • HTTP 메서드, uri 에 따라 미들웨어 실행 여부 결정
  • Router 생성
    • express.Router()로 Express Router 생성
  • 생성한 라우터는 다른 미들웨어와 마찬가지로 app.use 를 통해 등록할 수 있음
  • Express Router를 사용하면 Express앱의 모듈화가 가능
# router.js

var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
    res.send('GET /');
});

router.post('/', function(req, res, next) {
    res.send('POST /');
});

router.put('/', function(req, res, next) {
    res.send('PUT /');
});

router.delete('/', function(req, res, next) {
    res.send('DELETE /');
});

module.exports = router;
# index.js

var express = require('express');
var app = express();
var router = require('./router.js')

app.use(router);

app.listen(3000, function() {
    console.log("3000 포트로 웹서버 실행!");
});
  • Insomnia 설치
    • 서버에 GET, POST, PUT, DELETE 등을 전달할 수 있는 유틸리티

Express Route Parameter

  • RESTApi 에서 자원의 아이디를 uri 를 통해 전달
  • 아이디와 같이 Uri의 변하는 요소를 Route prameter 라고 함
  • Express Router 에서는 :(콜론)과 파라미터 이름으로 Route parameter를 설정
  • Request 객체의 params 프로퍼티로 Route parameter에 접근
router.get('/:id', function(req, res, next) {
    res.send('전달받은 파라미터 : ' + req.params.id);
});
  • GET localhost:3000 -> 응답 : Cannot GET/
  • GET localhost:3000/13244 -> 응답 : 전달받은 파라미터 : 13244

Query String

  • URI 를 통해 값을 전달하는 또 하나의 방법
  • RESTAPI 에서는 주로 자원을 검색, 필터링 할 때 사용
  • ex) /books?author=김군오&language=kr

Express에서 Query String 사용

  • Request 객체의 query 프로퍼티로 접근
  • Route parameter 와 다르게 어떤 query string을 받을지 미리 설정하지 않음
  • 라우트에 영향을 주지 않음
  • 쿼리스트링의 유무와 관계없이 http 메서드와 uri 를 통해서만 라우트가 결정
  • 전달하지 않은 query string에 접근하면 값이 설정되어 있지 않음
    • undefined 변수로 취급
router.delete('/', function(req, res, next) {
    res.send('Year : ' + req.query.year);
});
  • DELETE localhost:3000 -> 응답 : Year : undefined
  • DELETE localhost:3000/?year=2021 -> 응답 : Year : 2021

HTTP Body

• POST, PUT 메서드는 HTTP 요청에 Body 전달 가능
• Body에는 text, json, xml, html, 파일 등 어느 것이라도 전송될 수 있음
• Body는 Content-type 헤더에 따라 적절히 해석되어야 함

# index.js
app.use(express.json());

# router.js
router.post('/', function(req, res, next) {
    res.send('제목 : ' + req.body.title);
});

# insomnia test json
{
	"title" : "도서의 제목입니다."
}
  • POST localhost:3000 -> 응답 : 도서의 제목입니다.

bookmark_bordernpm과 express 모듈

NPM으로 모듈 설치

NPM

  • NodeJS 모듈을 공유하고 다운받는 저장소
  • CLI (명령줄 인터페이스)로 간편하게 모듈 관리
  • 의존성 관리
    • A 모듈이 B 모듈을 사용할 때 A모듈은 B모듈에 의존성이 있다고 말함
    • package.json 파일로 프로젝트 의존성 관리

npm init 명령어

  • NodeJS 프로젝트를 시작하기 위한 명령어
  • package.json 파일을 생성
  • 프로젝트의 이름, 버전, 개발자 정보 등의 메타데이터
  • NPM모듈의 의존성 정보 등을 담고 있음
  • 새로운 폴더 생성 및 실행
    • my_module_test>npm init
  • package.json
{
  "name": "my_module_test",
  "version": "1.0.0",
  "description": "나의 모듈 시험",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC"
}
  • 엔트리 포인트 : “main”: “index.js”,
  • “scripts”: {
    “start”: “node index.js”
    },
    => npm run start 명령으로 실행

Express.js 모듈 사용

NPM 패키지 검색

  • https://www.npmjs.com/
  • express
  • > npm install –save express
    • package.json 에 의존성 정보를 저장하려면 –save 옵션과 함께 실행
    • express에 의존성 있는 모든 모듈 설치됨

Express

  • 고성능 웹 프레임워크
  • 프로그래머가 작성한 함수를 실행해 HTTP요청에 대한 HTTP응답을 프로그래머가 원하는 대로 만들어 HTTP클라이언트에게 응답할 수 있음
  • 요청한 URL이나 HTTP메서드에 따라 원하는 함수를 실행시켜 주는 라우팅 기능
  • HTML의 내용 일부분을 변수에 저장된 값으로 치환해 동적인 HTML을 만들어 응답하는 뷰 템플릿 엔진도 가지고 있다
  • 미들웨어로 기능 확장

require 함수로 외부 모듈 이용하기

  • require 함수 모듈명을 인자로 실행
  • 파일명을 전달할 때와 마찬가지로 해당 모듈을 반환
var express = require('express');
var app = express();

app.listen(3000, function() {
    console.log("3000 포트로 웹서버 실행!");
});
  • my_module_test> npm run start
  • ctrl + C 키로 종료

미들웨어 콜백함수의 인수

  • HTTP 요청 -> 미들웨어1 -> 미들웨어2 -> 미들웨어… -> HTTP 응답
  • Request 객체
    • HTTP요청에 대한 정보가 담겨 있음
  • Response 객체
    • 브라우저에 전송할 HTTP응답을 어떻게 만들지에 대한 정보를 설정
  • next 함수
    • 이전 미들웨어에서 다음 미들웨어도 실행해야 한다고 알려주는 함수
app.use(function(req, res, next) {
    res.send('OK');
})
  • 디버깅
    • JavaScript Debug Terminal 로 실행
    • 디버그 터미널에서 my_module_test> npm run start 수행
    • break point

bookmark_borderNodeJS

NodeJS 소개

NodeJS

  • 브라우저 외부에서 실행되는 자바스크립트 엔진
  • 구글 크롬의 자바스크립트 엔진인 V8을 이용해 만들어짐
  • 기본 자바스크립트 기능 외에 운영체제 기능을 활용할 수 있는 라이브러리 제공
  • 주로 개발자 도구나 웹 서버 상에서 실행되는 프로그램을 작성할 때 많이 사용

Node 특징

  • 비동기 I/O처리
    • 시간이 많이 걸리는 Input,Output 작업을 비동기로 처리
  • 빠른 속도
    • 구글 크롬의 자바스크립트 엔진인 V8의 등장으로 자바스크립트의 속도 문제도 어느 정도 해결
  • 패키지 매니저를 통한 의존성 관리
    • NPM이라는 패키지 매니저를 제공
    • 노드 패키지 매니저는 전세계 수 많은 사람들이 자신들의 모듈을 업로드 할 수 있는 코드 저장소
  • 단일 쓰레드
    • 쓰레드란 CPU가 동시에 여러가지 일을 처리할 수 있게 해주는 기능

NPM

  • Node Package Manager
  • NodeJS로 만들어진 모듈 공유
  • 프로젝트 의존성 관리를 위한 package.json

로컬환경에 NodeJS 설치

VisualStudioCode NodeJS 디버깅

  • 중단점
  • 조건부 중단점
  • 로그지점
    • i 값 출력 : {i}

모듈 프로그래밍

  • 여러 파일에 기능을 쪼개서 개발
  • 코드 가독성이 올라가고 관리가 쉬워짐
  • module.exports 객체 이용
  • require(‘{파일명}‘) 함수로 모듈 로드
function add(a, b) {
    return a + b;
}

function sub(a, b) {
    return a - b;
}

module.exports = {
    'add' : add,
    'sub' : sub
}
var calculator = require('./0609-nodejs-module-1.js');

console.log(calculator.add(1, 2));
console.log(calculator.sub(5, 3));

bookmark_borderOpenAPI

OpenAPI

API

  • Application Programming Interface
  • 운영체제나 프로그래밍 언어 기능을 사용하기 위한 인터페이스
  • 예:
    • 다른 프로그래밍 언어에서 운영체제의 기능을 이용하려 할 경우
      • 운영체제에서 자신의 기능에 대해 접근할 수 있는 인터페이스를 공개
      • 프로그래머에게 인터페이스에 대한 자세한 스펙 또는 명세를 제공
      • 이 명세가 바로 API

OpenAPI

  • 특정 사이트의 데이터에 접근하는 API를 공개해 외부 사이트에서 자유롭게 가공하고 사용할 수 있도록 함
  • API 제공자는 API 사용료를 통해 직접적인 수익을 얻거나 사용자 유입 등을 유도할 수 있음
  • API 사용자는 직접 개발하는 것보다 훨씬 적은 비용으로 기능 개발이 가능

OpenAPI 사용 절차

OpenAPI의 종류

RESTAPI

  • 보통의 http통신 방식으로 api 를 호출하는 방식
  • 추가적인 라이브러리가 필요 없고 어느 플랫폼에서든 사용하는 언어에서 http통신만 지원한다면 api 를 사용

• 웹 JS SDK

  • Software Development Kit의 약자
  • 자바스크립트 sdk는 화면에 표시될 ui 와 상호작용 까지 포함하고 있고 더 풍부한 서비스를 제공
  • 대표적인 예 : 지도 api

네이티브 SDK

  • 안드로이드나 iOS에서 실행되는 스마트폰 앱을 위해 제공되는 방식

한동대학교 API

Query parameter

  • Http요청에서 인자를 전달하는 방식 중 하나
  • 인자에 이름을 부여하고 개수 제한이 없다는 것이 장점
  • 주소에 정보가 공개된 다는 점은 보안적으로 취약할 수 있음
  • Url 뒤 ?표시로 시작
  • http://example.com?date=20190601&param2=test

식단 정보 API

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>openapi-handong</title>
    <style>
      table,
      th,
      td {
        border: solid gray;
      }
    </style>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
  </head>
  <body>
    <h1>오늘의 식단</h1>
    <button id="haksikBtn">학식</button>
    <button id="momsBtn">맘스</button>
    <table>
      <thead>
        <tr>
          <th>한글메뉴</th>
          <th>가격</th>
        </tr>
      </thead>
      <tbody id="tableBody"></tbody>
    </table>
    <script src="./0604-app.js"></script>
  </body>
</html>
var haksik = [];
var moms = [];

$.ajax("http://smart.handong.edu/api/service/menu")
    .done(function(result) {
        haksik = result.haksik;
        moms = result.moms;
        addItem(haksik);
    });

function addItem(menuArr) {
    for (var menu of menuArr) {
        $("#tableBody").append(`<tr><td>${menu.menu_kor}</td><td>${menu.price}</td></tr>`);
    }
}

$("#haksikBtn").click(function() {
    $("#tableBody").html("");
    addItem(haksik);
});

$("#momsBtn").click(function() {
    $("#tableBody").html("");
    addItem(moms);
});

카카오 지도

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"/>
	<title>Kakao 지도 시작하기</title>
</head>
<body>
	<div id="map" style="width:500px;height:400px;"></div>
	<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=8979d3e8b21fffebfaa7d5b095b9595f"></script>
	<script>
		var container = document.getElementById('map');
		var options = {
			center: new kakao.maps.LatLng(33.450701, 126.570667),
			level: 3
		};

		var map = new kakao.maps.Map(container, options);
	</script>
</body>
</html>