자바스크립트 파일과 css 파일을 하나의 파일로 분리하여 관리

중복된 스크립트 코드를 image_read.js 라는 파일에 옮겨놓음

 

스크립트가 들어있는 경로를 /static 으로 설정 후 file_index.ejs 파일과 modify_form.ejs 파일에 설정

 

공용으로 사용할 css 파일 작성 후 file_list.ejs 에 적용해봄

728x90

 

 

 

 

파일 업로드, 다운로드

파일 세팅

 

npm install express --save
npm install ejs --save
npm install supervisor --save
npm install body-parser --save
npm install multer@1.4.4 --save

npm 설치

 

세팅 완료

 

npm start 로 서버 구동되게끔 설정도 완료

 

기본 서버 구동 코드 작성

 

파일 업로드, 다운로드는 post 방식을 사용하기 때문에 body-parser 사용 router 위임

 

router.js 에서 app 을 위임받아 사용 후 바로 router 를 export

 

router 에서 /file 경로로 들어오는 부분은 fileRouter 를 변수로 생성하여 위임 후 file_router.js 에서는 /file 경로로 들어올때 내용을 처리하고 router 를 다시 export 로 반환 

 

file_router 에서는 세부 경로를 다시 file_controller 로 위임

 

file_controller 에서 Object 를 하나 변수로 선언하여 키와 값으로 경로들을 묶어서 export 하고 file_router.js 에서는 사용 하고자 하는 키로 값을 가져와 사용한다

 

controller 작성, file_index.ejs 작성 후 작동 결과

 

form 태그 내에서 파일을 전송하는 경우

enctype="multipart/form-data"

위 코드를 적용해줘야 함

 

file_router 에 파일 선택 후 업로드할때 출력될 페이지 경로 설정 ( 파일 전송이기 때문에 post 방식 )

 

단순히 화면을 출력하는 부분은 view 라는 Object 에 모아서 사용, process 라는 Object 에는 연산을 하는 부분을 넣어서 사용, file_router 에서도 코드 수정

 

controller 에서 기존처럼 사용하지 않는 이유는 결국 controller 에 세부 경로가 많아질 수록 코드가 쌓이게 되는데 코드에서 문제가 생길 시 단순 출력 부분과 연산 부분 중 어느 부분이 문제가 생긴지 파악하고 쉽게 고칠 수 있기 때문... 또한 Object 로 묶어서 사용하는 이유는 exports 의 코드가 너무 길어지기 때문이므로 Object 를 exports 하여 router 에서 Object.key 형식으로 함수를 사용한다

 

router 에 multer 설정 및 파일 업로드 부분에 multer 의 기능을 추가.... controller 에서 console 로 출력 코드 적고 파일 전송해봄

 

저장되는 파일의 이름을 원본 파일과 동일하게 저장하기 위해 코드를 수정

 

코드 실행

 

 

 

 

 

특정 파일 형식만 사용하고 싶은 경우

filter 를 따로 구성하여 multer 에 추가한다

 

사용할 수 없는 확장자를 올리는 경우 filter 에서 확장자가 일치하지 않는 경우 req.fileValidation 에 문구를 설정하고 req.fileValidation 은 controller 에서도 사용할 수 있기 때문에 컨트롤러에서 확인하여 분류한다

 

코드 동작 영상

 

 

 

 

 

 

 

 

 

 

다운로드 구현

router 와 controller 에 이미지가 저장된 디렉토리의 내용을 읽어오는 코드를 작성

 

읽어온 이미지를 /file/list 경로로 보내줘서 출력 후 a 태그를 걸어 다운로드 링크를 생성

 

라우터에 다운로드 경로 추가, 컨트롤러에 다운로드 기능 추가

res.download(경로) : 해당 경로를 다운로드

 

다운로드 기능 구현 완료

 

 

 

 

 

 

 

 

 

 

이미지 업로드 시 미리보기 기능 구현

이미지 미리보기 구현은 파일 올리는 부분의 ejs 에서만 처리해주면 된다

onchange="readURL(this)" : 만약 파일이 선택되면 태그에 변경이 일어나기 때문에 readURL() 함수를 실행시킨다, 이때 매개변수로 자기 자신 태그가 가지고 있는 파일 정보를 전송한다.

 

readURL 함수에서는 이 파일의 정보를 input 변수로 넘겨 받아서 해당 변수의 files 라는 키 안에 들어있는 파일의 저장 경로를 file 함수로 담아준다

> 만약 파일 경로가 비어있지 않다면 ( 파일이 정상적으로 올라왔다면 ) 이 파일의 정보를 FileReader 를 사용하여 읽어서 변수 e 로 만든다.

> 이후에 이 변수의 target 이라는 키 안에 result 키에 담겨있는 이미지에 대한 경로를 가져와서 html 코드의 img 경로를 변경해준다

 

 

 

 

나중에 쇼핑몰같은 홈페이지의 경우 썸네일을 모두 원본으로 사용해버리면 용량이 너무 커지기 때문에 썸네일용으로 따로 파일을 처리해서 사용해야 한다 ( 구선생님께 노드 썸네일 생성 으로 검색하면 나옴 )

 

 

 

 

 

 

 

 

 

 

파일 삭제 구현

ejs 작성, router 작성

 

controller 에 삭제 기능 구현

 

 

 

 

 

 

 

 

 

 

파일 수정

원본 파일을 삭제 후 저장

수정기능 경로로 가는 ejs 파일 작성, router 에 경로와 파일이름 같이 전송

 

controller 에 views 에 modify_form 경로로 가는 부분 작성

 

modify_form.ejs 작성

 

modify_form.ejs 에 hidden 으로 코드 추가

 

수정 부분 router 에 추가 ( 파일을 전송하기 때문에 post 방식 )

 

파일을 수정하면 원본으로 있던 파일을 삭제하는 코드를 controller 에 작성, 그리고 수정을 누르는 순간 router 에서 수정될 이미지는 upload 명령어를 사용해서 저장하기 때문에 따로 새로 수정될 이미지를 저장하는 코드는 작성하지 않음

 

 

 

 

 

 

 

 

 

 

자바스크립트 파일과 css 파일을 하나의 파일로 분리하여 관리

중복된 스크립트 코드를 image_read.js 라는 파일에 옮겨놓음

 

스크립트가 들어있는 경로를 /static 으로 설정 후 file_index.ejs 파일과 modify_form.ejs 파일에 설정

 

공용으로 사용할 css 파일 작성 후 file_list.ejs 에 적용해봄

728x90

 

 

 

 

get, post, put, delete

 

index.ejs, app03.js 생성

 

{
  "scripts": {
    "start": "npx supervisor app03.js"
  },
  "dependencies": {
    "bcrypt": "^5.1.1",
    "body-parser": "^1.20.2",
    "ejs": "^3.1.9",
    "express": "^4.19.2",
    "supervisor": "^0.12.0"
  }
}

package.json

 

<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script>

    let content;
    window.onload = () => {
        content = document.getElementById("content");
        const getM = document.getElementById("getMembers");
        getM.addEventListener("click", getMembers);
        const regView = document.getElementById("regView");
        regView.addEventListener("click", registerView);
    }
    const register = () => {
        const arr = $("#form").serializeArray();
        // form 태그 안의 내용을 jquery 가 배열로 만들어준다
        console.log("arr : ", arr);
        let data = {};
        arr.forEach( d => data[d.name] = d.value );
        console.log("data : ", data);
        fetch("/register",{
            method : "post",
            headers : {"Content-Type":"application/json"},
            body : JSON.stringify(data)
            // 보내는 데이터를 json 방식으로 변환하여 보낸다
        })
        .then( res => res.json() )
        .then( result => {
            console.log( result )
            if(result === 1){
                alert("회원가입 성공!!!");
                getMembers();
            }
        })
    }
    const registerView = () => {
        let msg = `<form id="form">
            <input type="text" name="id" id="id" placeholder="input id"><br>
            <input type="text" name="pwd" id="pwd" placeholder="input pwd"><br>
            <input type="text" name="name" id="name" placeholder="input name"><br>
            <input type="text" name="addr" id="addr" placeholder="input addr"><br>
            <input type="button" id="btn" value="저장">
            </form>`;
        
        content.innerHTML = msg;
    }
    const getMembers = () => {
        fetch("get_members", {method:"get"})
        .then(res => res.json())
        .then(m => {
        let msg = "<table border='1'>";
            msg += "<tr><th>아이디</th><th>이름</th><th>주소</th></tr>"
            m.forEach((mem) => {
                msg += "<tr>";
                msg += `<td>${mem.id}</td>
                        <td style="cursor:pointer;" onclick="info('${mem.id}')">${mem.name}</td>
                        <td>${mem.addr}</td>`;
                msg += "</tr>";
            })
            msg += "</table>"
            content.innerHTML = msg;
        })
    }
    const info = (id) => {
        console.log("id : ", id);
        fetch("/search/"+id, {method:"get"})
        .then(res => res.json())
        .then(data => {
            console.log("data : ", data);
            content.innerHTML = `id : ${data.id}<br>
                                pwd : ${data.pwd}<br>
                                name : ${data.name}<br>
                                addr : ${data.addr}<hr>
                                <span style=cursor:pointer;
                                onclick="getMembers()"">
                                목록으로 이동
                                </span>
                                &nbsp; / &nbsp;
                                <span style=cursor:pointer;
                                onclick="modify_form('${data.id}')">
                                수정
                                </span>
                                &nbsp; / &nbsp;
                                <span style=cursor:pointer;
                                onclick="deleteM('${data.id}')">
                                삭제
                                </span>`;
        })
    }
    const modify_form = async (id) => {
        registerView();
        $("#btn").click(modify)
        $("#btn").val("수정 완료")
        const res = await fetch("/search/"+id, {method:"get"});
        const data = await res.json();
        console.log("data : ", data);
        $("#id").val(data.id);
        $("#pwd").val(data.pwd);
        $("#name").val(data.name);
        $("#addr").val(data.addr);
    }
    const modify = () => {
        const arr = $("#form").serializeArray();
        let data = {};
        arr.forEach( d => data[d.name] = d.value );
        fetch("modify", {
            method : "put",
            headers : {"Content-Type":"application/json"},
            body : JSON.stringify( data )
        })
        .then(res => res.json())
        .then(result => {alert("수정 성공"); info(data.id);})
    }
    const deleteM = async (id) => {
        const res = await fetch("/delete", {
            method : "delete",
            headers : {"Content-Type":"application/json"},
            body : JSON.stringify({id : id})
        })
        const result = await res.json();
        if(result == 1){
            alert("삭제 완료!!!");
            getMembers();
        }
    }
</script>

<div id="content">

</div>
<hr>
<button type="button" id="getMembers">목록보기</button>
<button type="button" id="regView">회원가입</button>

index.ejs

 

const express = require("express");
const app = express();

app.set("views", __dirname + "/views");
app.set("view engine", "ejs");

let members = [
    {id : "aaa", pwd : "aaa", name : "홍길동a", addr : "a산골짜기"},
    {id : "bbb", pwd : "bbb", name : "홍길동b", addr : "b산골짜기"},
    {id : "ccc", pwd : "ccc", name : "홍길동c", addr : "c산골짜기"},
]

app.get("/", (req, res) => {
    res.render("index");
})

app.get("/get_members", (req, res) => {
    res.json(members);
})

const bodyParser = require("body-parser");
app.use(bodyParser.json());
// post 로 받아오는 데이터를 json 형식으로 받아온다는 의미
app.post("/register", (req, res) => {
    console.log("req.body : ", req.body);
    members = members.concat(req.body);
    res.json(1);
    // 프론트한테 정상적으로 받았기 때문에 1 응답
})

app.get("/search/:id", (req, res) => {
    console.log(req.params);
    const result = members.filter(mem => mem.id === req.params.id)
    console.log("result : ", result);
    res.json(result[0]);
})

app.put("/modify", (req, res) => {
    members = members.filter(mem => mem.id !== req.body.id);
    members = members.concat(req.body);
    res.json(1);
})

app.delete("/delete", (req, res) => {
    members = members.filter(mem => mem.id !== req.body.id);
    res.json(1);
})

app.listen(3000, () => {console.log("3000server")})

app03.js

728x90

 

 

 

 

암호화

파일 app01.js 생성 및 npm 설치

 

암호화를 담당해주는 bcrypt 모듈도 설치

 

기본 서버 코드 작성

 

암호화 시

hash : 비동기적으로 작동 하므로 .then 이나 await 을 사용해줘야 함

hashSync : 동기적으로 작동하므로 따로 동기처리를 할 필요가 없다

 

DB 에 암호를 저장할때 암호화 과정을 진행한 값을 저장한다

 

암호화된 값을 비교할땐 compareSync(로그인 입력 비밀번호, DB에 저장된 비밀번호) 로 비교하여 결과 값이 true, false 로 나오는 것을 확인하여 사용한다.

 

 

 

 

 

 

 

 

 

 

fetch

fetch 를 사용하기 위해서 body-parser 모듈의 기능이 필요함

 

app02.js 파일 생성 후 코드 작성

 

보여질 폴더, 파일 추가

 

non_fetch.ejs 파일 작성

 

조회수 기능을 만들기 위해 count 함수 추가 후 전달

 

non_fetch.ejs 파일에 조회수 출력

 

fetch 를 사용하지 않고 자기 자신의 페이지로 가는 링크를 이동하면 웹페이지가 처음부터 끝까지 새로 갱신된다

( 즉, 웹을 처음부터 끝까지 다시 로딩한다 )

 

fetch 를 사용할 경로인 localhost:3000/fetch01 생성

 

fetch01.ejs 파일 생성하여 fetch 를 사용해서 자기 자신 경로를 다시 서버로 요청

 

fetch : 서버로 요청을 하는 것은 a 태그, location.href 와 동일하나 fetch 는 서버로 연동은 되지만 페이지를 요청하는 것이 아닌 데이터만 주고 받는다

 

.then 을 통해 동기처리, async - await 을 통해 동기 처리

 

fetch 를 사용해서 받아온 데이터는 비동기적으로 작동하기 때문에 동기적으로 작동하게끔 처리해줘야 하며, 전달 받은 데이터는 json 형식으로 변환해야 확인 할 수 있기 때문에 json() 을 사용하여 json 형식으로 변환시켜서 사용하며 이 과정도 비동기적으로 작동하기 때문에 동기적으로 작동하게끔 처리해줘야 한다

 

 

 

 

 

 

 

 

 

 

get : 데이터를 얻어올 때 사용 ( 파라미터를 get 방식으로 서버와 주고 받음 )

post : 데이터를 추가할 때 사용 ( 파라미터를 post 방식으로 서버와 주고 받음 )

put : 데이터를 수정할 때 사용

delete : 데이터를 삭제할 때 사용

app02.js 작성

 

rest.ejs 파일 생성하여 작성

 

 

 

 

 

다시 기본 웹 구동 파일 생성

 

<script>

    let content;
    window.onload = () => {
        content = document.getElementById("content");
        const getM = document.getElementById("getMembers");
        getM.addEventListener("click", getMembers);
        const regView = document.getElementById("regView");
        regView.addEventListener("click", registerView);
    }
    const registerView = () => {
        let msg = `<form id="form">
    <input type="text" name="id" placeholder="input id"><br>
    <input type="text" name="pwd" placeholder="input pwd"><br>
    <input type="text" name="name" placeholder="input name"><br>
    <input type="text" name="addr" placeholder="input addr"><br>
    <input type="button" onclick="register()" value="저장">
</form>`;

        content.innerHTML = msg;
    }
    const getMembers = () => {
        fetch("get_members", {method:"get"})
        .then(res => res.json())
        .then(m => {

        let msg = "<table border='1'>";
            msg += "<tr><th>아이디</th><th>이름</th><th>주소</th></tr>"
            m.forEach((mem) => {
                msg += "<tr>";
                msg += `<td>${mem.id}</td>
                        <td>${mem.name}</td>
                        <td>${mem.addr}</td>`;
                msg += "</tr>";
            })
            msg += "</table>"
            content.innerHTML = msg;
        })
    }
</script>

<div id="content">

</div>
<hr>
<button type="button" id="getMembers">목록보기</button>
<button type="button" id="regView">회원가입</button>

index.ejs 파일 작성

(app03.js 에서 json 형식으로 보내주는 members 변수를 fetch 를 통해 get 방식으로 가져와서 사용중.... )

 

코드 실행, SPA ( Single Page Application ) - 한 페이지에서 여러 기능이 다 작동

 

 

 

 

 

jquery 를 사용하여 프론트에서 백엔드로 데이터 넘겨주기

jquery 를 require

 

form 태그 안의 내용을 jquery 를 사용하여 배열로 만들어 arr 배열에 저장

> 해당 배열을 forEach 문을 사용해서 배열의 키를 우리가 사용할 키, 값으로 변경

arr : jquery 가 만들어준 데이터, data : jquery 가 만들어준 배열을 다시 생성

> fetch 를 통해 /register 경로를 서버에 요청하면서 post 방식으로 json 형식의 데이터를 보내는데 이 데이터는 body 안에 담겨서 보내지며 JSON.stringify() 를 통해 전송할 자료를 json 형식의 자료로 변환하여 보낸다

> .then 을 사용하여 서버로부터 돌아오는 응답을 json() 을 사용하여 json 형식으로 받는다

> .then 을 이용하여 받아온 json 데이터를 result 라는 변수에 담아서 사용한다

 

app03.js (백) 는 /register 경로로 넘어온 프론트에서 넘어온 데이터를 post 형식으로 받는다

> 이때 body-parser 가 필요하며, app.use(bodyParser.json()) 을 선언하여 받는 데이터를 json 형태로 받는다고 설정한다

> 이후 데이터를 처리하는 코드를 작성하며 res.json() 을 사용하여 json 형태로 프론트에 응답한다

728x90

 

 

 

 

DB 연동

파일 세팅

 

create table members(
id varchar2(20) primary key,
pwd varchar2(100),
name varchar2(20),
addr varchar2(100)
);
insert into members values('aaa','aaa','홍길동','산골짜기');
insert into members values('bbb','bbb','김개똥','개똥별');
insert into members values('ccc','ccc','고길똥','마포구');
commit;

DB 에 데이터 생성

 

npm install express --save
npm install ejs --save
npm install oracledb@^5.5.0 --save
npm install supervisor --save
npm install body-parser --save

npm 도 설치

 

app.js 기본 설정

이제는 router 경로를 최초 root 경로만 app.js 에서 설정한 뒤 세부 주소는 router.js 에서 나눠준다

 

router.js 에서는 app.js 에서 전달받은 app 을 사용한 뒤 return 으로 라우터를 반환하고 바로 module.exports 를 시켜버린다, index.ejs 작성

 

회원정보 클릭시 이동되는 /member/list 경로를 member_router.js 에 작성, router.js 에서는 경로가 /member 로 오면 member_router.js 가 경로를 관리하게끔 설정 - app.use("/member", [require 를 통해 받아온 member_router 의 이름] )

 

이제 member_router 에서 controller 로 연동할 것

/member/list 경로로 들어오면 컨트롤러에서 처리하도록 함 ( 좌 : member_router.js , 우 : member_ctrl.js )

 

db_config.js 에 db 에 접속하기 위한 기본 정보를 작성 후 exports

 

member_controller 에서 db 를 호출.... 하지만 DB 는 비동기적으로 연결되기 때문에 DB 에 연결되기 전에 console.log 구문이 먼저 실행되기 때문에 con 의 결과 값을 promise 로 가져온다

 

비동기적으로 돌아가는 함수 앞에 await 을 붙이고 이 전체 함수엔 비동기 함수가 들어있다는 것을 표현하는 async 을 넣은 뒤 코드를 실행하니 정상적으로 DB 에서 값을 가져오며 Object 자료형으로 가져오는 것을 확인

 

DB 에 접근해서 데이터를 가져오는 기능은 controller 에서 하지 않으므로 member_service 쪽으로 해당 기능을 옮긴다

 

service 에서는 DB 에 직접 접근하지 않으니 해당 기능을 또 DAO 로 넘겨준다

 

member_dao 에서 DB 에 접근

 

DAO 를 호출해서 사용하는 service 와 service를 호출해서 사용하는 controller 에도 async 와 await 을 걸어서 비동기로 작동하는 코드를 처리해줘야 promise 가 아닌 정상적인 연산을 끝낸 결과 값을 받을 수 있다

 

controller, service, dao

 

controller : service 와 연동하여 처리된 데이터를 ejs 와 스크립트 등에 전달하여 세부경로로 들어왔을때 클라이언트에게 보여줄 내용을 컨트롤한다

service : 기능을 담당하며 dao 에서 DB 에 접근해서 가져온 데이터를 가공해서 다시 controller 에 전송한다

dao : DB 에 접근하여 쿼리문을 처리한 뒤 DB 에서 돌아온 리턴 값을 그대로 service 에게 전달한다

 

member_index.ejs 에서 전달받은 데이터를 출력

 

데이터 추가 기능을 만들 것임

 

router 와 controller 에 register 경로로 들어올 때 기능 추가

 

연결될 register_form.ejs 생성 및 작성

 

정상적으로 연동, 회원가입을 누르면 /member/register 로 값들을 전달

 

회원가입 버튼 누르면 post 방식으로 들어오는 데이터를 처리할 /member/register 를 작성

 

controller 에서 post 방식으로 받은 데이터를 req.body 를 사용하여 출력해봄 - 정상 출력

 

service 에 insert 기능을 추가해서 거기에 입력 값을 전달

 

service 에서는 DAO 에 입력 값을 다시 전달하여 반환 값을 받고 반환 값에 따라 메세지가 출력되는 부분을 다시 리턴해준다

 

DAO 에서는 데이터를 전달 받아서 쿼리문을 실행시키고 쿼리문이 정상적으로 동작하면 result 에 객체 값이 전달되어 리턴된다, 만약 쿼리문 사용에 오류가 생기면 catch 로 코드가 진행되고 종료되기 때문에 result 는 0 으로 반환된다

sql 문에서 사용된 :id, :pwd, :name, :addr 은 키에 대한 값을 의미한다.

:id > id 키에 대한 값으로 변환

:pwd > pwd 키에 대한 값으로 변환

:name > name 키에 대한 값으로 변환

:addr > addr 키에 대한 값으로 변환

 

코드 실행 ( id 값이 db 에서는 primary key 로 설정되어 있으므로 동일한 zzz 아이디를 두 개 생성할 수 없어 문제 발생 )

 

member_index 를 볼때 이름에 a 태그로 회원 정보를 보는 기능을 추가 ( 하나는 경로로 아이디 값을 보여줌, 하나는 아이디 값으로 아이디를 보이지 않고 전달함 )

 

member_router 에 기능 추가

 

controller 에 기능 추가

 

service 는 controller 로 부터 전달 받은 id 정보를 DAO 에 전달

 

DAO 에서는 sql query 문 실행 후 리턴 값을 service 에 전달 ( sql 문을 작성할때 위 코드에서 DB 에 있는 id 열과 매개변수의 이름을 동일하게 id 로 맞춰줘야 한다 ), 위 코드에서 :id > mId.Id 를 의미

 

service 에서는 전달 받은 값의 rows 키 안에 들어있는 내용의 0번째 index 에 데이터가 들어있기 때문에 해당 값을 리턴

 

controller 에서는 해당 값을 member 라는 변수로 받아서 member_view.ejs 를 출력할때 값을 전달

 

member_view.ejs 생성 후 전달 받은 값으로 내용을 작성

 

회원 삭제 버튼을 누를 시 /member/delete 경로로 이동될 때 처리될 내용을 router 와 controller 에 작성

 

서비스에서도 전달 받은 아이디 값으로 DAO 에 전달하여 리턴을 받아 사용

 

DAO 에서는 해당 값을 전달 받고 쿼리문을 실행한 뒤 반환

 

삭제 기능 구현 완료

 

 

 

 

 

회원 수정 기능 구현

router 에 회원 수정 기능 경로 설정

( 경로 오타 : /modify_form 으로 수정해야 함 )

 

controller 에서 우선적으로 기존에 사용하던 멤버 보는 기능을 구현했던 service 의 함수를 재활용 하여 출력할 것임

 

modify_form.ejs 작성 후 수정 버튼 누르면 modify로 가기 때문에 modify 기능 추가

 

router 와 controller 작성
service 작성

 

DAO 작성, 쿼리문 결과 값 return

 

회원 수정 기능 구현 완료

 

 

 

 

 

네비게이션 bar 설정하기

( 모든 페이지에서 상단에 같은 ejs 파일을 적용하기 )

test.ejs 생성 및 네비게이션 bar 로 설정 및 적용

 

localhost:3000/ 으로 접속 시 나오는 페이지 상단에 test.ejs 파일의 내용이 출력되는 모습

 

- 네비게이션 bar 로 설정할때 주의점 -

<%- include("네비게이션 bar 로 사용할 파일의 경로")%>

위 코드로 적용할때 경로는 상대경로로 적용하는 경우 현재 파일 위치를 기준으로 변경해줘야 한다

728x90

'BE > Node.js' 카테고리의 다른 글

[Node.js] get, post, put, delete  (0) 2024.04.05
[Node.js] 암호화, fetch, spa  (1) 2024.04.04
[Node.js] DB 연동(1)  (0) 2024.04.02
[Node.js] 세션, post 방식 전달  (1) 2024.04.02
[Node.js] 쿠키  (0) 2024.04.01

 

 

 

 

DB 연동(1)

db_connect 폴더 생성 후 해당 폴더로 터미널 디렉토리 이동하여 필요한 모듈 설치


module 다운로드

npm install express --save
npm install ejs --save
npm install oracledb@^5.5.0 --save
npm install supervisor --save
npm install body-parser --save

 

app01.js 파일 생성

 

app01.js 간단히 작성

위 코드는 동기 방식 ( 순차적으로 코드를 읽는다 )

 

 

 

 

 

DB 를 연결하는 방식은 비동기 방식이다.

비동기 방식이므로 코드가 순차적으로 읽히지 않고 DB 에서 데이터를 읽어오지 못한 경우에도 DB 에서 가져온 데이터를 가지고 연산해야 하는 코드들이 실행되게 된다.... 이때 비동기 방식의 코드가 처리된 이후 코드를 실행하게 설정해 줄 필요가 있다.

비동기 방식의 함수인 connect 를 선언하고 해당 함수가 실행 된 뒤에 다른 코드를 실행하게끔 설정

 

1. 함수를 변수로 선언 [ con = connect(); 와 같이 ] 한 뒤 con.then 으로 con 함수가 실행되면 다음 함수를 실행하게끔 설정

2. 함수 내에 비동기 함수가 있음을 async 을 통해 선언 후 await 으로 비동기 함수가 동작한 뒤 다음 내용을 실행할 수 있도록 설정 

 

 

 

 

 

DB 를 연결 할때 비동기 방식을 처리한 뒤 연결하게끔 설정

비동기 처리 방식 2가지 ( .then / async - await 두 가지를 모두 사용해봄 )

728x90

 

 

 

 

세션

연습용 파일 세팅

 

파일 세팅

 

세션 모듈 다운로드

 

session 기본 Config 설정!!!! 필수★★★★★

 

app01.js 파일에 세션 설정

 

session router 와 session controller 작성

 

index.ejs 파일 작성

 

세션 설정용 경로, 확인용 경로 2개 라우터와 컨트롤러에 설정

 

set_session.ejs 와 get_session.ejs 파일 생성 및 작성

 

컨트롤러에서 get_session 페이지에 세션 정보를 변수로 담아 전달하는 코드를 작성

req.session.[ 세션키 ]

 

코드 실행

 

라우터와 컨트롤러에 delSession 경로를 추가

 

del_session.ejs 작성

 

키 값으로 특정 세션을 삭제하는 경우와 모든 세션을 삭제하는 경우의 코드 차이

delete req.session.[세션 키] : 특정 키의 세션을 삭제

req.session.destroy() : 모든 세션을 삭제

 

 

body-parser : post 방식의 데이터를 가져올때 사용하는 방식

코드 실행

 

세션도 동일하게 만료시간을 설정해줄 수 있다

( session 의 default 자동 만료 시간은 30분 )

 

세션 만료시간 설정

세션의 만료 시간 설정, 5초 후 세션이 만료되게 설정

 

 

 

 

 

body-parser 모듈 설치

body-parser : post 방식의 데이터를 가져올때 사용하는 방식

body-parser 설치

 

body-parser 를 middle-ware 로 등록

 

로그인 기능을 구현하기 위해 router 와 controller 에 경로를 추가

 

login.ejs 작성 ( 로그인 정보를 세션으로 담아 보낼 것이기 때문에 post 형식으로 전달 )

 

router 에 login_check 경로 생성 ( post 방식으로 전달했기 때문에 router.post 를 사용 )

라우터에 post 방식으로 받아오기 때문에 router.post 를 사용한다

controller 에서 세션에 대한 정보를 받아서 콘솔에 출력하는 코드 작성

 

세션 값 확인

 

로그인 검증 코드를 controller 에 작성 ( DB 는 더미 데이터 변수 사용 )

 

success 경로로 가는 기능을 router 와 controller 에 작성

 

success.ejs 파일 생성 및 작성

 

로그인 정보가 있을때만 success 페이지로 보내는 코드를 작성, 로그인 실패 시 로그인 실패 문구 출력 코드도 작성

success 함수 부분에 if 문 안에 req.session.username 은 오타 => req.session.userName 으로 변경해야 함

 

스크립트를 처리하는 함수를 따로 선언

 

함수로 간단하게 출력 문구 코드 대체

 

로그인 부분에 username 키를 전달

 

로그인 페이지에 접근했을때 username 이라는 세션이 존재한다면 로그인 문구 출력, 세션이 존재하지 않는다면 로그인 창을 출력

 

router 와 controller 에 세션을 모두 만료시키는 기능을 추가

 

코드 실행

( 시크릿 모드로 실행시키면 개발자 모드를 켜놓지 않고 /localhost:3000/session/success 로 직접 진입 시 alert 창이 출력되지 않고 바로 /localhost:3000/session/login 으로 리다이렉트 되는 현상이 발생.... 시크릿 모드 해제 또는 시크릿모드에서 개발자 모드 활성화 및 다른 브라우저로 작동시키면 정상 작동 확인 )

 

 

 

 

 

파일로 세션을 저장해서 관리하는 방법

( 개발할때 테스트가 필요한 경우 코드를 수정하면 세션이 초기화되기 때문에 파일로 저장해놓고 사용 )

 

npm install session-file-store

session-file-store 모듈 필요

사용 방법은 구글링 해보기

 

 

 

 

 


 

 

 

 

 

실습 예제

실습 예제

 

728x90

 

 

 

 

cookie, session

cookie_session 디렉토리 생성 후 필요한 모듈 설치
연습용 파일 세팅

 

파일 세팅 완료

 

스크립트 추가

 

기본 코드 작성 ( app.js, cookie_router.js, cookie_controller.js, cookie01.ejs )

 

서버 실행 확인

 

 

쿠키와 세션을 사용하는 이유 : HTTP 통신은 비연결성 통신( 연결 시도 후 연결이 되면 끊기는 형식 - 예를 들어 클라이언트가 request 를 서버로 전송한 뒤 연결을 끊음, 그럼 서버는 클라이언트에게 response 를 보낸 후 연결을 끊음.... 그렇기 때문에 로그인 정보와 같은 것을 쿠키와 세션에 보관해서 인증한다 )

 

쿠키 : 클라이언트가 관리 ( 보안에 좋지 않기 때문에 쿠키는 로그인에는 잘 사용하지 않는다 )

세션 : 서버가 관리

 

app01.js 파일에 cookie-parser 모듈을 불러온다

 

app 에서 동작하는 cookieParser 라는 값을 app 에서 사용할 수 있게끔 middle ware 로 위임

 

cookie_ctrl.js 에서 response 에 cookie 를 추가 이때 res.cookie("쿠키 키","쿠키 값"); 으로 표현한다

 

다시 웹에 접속해 개발자 모드(F12)에서 Application 탭에 들어가서 쿠키 탭을 확인하면 쿠키가 정상적으로 받아지는 것을 확인할 수 있다

 

쿠키 설정 값을 변수화하여 쿠키의 속성 값을 적용한다

 

쿠키가 5초뒤에 삭제됨

 

전달 받은 쿠키의 값이 제대로 출력되는지 cookie01.ejs 파일에 전달하여 출력해보기

 

쿠키 관리를 위해 팝업을 띄우기

 

 

 

 

 


 

 

 

 

 

쿠키를 생성하여 5초동안 팝업이 뜨지 않게 하기

localhost:3000/cookie02 로 접속하면 창 띄우기

 

쿠키 정보가 담긴 userCookie 변수를 cookie02.ejs 를 실행할때 전송하기

 

cookie02.ejs 에서는 쿠키가 존재하지 않는다면 팝업창을 띄우기.... popup02 를 띄우게 라우터와 컨트롤러에 다시 설정하러 가야함

 

popup02 경로를 설정

 

popup02.ejs 파일에서 하루동안 열지 않음!!! 텍스트나 체크박스를 클릭하면 makeCookie 함수가 실행되며 이 함수에는 /cookie/makeCookie 경로로 이동시키는 기능과 창을 닫는 기능을 스크립트로 생성해놓는다

 

makeCookie 가 실행되면 쿠키를 적용해주고 창을 닫는다

 

코드 실행 시 쿠키를 가지고 있는 5초 동안은 새로고침을 해도 팝업창이 출력되지 않는 모습

 

 

 

 

 


 

 

 

 

 

쿠키를 암호화 하기, 쿠키를 config.js 파일로 분리하기

기존에 있던 cookieConfig 를 config.js 파일을 따로 생성하여 분리하면서 signed : true 옵션을 사용하여 암호화 시킨다

signed : true => 쿠키 암호화 ( 암호화 키 값은 cookieParser 를 미들웨어로 등록할때 괄호 안에 키 값을 입력해준다 )

 

이후에 cookieConfig 를 require 하여 불러온 뒤 사용한다, 또한 쿠키를 가져올땐 req.signedCookies.쿠키이름 을 사용하여 쿠키를 가져온다... 기존에는 req.cookies.쿠키이름 이었지만 signedCookies 로 암호화된 쿠키를 가져옴을 명시한다

 

 

 

 

 


 

 

 

 

 

장바구니 만들기

더미로 장바구니 DB 생성

 

라우터에 경로 추가

 

컨트롤러에 cart 경로와 서비스 추가

 

cookie_service 에 더미 DB 반환 코드 추가 및 export

 

전달 받은 더미 데이터 forEach 문으로 나열하기

 

상품 목록에 상품 아이디로 링크를 걸기 링크 클릭하면 /cookie/save 로 넘어가야 하기 때문에 경로를 라우터와 컨트롤러에 추가

 

/save/:goods 에서 경로 뒤에 :goods 는 콜론 뒤에 /save/ 경로 뒤에 오는 내용을 goods 라는 변수로 저장한다는 뜻

 

goods 라는 변수로 넘겨받은 /save/ 뒤의 경로 정보를 params 를 사용하여 변수로 저장한 뒤 alert 창을 출력하고 다시 /cookie/cart 경로로 돌려보낸다

 

코드 실행

 

쿠키 정보가 있는지 없는지 확인 후 변수에 쿠키에 저장될 변수를 생성 및 데이터 추가

 

cookie_service 에서 전달받은 cart_list 에 쿠기를 저장한 뒤 cart_list 를 다시 반환

 

저장 목록 확인을 눌렀을때 이동되는 view_list 경로를 라우터에 설정
controller 에도 설정하여 만약 cart_list 라는 쿠키를 사용자가 가지고 있지 않다면 alert 창을 띄운 후 다시 /cookie/cart 로 보내고 사용자가 cart_list 쿠키를 가지고 있다면 views_list.ejs 에 cart_list 쿠키를 값으로, list 를 키로 설정하여 전달

 

view_list.ejs 파일 생성하여 해당 내용을 출력하게 설정

 

코드 실행 영상 ( 쿠키는 현재 5초 뒤 삭제되게끔 설정되어 있으므로 5초가 경과되면 자동으로 저장 목록이 삭제된다 )

 

 

 

 

 

실습 예제

실습 예제

 

예제 풀이

기존에 쿠키가 5초가 지나면 삭제되게 설정해 놓은 문구를 제거 후 시작하기

728x90

+ Recent posts