2023.11.24(금)

💾Database

🖋️SQL (Structured Query Language)

  • DB에 연산을 요청하기 위해 사용되는 언어로 데이터 생성(INSERT), 조회(SELECT), 수정(UPDATE), 삭제(DELETE) 등과 같은 기능 수행 가능

🐋Docker

  • Go언어로 작성된 리눅스 컨테이너 기반으로 하는 오픈소스 가상화 플랫폼
  • 리눅스의 응용 프로그램들을 프로세스 격리 기술들을 사용해 컨테이너로 실행하고 관리하는 오픈 소스 프로젝트 (특정한 서비스를 패키징하고 배포하는데 유용한 오픈소스 프로그램)

도커 컨테이너는 일종의 소프트웨어를 소프트웨어의 실행에 필요한 모든 것을 포함하는 완전한 파일 시스템 안에 감싼다. 여기에는 코드, 런타임, 시스템 도구, 시스템 라이브러리 등 서버에 설치되는 무엇이든 아우른다. 이는 실행 중인 환경에 관계 없이 언제나 동일하게 실행될 것을 보증한다.

  • 이미지(Image)와 컨테이너(Container)

    ImageBuild and RunContainer\textcolor{Turquoise}{\text{Image}}\xrightarrow{\text{Build and Run}}\textcolor{Turquoise}{\text{Container}}

    • 이미지
      • 컨테이너 실행에 필요한 파일과 설정값등을 포함하고 있는 파일
      • Docker Hub에 다양한 이미지를 업로드/다운로드할 수 있음
    • 컨테이너
      • 이미지를 Build 과정을 거쳐서 메모리에 올리고 Run을 통해 동작하는 프로세스
  • 참고자료
  • Docker 설치🔗
  • Docker에서 MariaDB
    Terminal에서 명령어 입력
    • mariadb 이미지를 가져와서 설치 & 설정(port = 3306, password = root)
      docker pull mariadb
      docker run --name mariadb -d -p 3306:3306 --restart=always -e MYSQL_ROOT_PASSWORD=root mariadb
    • 현재 내 컴퓨터에 있는 이미지 보기 : docker images
    • mariadb가 있는 컨테이너 접속 : docker exec -it mariadb /bin/bash
    • 현재 실행되고 있는 컨테이너 보기 : docker ps
    • mariadb 실행 : mariadb -u root -p

🦭MariaDB(MySQL) Basic Commands

  • 명령어를 모두 소문자로 적었지만 관습적으로 가독성을 위해 대문자로 많이 쓰는 것 같다.
  • JavaScript처럼 꼭 문장 끝에 ;를 쓰자.
  • DB 보기 : show databases;

  • DB 생성하기 : create database db_name;

  • DB 삭제하기 : drop database db_name;

  • DB 사용하기 : use db_name;

  • Table 보기 : show tables;

  • Table 생성 : create table tbl_name (create_definition,...);

  • Table 삭제 : drop table tbl_name;

  • Table 이름 변경 : rename table tbl_name to new_tbl_name;

  • Table 데이터 삽입 : insert [col1, col2, … ] into tbl_name values (val1, val2, …), (val1, val2, …), ...;

  • Table 데이터 조회 : select col_name, ... from tbl_name;

    *으로 전체 column 가져올 수 있음

  • Table 데이터 수정 : update tbl_name set col = val where cond;

  • Table 데이터 삭제 : delete from tbl_name where cond;

🔗Node.js에 DB 연동

  • VS Code Terminal에 npm install mysql --save로 Node.js에 mysql(mariadb의 모체가 mysql이기 때문) 모듈 설치

  • database/connect/mariadb.js를 생성하고 mariadb의 database와 웹 서버를 연결 ([mariadb](https://hub.docker.com/_/mariadb) 이미지를 가져와서 설치 & 설정(port = 3306, password = root) 에서 설정한 값들을 넣어줌)

    const mariadb = require('mysql');
    
    const conn = mariadb.createConnection(  // mariadb의 database와 연결
        {
            host: 'localhost',
            port: 3306,
            user: 'root',
            password: 'root',
            database: 'tennis'
        }
    );
    
    module.exports = conn;
  • 최종 Code

    • main.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <link rel="shortcut icon" href="./img/tennis.ico" type="image/x-icon">
          <link rel="stylesheet" href="main.css">
          <title>Tennis Market</title>
      </head>
      <body>
          <div id="title">
              <h1>&#127934;Tennis Market</h1>
              Welcome to Tennis market!
              <br>
              Enjoy your shopping.
              <br>
              <br>
              <button class="link_btn"><a href="./orderlist">&#128722;Order List</a></button>
          </div>
          <div id="card_list">
              <div class="card">
                  <img class="card_img" src="./img/redRacket.jpg">
                  <p class="card_title">Red Racket</p>
                  <input class="card_btn" type="button" value="order" onclick="location.href='/order?productId=1';">
              </div>
              <div class="card">
                  <img class="card_img" src="./img/blueRacket.jpg">
                  <p class="card_title">Blue Racket</p>
                  <input class="card_btn" type="button" value="order" onclick="location.href='/order?productId=2';">
              </div>
              <div class="card">
                  <img class="card_img" src="./img/blackRacket.jpg">
                  <p class="card_title">Black Racket</p>
                  <input class="card_btn" type="button" value="order" onclick="location.href='/order?productId=3';">
              </div>
          </div>
          <!-- <script src="main.js"></script> -->
      </body>
      </html>
    • orderlist.html

      • table 태그의 아래 부분은 웹 서버에서 DB로부터 가져온 값으로 표를 만들어 넣을 것이기 때문에 주석 처리함
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <link rel="shortcut icon" href="./img/tennis.ico" type="image/x-icon">
          <link rel="stylesheet" href="main.css">
          <title>Order List</title>
      </head>
      <body>
          <div id="title">
              <h1>&#128722;Order List</h1>
              <button class="link_btn"><a href="./">&#127968;Go Home</a></button>
          </div>
          <div id="table">
              <table>
                  <th>No</th>
                  <th>Product</th>
                  <th>Description</th>
                  <th>Price</th>
                  <th>Order Date</th>
                  <!-- <tr>
                      <td>1</td>
                      <td>product1</td>
                      <td>description1</td>
                      <td>price1</td>
                      <td>date1</td>
                  </tr>
                  <tr>
                      <td>2</td>
                      <td>product2</td>
                      <td>description2</td>
                      <td>price2</td>
                      <td>date2</td>
                  </tr>
                  <tr>
                      <td>3</td>
                      <td>product3</td>
                      <td>description3</td>
                      <td>price3</td>
                      <td>date3</td>
                  </tr>
              </table> -->
          </div>
      </body>
      </html>
    • main.css

      • 다른 교육생분께서 공유해주신 코드에서 추가/수정함
      html {
          font-size: 10px;
      }
      
      body {
          margin: 0;
      }
      
      a {
          text-decoration: none;
          color: black;
      }
      
      table {
          margin: auto;
          border: 1px solid #545454;
          border-collapse: collapse;
          font-size: 1.5rem;
      }
      
      th, td {
          border: 1px solid #444444;
          padding: 0.5rem;
      }
      
      #table {
          margin-top: 1rem;
      }
      
      #title {
          text-align: center;
          width: 100vw;
          font-size: 1.5rem;
      }
      
      #card_list {
          display: flex;
          flex-wrap: wrap;
          justify-content: space-around;
          margin-top: 10rem;
      }
      
      .card {
          width: calc(33% - 1rem);
          margin: 0.5rem;
          text-align: center;
      }
      
      .card_img {
          width: calc(75% - 1rem);
      }
      
      .card_title {
          font-size: 15px;
          font-weight: bold;
      }
      
      .card_btn {
          position: relative;
          border: 0;
          padding: 0.8rem 3rem;
          display: inline-block;
          text-align: center;
          color: white;
          box-shadow:0px 4px 0px #454545;
          background-color: #7b7b7b;
          border-radius:8px;
      }
      
      .card_btn:hover {
          background-color: rgb(161, 161, 161);
      }
      
      .card_btn:active {
          box-shadow: none;
      }
      
      .link_btn {
          position: relative;
          border: 0;
          padding: 0.8rem;
          display: inline-block;
          text-align: center;
          box-shadow:0px 4px 0px #8a8a8a;
          background-color: #d4d4d4;
          border-radius:8px;
      }
      
      @media screen and (max-width: 768px) {
          #card_list {
              margin-top: 2.5rem;
          }
      }
      @media screen and (max-width: 480px) {
          .card {
              width: 100%;
          }
      }
    • index.js

      let server = require('./server');
      let router = require('./router');
      let requestHandler = require('./requestHandler');
      
      const mariadb = require('./database/connect/mariadb');
      mariadb.connect();
      
      server.start(router.route, requestHandler.handle);
    • server.js

      • url.parse()가 더 이상 사용되지 않아서 new URL()로 대체함
      • searchParams로 url로 부터 query 값들을 가져와야 하고 get() method로 특정 query 값을 가져올 수 있음
      let http = require('http');
      // let url = require('url'); // URL class is a global reference for require('url').URL
      
      function start(route, handle){
          function onRequest(request, response) {
              // let pathname = url.parse(request.url).pathname; //url.parse is deprecated.
              let pathname = new URL(request.url, `http://${request.headers.host}`).pathname;
              // let queryData = url.parse(request.url, true).query; //url.parse is deprecated.
              let queryData = new URL(request.url, `http://${request.headers.host}`).searchParams;
              if (!request.url.includes('favicon.ico')) {
                  // route(pathname, handle, response, queryData.productId);
                  route(pathname, handle, response, queryData.get('productId'));
              }
          }
      
          http.createServer(onRequest).listen(8888);  // localhost:8888
      }
      
      exports.start = start;
    • router.js

      function route(pathname, handle, response, productId) {
          console.log('pathname :', pathname);
          if (typeof handle[pathname] == 'function') {
              handle[pathname](response, productId);
          } else {    // 등록된 path가 아닌 경우
              response.writeHead(404, {'Content-Type':'text/html'});
              response.write('<h1>Page Not Found &#128531;</h1><br><a href="./">&#127968;Go Home</a>');
              response.end();
          }
      }
      
      exports.route = route;
    • requestHandler.js

      • 요청을 실질적으로 모두 처리하는 파일
      • pathname에 따라 함수를 mapping해서 처리하고, 페이지 요청의 경우 file system module을 가져와서 해당 파일을 가져와서 보내줘야 함
      • DB에서 table 값을 가져와야 하는 경우 mariadb.query()를 통해 query문으로 처리를 함
      • response.end()는 반드시 response.write()와 같은 코드 블럭에 위치해야 함 (response.write()를 실행한 뒤 response.end()를 실행하지 않으면, 클라이언트는 서버로부터 응답이 완료되지 않은 상태이기 때문에 해당 위치에서 다음 작업을 위해 계속해서 대기하게 되기 때문)
      const fs = require('fs');   // file system module
      const main_view = fs.readFileSync('./main.html', 'utf-8');
      const orderlist_view = fs.readFileSync('./orderlist.html', 'utf-8');
      
      const mariadb = require('./database/connect/mariadb');
      
      function main(response) {
          mariadb.query("SELECT * FROM product", function(err, rows) {
              console.log(rows);
          })
      
          response.writeHead(200, {'Content-Type':'text/html'});
          response.write(main_view);
          response.end();
      }
      
      function redRacket(response) {
          fs.readFile('./img/redRacket.jpg', function(err, data) {
              response.writeHead(200, {'Content-Type':'text/html'});
              response.write(data);
              response.end();
          });
      }
      
      function blueRacket(response) {
          fs.readFile('./img/blueRacket.jpg', function(err, data) {
              response.writeHead(200, {'Content-Type':'text/html'});
              response.write(data);
              response.end();
          });
      }
      
      function blackRacket(response) {
          fs.readFile('./img/blackRacket.jpg', function(err, data) {
              response.writeHead(200, {'Content-Type':'text/html'});
              response.write(data);
              response.end();
          });
      }
      
      function mainCSS(response) {
          fs.readFile('./main.css', function(err, data) {
              response.writeHead(200, {'Content-Type':'text/css'});
              response.write(data);
              response.end();
          });
      }
      
      function order(response, productId) {
          response.writeHead(200, {'Content-Type':'text/html'});
          const options = {
              year: 'numeric',
              month: '2-digit',
              day: '2-digit',
              hour: '2-digit',
              minute: '2-digit',
              second: '2-digit'
          };
          mariadb.query(`INSERT INTO orderlist VALUES (${productId}, '${new Date().toLocaleDateString('ko-KR', options)}');`, function(err, rows) {
              if (err) {
                  console.log(err);
                  response.write('<a href="./">order success</a>');
                  response.end();
              } else {
                  console.log(rows);
                  response.write('<a href="./">order success</a>');
                  response.end();
              }
          })
      }
      
      function orderlist(response) {
          response.writeHead(200, {'Content-Type':'text/html'});
          const sqlQuery = `
              SELECT orderlist.product_id, product.name, product.description, product.price, orderlist.order_date
              FROM orderlist
              JOIN product ON orderlist.product_id = product.id
              ORDER BY orderlist.order_date;
          `;
          mariadb.query(sqlQuery, function(err, rows) {
              response.write(orderlist_view);
              rows.forEach(element => {
                  response.write(`
                      <tr>
                          <td>${element.product_id}</td>
                          <td>${element.name}</td>
                          <td>${element.description}</td>
                          <td>${element.price}</td>
                          <td>${element.order_date}</td>
                      </tr>
                  `);
              });
              response.write("</table>");
              response.end();
          })
      }
      
      let handle = {};
      handle['/'] = main;
      handle['/order'] = order;
      handle['/orderlist'] = orderlist;
      
      /* image directory */
      handle['/img/redRacket.jpg'] = redRacket;
      handle['/img/blueRacket.jpg'] = blueRacket;
      handle['/img/blackRacket.jpg'] = blackRacket;
      
      /* css file */
      handle['/main.css'] = mainCSS;
      
      exports.handle = handle;
  • 동작

  • To Do

    • hardcoding된 부분 개선
    • order 누르면 main.html에서 order 성공 여부를 결과로 받아 popup 띄우기
profile
이것저것 관심 많은 개발자👩‍💻

0개의 댓글