본문 바로가기

토이 프로젝트

[자바스크립트] 작은 도서관 프로그램 만들기 (MySQL, Express, Fetch API, Node.js) - Mysql, express, fetch api crud example (1)

2020/10/08 - [토이 프로젝트] - [자바스크립트] 작은 도서관 프로그램 만들기 (MySQL, Express, ejs, Node.js) - Mysql, express, ejs crud example

 

[자바스크립트] 작은 도서관 프로그램 만들기 (MySQL, Express, ejs, Node.js) - Mysql, express, ejs crud example

2020/09/03 - [토이 프로젝트] - [자바스크립트] 작은 도서관 프로그램 만들기 (쿠키, 로컬, 세션 스토리지의 개념 포함) [자바스크립트] 작은 도서관 프로그램 만들기 (쿠키, 로컬, 세션 스토리지의 ��

ukcasso.tistory.com

  지난 시간엔 ejs를 활용해서 ejs 문법을 넣고  crud를 구현해보았다. 이번에는 fetch api를 이용하여 html 파일을 더블 클릭해서 열어놓은 다음 서버를 연결하면 책들의 내용을 서버에서 받아오는 프로그램을 만들기로 하였다. fetch api는 superagent나 axios와 다르게 설치하지 않아도 사용가능하다.

  전체 코드를 올려놓고 주석으로 설명을 달아 놓을 예정이므로 코드안에 주석을 보면서 차근차근 이해하고 자신의 프로젝트로 옮겨보는 것을 추천한다.

 

 

사전 작업

npm install --save express

npm install --save mysql

npm install --save sequelize

npm install --save body-parser

npm install --save-dev sequelize-cli
// 다른 url 주소에서 정보를 가져오는 것을 막아놓은 브라우저들을 위하여 cors를 사용한다.
npm install --save cors

 

 


Conceptual Diagram Of This Project

  이번 도서관 프로젝트의 개념도이다. 이것은 내가 이해한 개념을 토대로 작성한 것이니 100% 정답이라고 볼 수는 없다. 나의 생각이 틀렸거나 더 추가적인 개념이 있다면 댓글을 통해 남겨주시면 좋을 것 같다.

 

개념도

 

 


/server/index.js

'use strict';

// 사용할 모듈 불러오기
const express = require('express');
const app = express();
const { Sequelize, DataTypes } = require('sequelize');
const env = process.env.NODE_ENV || 'development';

// sequelize에서 접속할 DB config 정보
const config = {
  "development": {
    "username": "root",
    "password": ****,
    "database": "library",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}[env];

// 사용할 모듈 불러오기
// cor는 다른 url에서 정보를 가져오는 것을 막아놓은 브라우저에게 허용하게 한다.
let cors = require('cors')
let http = require('http');

// bodyparser가 없으면 아래에서 req.body를 사용하지 못한다.
let bodyParser = require('body-parser');
let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

// sequelize로 books라는 테이블을 만들고 테이블안에 넣을 정보를 넣어주는 것이다.
const books = sequelize.define('books', {
  title: {
    type: DataTypes.STRING(200),
    allowNull: true,
  },
  content: {
    type: DataTypes.STRING,
    allowNull: true,
  },
  author: {
    type: DataTypes.STRING,
    allowNull: true,
  },
  date: {
    type: DataTypes.STRING,
    allowNull: true,
  }
});

// sequelize로 sync해주어 DB에 접속한다.
sequelize.sync({ force: false }).then( () => {
  console.log("DB connection is successful");
  
}).catch(err => {
  console.log("DB connection faild");
  console.log(err);
});

// 미들웨어로 cors와 bodyparser를 사용할 것이라고 정해주는 것이다.
app.use(cors())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended : false}));

// /get이라는 url로 db안에 모든 정보를 json정보로 보내준다.
app.get('/get', async(req, res) => { 
  await books.findAll().then(result => {
    res.json(result)
  });
});

// CREATE: url /inputBook으로 library.js에서 함수로 받아온 값들을 DB에 create해준다.
app.post('/inputBook', async (req, res) => {
  await books.create({
    title : req.body.title,
    content : req.body.content,
    author : req.body.author,
    date : req.body.date
  }).then(result => {
    console.log("Success input data" + result);
    res.redirect('/');
  }).catch(err => {
    console.log("Fail update data" + err);
  });
});

// UPDATE: url /edit/:id로 library.js에서 함수로 받아온 값들을 id에 맞는 곳에 update해준다.
app.post('/edit/:id', async(req, res) => {
  await books.update({
    title : req.body.title,
    content : req.body.content,
    author : req.body.author,
    date : req.body.date
  }, {
    where : {id: req.params.id}
  }).then(result => {
    console.log("Success update data" + result);
    res.redirect('/');
  }).catch(err => {
    console.log("Fail update data" + err)
  })
})

// DELETE: url /delete/:id로 library.js에서 id를 가져와 delete해준다.
app.delete('/delete/:id', async(req, res) => {
  await books.destroy({
    where: {id: req.params.id}
  }).then(result => {
    console.log(result)
    res.redirect('/');
  }).catch(err => {
    console.log("Fail delete data" + err);
  });
});

http.createServer(app).listen(3000, () => {'Server is running on port 3000...'})

 

 

library.js

// 이 element(bTable이라는 id에서 사용하기 위해)와 db는 미리 선언해준것이고 showHtml은 내부에서 사용할 코드들을 줄인 것이다.
const element = document.getElementById("bTable");
let db = [];
function showHtml(i) {
  return  `
          <td>${i + 1}</td>
          <td><a href="#" id='${i}' onclick='popInfo(this.id);'>${db[i].title}</a></td>
          <td>${db[i].content}</td>
          <td>${db[i].author}</td>
          <td>${db[i].date}</td>
          <td><button id="${db[i].id}" type="submit" onclick="editBook(this.id)" style="float:left">수정</button>                                  
          <button id="${db[i].id}" type="submit" onclick="deleteBook(this.id)" style="float:right">삭제</button></td>
          `;
}

// fatch api로 /get으로 data를 받아오고 받아온 데이터를 db라는 배열에 넣어준다. 넣어주는 이유는 사용하기 쉽게 하기 위해서이다.
function startServer() {
  fetch("http://localhost:3000/get")
    .then((response) => response.json())
    // showTable()은 바로 실행하기 위해 선언
    .then((data) => {db = data; showTable();})
    .catch(err => {
      console.log('Fetch Error', err)
    })
}

// DB정보들을 table에 보여준다.
function showTable() {
  for(let i = 0; i <= db.length - 1; i++) {
      element.innerHTML += showHtml(i);
  };
  for(let i = 0; i < 5 - db.length; i++) {
    element.innerHTML += `<td>-</td>
                          <td>-</td>
                          <td>-</td>
                          <td>-</td>
                          <td>-</td>
                          <td>-</td>
                          `;
  };
};

// 책을 등록하는 함수로 fetch api를 통해 /server/index.js에 정의되있는 url들과 소통한다.
function inputBook() {
  fetch("http://localhost:3000/inputBook", {
    method: "POST",
    body: JSON.stringify({
      title: document.getElementById("title").value,
      content: document.getElementById("content").value,
      author: document.getElementById("author").value,
      date: document.getElementById("date").value
    }),
    headers: {
      "Content-type": "application/json; charset=UTF-8"
    }
  })
  .then(response => response.json())
  .then(json => console.log(json))
  location.reload();
}

// 책을 삭제하는 함수로 fetch api를 통해 /server/index.js에 정의되있는 url들과 소통한다.
function deleteBook(clickedId){
  fetch("http://localhost:3000/delete/" + clickedId, {
    method: "DELETE"
  })
  .then(response => response.json())
  .then(json => console.log(json))
  location.reload();
}

// 책을 수정하는 함수로 fetch api를 통해 /server/index.js에 정의되있는 url들과 소통한다.
function editBook(clickedId) {
  fetch("http://localhost:3000/edit/" + clickedId, {
    method: "POST",
    body: JSON.stringify({
      title: document.getElementById("title").value,
      content: document.getElementById("content").value,
      author: document.getElementById("author").value,
      date: document.getElementById("date").value
    }),
    headers: {
      "Content-type": "application/json; charset=UTF-8"
    }
  })
  .then(response => response.json())
  .then(json => console.log(json))
  location.reload();
}

// 책 제목을 클릭하면 db정보에서 해당 id 값에 맞는 내용들을 가져온다.
function popInfo(id) {
  document.getElementById("title").value = db[id].title;
  document.getElementById("content").value = db[id].content;
  document.getElementById("author").value = db[id].author;
  document.getElementById("date").value = db[id].date;
};

// 책을 찾는 함수인데 db안에 넣어놓은 것을 활용하여 조건에 맞게 bTable에 뿌려준다.
function searchBook(data, sDate, eDate) {
  console.log(data, sDate, eDate)
  element.innerHTML = ``;
  if(!data && isNaN(sDate)) {
      location.reload();
  } else {
    for(let i = 0; i <= db.length - 1; i++) {
      let popData = (db[i].title.includes(data)) || (db[i].author.includes(data)) || (db[i].content.includes(data));
      if(!isNaN(sDate) ? popData && sDate <= new Date(db[i].date) && eDate >= new Date(db[i].date) : popData) {
        element.innerHTML += showHtml(i);
      };
    };
  };
};

 

 

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>작은 도서관</title>
    </head>
    <style>
    </style>
    <link rel="stylesheet" href="./style.css">
    <body onload="startServer()">
        <div id="library">
            <center>
                <div id="logo"><br>
                    <center>
                        <a href="#"><img src="./vendit-logo-white.png" onclick="location.reload()" width="150px"></a>
                    </center>
                </div>
            </center>
            <center>
                <div id="search">
                    <center>
                        <!--<b>서적 검색</b><br>-->
                        <input type="search" id="searchInput" placeholder="제목, 내용, 저자로 검색">
                        <input class="dateSet" type="date" id="dateStart" >
                        ~
                        <input class="dateSet" type="date" id="dateEnd" >
                        <button id="searchBtn" type="submit" onclick="searchBook(document.getElementById('searchInput').value, 
                        new Date(document.getElementById('dateStart').value),
                        new Date(document.getElementById('dateEnd').value))">검색</button>
                    </center><br>
                </div>
            </center>
            <center>
                <div id="table">
                    <!--<b>찾은 서적 목록</b><br>-->
                    <center>
                        <table>
                            <thead>
                                <tr><th>순번</th><th>제목</th><th>내용</th><th>저자</th><th>출간날짜</th><th>수정/삭제</th></tr>
                            </thead>
                            <tbody id="bTable"></tbody>
                        </table>
                    </center>    
                </div>
            </center>
            <center>
                <div id="newBooks">
                    <center><br>
                            <!--<b>새로운 서적 등록</b><br>-->
                            <input class="new" type="text" id="title" name="title" placeholder="제목">
                            <input class="new" type="text" id="author" name="author" placeholder="저자">
                            <input class="dateSet" type="date" id="date" name="date" placeholder="출간날짜"><br><br>
                            <textarea name="contents" type="text" id="content" name="content" placeholder="내용"></textarea><br>
                            <button id="putBtn" type="submit" onclick="inputBook()">등록</button>
                    </center><br>
                </div>
            </center>
        </div>
        <script src="./library.js"></script>
    </body>
</html>

 

 

style.css

.dateSet {
  width: 110px;
  height: 16px;
}
#logo {
  background-color: #5E6698;
  width: 950px;
  padding: 5px;
}
#search {
  background-color: #5E6698;
  width: 950px;
  padding: 5px;
}
#table {
  background-color: white;
  width: 950px;
  padding: 5px;
  height: 275px;
  overflow: auto;
}
#newBooks {
  background-color: #5E6698;
  width: 950px;
  padding: 5px;
}
#searchInput {
  width: 440px;
}
#searchBtn {
  width: 100px;
}
#putBtn {
  width: 400px;
  height: 50px;
}
#delBtn {
  width: 400px;
  height: 50px;
}
#title {
  width: 505px;
}
#content {
  width: 798px;
  height: 100px;
  resize: none;
}
table {
  background-color: white;
  width: 810px;
  table-layout: fixed;
  word-break: break-all;
}
tr {
  background-color: white;
  padding: 10px;
  border: 0px solid black;
}
th {
  padding: 10px;
  border: 0px solid black;
}
td {
  padding: 10px;
  border: 0px solid black;
  text-align: center;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
a {
  color: black;
  text-decoration: none;
}
a:hover {
  color: rgb(74, 138, 211);
}

 

 


 

html 파일만 열었을 때 스크린 샷이다.

html을 열었을 때

 

html 파일을 열고 서버를 

node index.js

로 열었을 때 내용을 받아오는 모습이다.

 

html을 열고 서버를 연결시켰을 때

 

서버를 연결시키고 책을 등록했을 때 모습이다.

서버가 연결된 상태에서 책 등록했을 때

 


아래 github에 정확한 소스코드가 올라와 있습니다. 다운로드하시고 npm install로 모듈 설치 후 자신의 mysql 정보 입력 후 실행하시면 됩니다.

https://github.com/ukcasso/library 

 

ukcasso/library

second-library. Contribute to ukcasso/library development by creating an account on GitHub.

github.com