jnk1m
Foliage IT
jnk1m
전체 방문자
오늘
어제
  • 분류 전체보기 (209)
    • Today I Learned (34)
    • Java (47)
    • Database (15)
    • [NHN Academy] (27)
    • Spring (47)
    • HTML + CSS + JavaScript (11)
    • JSP (3)
    • Node.js (10)
    • React Native (2)
    • 기타 (8)
    • 스크랩 (5)

인기 글

최근 글

티스토리

hELLO · Designed By 정상우.
글쓰기 / 관리자
jnk1m

Foliage IT

Node.js

[Node.js + MySQL] Day04: pug, nunjunk, repository (MySQL)

2022. 5. 11. 00:46

**node_express
1.에러 처리
1)에러 발생 즉시 처리 
res.status(상태코드).수행할 코드
=>수행할 코드 부분은 매개변수가 4개가 되는데 error 객체, req 객체, res 객체, next

2)에러 별도 처리
app.use((err, req, res, next) => {
에러 처리 코드
});

2.req 객체 - request(클라이언트의 정보를 저장한 요청) 객체
=>req.app: app 객체에 대한 참조

=>req.body: body-parser 가 만드는 요청의 내용을 해석한 객체(post 방식으로 전송된 데이터 중에서 file을 제외한 데이터 해석에 사용)
=>req.params: 라우트 매개변수에 대한 정보가 저장된 객체(URL의 일부분을 파라미터로 사용하고자 하는 경우 사용)
=>req.query: query string 해석에 사용(get 방식으로 전송된 데이터를 해석)

=>req.cookies: 쿠키 해석에 사용
=>req.signedCookies: 서명된 쿠키 해석에 사용 

=>req.ip: 클라이언트의 IP

=>req.get(헤더 이름): 헤더에 해당하는 데이터 리턴(API Key 해석에 많이 이용)

3.res 객체 - response(응답 정보를 제공) 객체
=>res.app: app 객체에 대한 참조

=>res.cookie(키, 값, 옵션): 쿠키를 설정하는 함수
=>res.clearCookie(키, 값, 옵션): 쿠키를 삭제하는 함수
이전에는 보안 문제때문에 사용하지 않는 것을 권장했지만 최근에는 사용자의 동선 추적 등에 많이 이용

=>res.send(출력할 내용): 내용을 직접 출력
=>res.sendFile(파일 경로): 파일을 출력 

=>res.end(): 데이터없이 응답을 전송

=>res.render(뷰이름, 데이터): 템플릿 엔진(spring 에서의 thymeleaf 나 velocity 나 python 의 django  와 유사)을 이용해서 출력

=>res.json(JSON 데이터): JSON 형식으로 응답, 최근에 많이 사용

=>res.redirect(리다이렉트할 URL): URL로 리다이렉트

=>res.status(상태 코드)

=>응답은 1번만 수행
=>최근의 추세인 SPA(Single Page Application) 구현이나 다양한 디바이스 지원을 위한 Server를 구축하고자 하는 경우에는 json 형태로 리턴하는 경우가 많습니다.

4.템플릿 엔진
=>HTML은 정적이기 때문에 서버에서 생성하는 동적인 데이터를 가져다가 사용할 수 없는데 이를 위한 해결책으로는 ajax 나 web socket 같은 JavaScript를 이용한 전송 방식이 있고 서버의 데이터를 사용할 수 있도록 해주는 템플릿 엔진을 이용하는 방법이 있음
=>서버의 데이터를 html 파일에서 자바스크립트 코드 없이 바로 출력하고자 하는 경우 사용

1)Jade
=>Jade 로 배포되었다가 저작권 문제로 Pug로 개명
=>공식 문서: https://pugjs.org/api/getting-started.html
=>html 도 jade 문법으로 출력
=>설치: npm install pug
=>설정
app.set('views', path.join(__dirname, '실제 pug 파일이 위치할 디렉토리')
app.set('view engine', 'pug')
=>라우팅 시 pug로 출력
res.render('출력할 뷰 이름'): 실제 pug 파일이 위치할 디렉토리에 뷰이름.html 이나 뷰이름.pug 파일을 이용해서 출력
render 함수를 호출할 때 뒤에 데이터를 같이 전송할 수 있으며 pug를 이용한 출력 파일에서는 이 데이터를 사용할 수 있고 변수 생성이나 제어문 사용도 가능합니다.

2)jade를 이용한 데이터 출력
=>node 프로젝트 생성

=>필요한 라이브러리 설치
일반 설치: express, morgan,  multer, cookie-parser, express-session, session-file-store, dotenv, pug

개발용으로 설치: nodemon

=>package.json 을 수정: main 부분 과 scirpts 수정
  "main": "app.js",

  "scripts": {
    "start":"nodemon app",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

=>.env 파일을 만들고 필요한 상수(변하지 않는 데이터)를 선언
PORT=9000
COOKIE_SECRET=cookie_secret

=>시작 파일로 사용할 app.js 파일을 생성하고 작성

//필요한 모듈 가져오기
const express = require('express')
const morgan = require('morgan')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const dotenv = require('dotenv')
const path = require('path')
const fs = require('fs')

//dotenv 사용 설정
//dotenv 파일에 만든 내용을 읽어서 process.env(express가 생성) 에 속성으로 추가
dotenv.config();

//express app 생성
const app = express()

//포트 설정
app.set('port', process.env.PORT)

//로그 기록 설정 - 로그를 콘솔에 출력
//실제 개발용이면 대부분 파일에 출력
app.use(morgan('dev'))

//정적 파일(css, javascript, 그 이외 필요한 자원) 경로 설정
app.use('/', express.static(path.join(__dirname, 'public')))

//클라이언트에서 데이터를 json 형식으로 전송한 경우 처리하기 위한 설정
app.use(express.json())
app.use(express.urlencoded({extended:false}))

//쿠키를 req.cookies 로 읽을 수 있도록 해주는 설정
app.use(cookieParser(process.env.COOKIE_SECRET))

//세션을 req.session 으로 사용할 수 있도록 해주는 설정
app.use(session({
    resave:false,
    saveUninitialized:false,
    secret:process.env.COOKIE_SECRET,
    cookie:{
        httpOnly:true,
        secure:false
    },
    name:'session-cookie'
}))

//pug 설정
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')

//요청 처리
app.get('/', (req, res) => {
    //pug 가 설정된 디렉토리의 index.html 이나 index.pug로 출력
    //title 과 aespa 라는 데이터를 가지고 넘어갑니다.
    res.render('index', {title:'aespa',
    aespa:['카리나', '지젤', '윈터', '링링']})
})


//서버 실행
app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트에서 대기 중')
})



=>프로젝트에 views 디렉토리를 생성하고 index.pug 추가한 후 작성

doctype html
html
    head
        title=title
        link(rel='stylesheet', href='/style.css')
    body
        block content
block content
    h1 Welcome to #{title}

    #aespa
        ul
            each artist in aespa
                li=artist

    - const message = 'Hello'
    p #{message}
    script
        | alert('test')



=>프로젝트에 public 디렉토리를 만들고 style.css 파일을 만든 후 작성
h1{
    color:blue;
}


=>서버를 실행하고 브라우저에 localhost:9000 을 입력하고 데이터가 출력되고 스타일이 적용되는지 확인

3)nunjucks
=>템플릿 엔진 중의 하나로 태그는 그대로 사용하고 데이터를 출력하는 부분이나 제어문 사용하는 부분만 별도의 문법으로 작성하는데 {% 내용 %} 의 형태로 사용

=>설치
npm install nunjucks

=>설정
const numjucks = require('numjucks')
app.set('view engine', 'html')
nunjucks.configure('디렉토리이름', {
express:app,
watch:true
});

=>출력
res.render('뷰이름', {데이터이름: 데이터, ...})

=>html 파일에서 데이터를 단순 출력
{{데이터 이름}}

=>반복문
{% for 임시변수 in 컬렉션이름 %}
{{임시변수}}

=>조건문
{% if 조건식 %}
true 일 때 수행할 내용

{% elif 다른 조건식 %}
...

...

{% else %}
수행할 내용

=>다른 파일 가져오기
{% include "파일 경로" %}

4)nunjucks 로 데이터 출력
=>설치
npm install nunjucks

=>app.js 파일 수정
//nunjucks 설정
const nunjucks = require('nunjucks')
app.set('view engine', 'html')
nunjucks.configure('views',{
    express:app,
    watch:true
})

=>views 디렉토리에 index.html 파일을 생성

<!DOCTYPE html>
<html>
    <head>
<meta charset="utf-8"/>
<title>nunjucks</title>
    </head>
    <body>
<h1>{{title}}</h1>
<ul>
    {% for item in aespa %}
        <li>{{loop.index}} 번째 {{item}}</li>
    {% endfor %}
</ul>

<p>변수 생성</p>
{% set fruit = 'orange' %}

{% if fruit === 'apple' %}
    <p>사과</p>
{% elif fruit === 'orange' %}
    <p>오렌지</p>
{% else %}
    <p>모르는 과일</p>
    {% endif %}
    </body>
   </html>



5)nunjunck 는 python 의 django 에서도 사용 가능

6)rest api를 전송해서 ajax로 출력
=>app.js 파일에 추가

app.get('/rest', (req, res) => {
    res.sendFile(path.join(__dirname, 'rest.html'))
})

app.get('/json', (req, res) => {
    res.json({title:'aespa',
    aespa:['카리나', '지젤', '윈터', '링링']})
});




7)프로젝트 디렉토리에 출력하는 파일인 rest.html 파일을 생성하고 작성

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>ajax를 이용한 출력</title>
    </head>
    <body>
        <div id="content"></div>
    </body>

    <script>
        var xhr = new XMLHttpRequest()
        xhr.open('GET', '/json', true)
        xhr.send()
        xhr.addEventListener('load', function(){
            var result = xhr.responseText;
            //위의 데이터를 javascript 객체로 변환
            var obj = JSON.parse(result)
            document.getElementById('content').innerHTML = 
                obj.title;
        })
    </script>
</html>


8)서버를 구동하고 브라우저에 localhost:3000/rest 를 입력하고 데이터가 읽어져 오는지 확인

9)java에서 데이터를 가져다가 사용

try{
URL url = new URL("http://ip:3000/rest");
HttpURLConnection con = (HttpURLConnection)url.openConnection();
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
while(true){
String line = br.readLine();
if(line == null){
break;
}
sb.append(line + "\n");
}

br.close();
con.disconnect();
System.out.println(sb.toString());
}catch(Exception e){
System.out.println(e.printStackTrace());
}



**Repository
=>저장소
1.종류
=>File System: 일반 File System 과 Hadoop 과 같은 분산 파일 시스템
=>DataBase
 - 로컬 데이터베이스: 로컬에서만 접속이 가능한 데이터베이스로 대표적인 Local Database 가 SQLite(Android, iOS, Web Browser에는 내장되어 있음)이고 모바일에서 자주 사용하는 데이터를 caching 할 목적으로 많이 사용

 - 서버 데이터베이스: 여러 사용자가 데이터를 공유할 목적으로 로컬 컴퓨터 이외의 곳에 데이터를 보관하는 방식
   RDBMS(관계형 데이터베이스): 테이블을 이용해서 데이터를 저장하는 방식으로 Oracle, MySQL(Maria DB), MSSQL, Tibero, HANA DB, Postgre SQL 등

   NoSQL: 테이블 구조를 이용하지 않는 데이터베이스로 여러 종류가 있는데 그 중에서 대중에게 가장 많이 알려진 NoSQL 이 Mongo DB 입니다.
스마트 폰 애플리케이션 제작에는 google 의 firebase 를 많이 사용합니다.
노드 진영에서는 mongo db를 많이 사용합니다.

  최근에는 클라우드 기반의 데이터베이스도 많이 사용합니다.

 - 여러분 final project 에서는 MySQL 을 사용

2.연동 방법
1)언어 차원에서 제공하는 기본 라이브러리 이용

2)framework 이용
=>SQL Mapper Framework: SQL 과 로직을 처리하는 코드를 분리해서 사용하는 방식으로 MyBatis(iBatis)가 대표적

=>ORM(Object Relation Mapper Frmework): 하나의 객체 와 하나의 record(row, tuple 등)를 매핑하는 방식으로 사용하는데 SQL 없이 관계형 데이터베이스 사용이 가능
Java 에서는 JPA 가 표준으로 채택이 되었으며 다른 언어들에도 이러한 프레임워크가 존재합니다.
최근에는 ORM 방식으로 데이터베이스 연동을 많이하고 SQL Mapper를 보조적인 역할을 수행하는 형태로 사용하는 경우가 많습니다.


3.데이터베이스 사용 준비
=>데이터베이스 서버 준비

=>데이터베이스 접속 도구: 서버를 직접 설치하면 제공되는 경우가 있음

**MySQL
1.설치
1)windows 는 mysql site에 가서 installer 버전을 다운로드 받아서 설치

2)mac 은 homebrew 이용해서 설치
=>homebrew 설치(M1, Intel chip 이냐에 따라서 다르게 설치)
=>brew install mysql : 설치
=>brew services start mysql : mysql server 실행(root 비밀번호는 없음)
=>brew services stop mysql : mysql server 중지

3)ubuntu linux
sudo apt install -y mysql-server

4)docker 같은 가상화 애플리케이션에 설치
=>docker pull mysql
=>서버 시작은 docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=비밀번호 -d -p 3306:3306 mysql:latest
=>클라우드 환경 개발이나 애플리케이션 개발자가 되고자 하는 경우 추천

2.MySQL 버전
=>5.x 버전 과 최근의 8.x 버전으로 구분
=>8.x 버전은 처음부터 비밀번호가 암호화 되어 있으며 기본 설정이 외부에서는 root 계정에 접근할 수 없도록 되어 있음

3.MySQL 접속
=>관리자 계정은 root 이고 설치할 때 관리자 비밀번호를 설정하면 기본 포트는 3306번
처음부터 제공되는 데이터베이스는 mysql 이 있습니다.
=>MySQL 의 데이터베이스는 user 보다 큰 개념으로 하나의 database를 만들면 여러 명의 user 가 공유해서 사용할 수 있습니다.


4.계정 생성
1)계정 생성
create user '사용자이름'@'%' identified by '비밀번호'
=>% 대신에 localhost를 사용하거나 ip를 작성하시면 localhost 나 ip에서만 접속이 가능합니다.

2)계정에 권한 부여
grant all privileges on *.* to '사용자이름'@'%'

3)일반 비밀번호로 접속이 가능하도록 수정
alter user '사용자이름'@'%' identified with mysql_native_password by '비밀번호'

4)변경 내용 적용
flush privileges;

5)계정 생성 실습 - mac 이신 분들은 mysql -uroot -p mysql 을 터미널에서 입력해서 수행하시면 됩니다.

create user 'user00'@'%' identified by 'user00';

grant all privileges on *.* to 'user00'@'%' ;

alter user 'user00'@'%' identified with mysql_native_password by 'user00';

flush privileges;

=>mac에서 계정이 만들어졌는지 테스트
mysql -u user00 -p 를 입력하고 비밀번호 입력

5.데이터베이스 관련 명령
=>mysql 의 데이터는 데이터베이스 단위로 관리가 이루어집니다.
=>하나의 데이터베이스는 여러 유저가 공유 가능합니다.

1)사용 가능한 데이터베이스 확인
show databases;
=>제공되는 데이터베이스 중에서 world 와 test를 제외한 데이터베이스는 관리자가 사용하는 데이터베이스입니다.
사용자의 데이터를 저장하는 용도로 사용하는 것은 바람직하지 않음

2)데이터베이스 생성
create database 데이터베이스이름;

3)데이터베이스 삭제
drop database 데이터베이스이름;

4)데이터베이스 사용
use 데이터베이스이름;

5)데이터베이스 생성 및 확인
create database node;

show databases;

6.SQL(Structured Query Language)
=>관계형 데이터베이스의 질의어

1)DDL(Data Definition Language - 정의어, 데이터베이스 관리자의 언어)
=>Create: 구조 생성
=>Alter: 구조 변경
=>Drop: 구조 삭제

=>Truncate: 테이블의 데이터 삭제
=>Rename: 구조 이름 변경

2)DML(Data Manipulation Language - 조작어, 개발자의 언어)
=>Select: 조회, DQL 로 분리하는 것이 요즈음의 추세, 데이터에 변경을 가하지 않음

=>Insert: 데이터 삽입
=>Update: 데이터 변경
=>Delete: 데이터 삭제

=>4개의 구문을 줄여서 CRUD(Create Read Update Delete) 라고도 합니다.

3)DCL(Data Control Language - 제어어, 데이터베이스 관리자의 언어)
=>Grant & Revoke: 권한을 부여하고 회수하는 명령

=>Commit & Rollback: 작업 내역을 데이터베이스에 반영하고 취소하는 명령(Transaction Control Language 로 분리를 하고 개발자의 언어)


7.DQL - Select
=>샘플 데이터 생성

show databases;

create database node;

show databases;

use node;

create table usertbl(
userid char(15) not null primary key,
name varchar(20) not null,
birthyear int not null, 
addr char(100),
mobile char(11),
mdate date)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

create table buytbl(
num int auto_increment primary key,
userid char(8) not null,
productname char(10),
groupname char(10),
price int not null,
amount int not null,
foreign key (userid) references usertbl(userid) on delete cascade)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

show tables;



insert into usertbl values('kty', '김태연',1989,'전주','01011111111', '1989-3-9');
insert into usertbl values('bsj', '배수지',1994,'광주','01022222222', '1994-10-10');
insert into usertbl values('ksh', '김설현',1995,'부천','01033333333', '1995-1-3');
insert into usertbl values('bjh', '배주현',1991,'대구','01044444444', '1991-3-29');
insert into usertbl values('ghr', '구하라',1991,'광주','01055555555', '1991-1-13');
insert into usertbl values('san', '산다라박',1984,'부산','01066666666', '1984-11-12');
insert into usertbl values('jsm', '전소미',2001,'캐나다','01077777777', '2001-3-9');
insert into usertbl values('lhl', '이효리',1979,'서울','01088888888', '1979-5-10');
insert into usertbl values('iyou', '아이유',1993,'서울','01099999999', '1993-5-19');
insert into usertbl values('ailee', '에일리',1989,'미국','01000000000', '1989-5-30');

commit;

insert into buytbl values(null, 'kty', '운동화', '잡화', 30, 2);
insert into buytbl values(null, 'kty', '노트북', '전자', 1000, 1);
insert into buytbl values(null, 'jsm', '운동화', '잡화', 30, 1);
insert into buytbl values(null, 'lhl', '모니터', '전자', 200, 1);
insert into buytbl values(null, 'bsj', '모니터', '전자', 200, 1);
insert into buytbl values(null, 'kty', '청바지', '잡화', 100, 1);
insert into buytbl values(null, 'lhl', '책', '서적', 15, 2);
insert into buytbl values(null, 'iyou', '책', '서적', 15, 7);
insert into buytbl values(null, 'iyou', '컴퓨터', '전자', 500, 1);
insert into buytbl values(null, 'bsj', '노트북', '전자', 1000, 1);
insert into buytbl values(null, 'bjh', '메모리', '전자', 50, 4);
insert into buytbl values(null, 'ailee', '운동화', '잡화', 30, 2);
insert into buytbl values(null, 'ghr', '운동화', '잡화', 30, 1);

commit;


1)Select 의 구조
 SELECT 열단위 추출을 위한 컬럼이나 연산식을 나열 - 별명 부여 할 수 있음, 필수 
 FROM 테이블 이름 나열하는데 다른 이름을 부여할 수 있음 - 필수
 WHERE 행단위 추출을 위한 조건 나열
 GROUP BY 그룹화하기 위한 컬럼이나 연산식을 나열 - 그룹 함수 생성 시점
 HAVING 그룹화 한 후 행단위 추출을 위한 조건 나열
 ORDER BY 정렬할 컬럼이나 연산식 나열
 LIMIT 추출할 행의 시작 인덱스 와 개수 나열 가능(오라클은 이 옵션이 없어서 inline view를 최근의 버전의 다른 옵션을 이용해서 이 부분을 해결)

2)테이블의 전체 데이터 확인
select *
from 테이블이름;

=>접속 도구에서는 블럭을 잡아서 실행하므로 ;을 하지 않아도 됩니다.
=>콘솔 환경이라면 반드시 ;을 해주어야 합니다.
=>프로그래밍 언어에서 embedded sql 의 형태로 많이 사용하는데 이 경우 ;이 있으면 에러가 나는 경우가 많습니다.
;을 생략하고 입력하는 것이 일반적입니다.

=>usertbl 테이블 과 buytabl 테이블을 조회
select *
from usertbl;

select *
from buytbl;

=>Oracle은 테이블 이름 과 컬럼 이름을 대문자로 사용하는데 MySQL은 소문자로 사용합니다.
Oracle은 SQL 조건절은 제외한 경우에는 대소문자 구분을 하지 않지만 MySQL은 대소문자 구분은 하는 경우가 많습니다.

3)특정 컬럼 이나 연산식 출력
select 컬럼 이름 이나 연산식 나열
from 테이블이름;
=>연산식을 사용하게 되면 연산식은 컬럼으로 만들어지는 것이 아니고 출력할 때 연산을 수행해서 출력을 합니다.
=>별명을 붙이고자 할 때는 공백이나 as를 붙이고 별명을 입력하면 됩니다.
별명에 공백이 있는 경우에는 별명을 반드시 ' '로 감싸야 합니다.
=>테이블을 만들 때는 컬럼 이름을 길게하고 사용을 할 때 별명을 이용해서 사용하는 경우가 많습니다.

=>buytbl 테이블에서 num, userid, amount * price 를 결과를 조회
select num, userid, amount * price
from buytbl;

select num as 번호, userid as 아이디, amount * price as 금액
from buytbl;

4)조건 검색
=>where 에 조건을 설정해서 행 단위 추출을 수행
=>연산자
>, >=, <, <=
=, !=
between A and B(not between A and B): A 와 B 사이, 반드시 B 의 값이 A 보다 크거나 같아야 합니다.
in(not in): 여러 개의 데이터를 괄호 안에 나열해서 그 중 하나와 일치하는 데이터 조회
is null(is not null): null 데이터 조회
and: 그리고
or: 또는(and 의 우선 순위가 or 보다 높음)

and 는 앞의 조건이 false 이면 뒤의 조건을 확인하지 않고 or는 앞의 조건이 true이면 뒤의 조건을 확인하지 않음

like(not like): 패턴 검색
_: 하나의 문자
%: 글자 수 없는 문자

=>데이터베이스에서는 문자도 크기 비교가 가능
=>날짜도 숫자로 인식

=>usertbl 테이블에서 name 이 김태연 인 데이터 조회
select *
from usertbl
where name='김태연';

=>usertbl 테이블에서 birthyear 가 1990 보다 크고 addr 이 서울인 데이터 조회
select *
from usertbl
where birthyear >= 1990 and addr = '서울';

=>usertbl 테이블에서 birthyear 가 1990 에서 1993 인 데이터 조회
select *
from usertbl
where birthyear >= 1990 and birthyear <= 1993;

select *
from usertbl
where birthyear between 1990 and 1993;


=>usertbl 테이블에서 name에 라 가 포함된 데이터 조회
select *
from usertbl
where name like '%라%';

=>usertbl 테이블에서 name이 배 로 시작하는 데이터 조회 
select *
from usertbl
where name like '배%';

=>usertbl 테이블에서 name이 4글자인 데이터 조회 시작하는 데이터 조회 
select *
from usertbl
where name like '____';

    'Node.js' 카테고리의 다른 글
    • [Node.js] Day 07: 데이터 가져와서 출력하기
    • [Node.js + MySQL] Day 06: 노드와 데이터 베이스 연결
    • [Node.js] Day03: express, dotenv, morgan, static, body-parser, compression, cookie-parser, express-session, multer, routing
    • [Node.js] Day 02: node, express

    티스토리툴바