2023-09-06 10:31:39

WebSocket을 활용한 좌석예매 하기

영화관에서 표를 예매하거나 기차, 버스, 비행기등 좌석을 예매 할때 동시에 같은 자리를 예약하는 경우가 발생할 수 있기 때문에 socket의 장점인 실시간 접근을 이용하여 중복 예매를 방지 할 수 있습니다.

 

사용 모듈

npm init -y
npm install express socket.io ejs nodemon

 

page/main.ejs

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      /*  */
      .line {
        overflow: hidden;
      }
      .seat {
        margin: 5px;
        float: left;
        width: 30px;
        height: 30px;
        border-radius: 3px;
      }
      .enable {
        background-color: gray;
      }
      .disable {
        background-color: aqua;
      }
    </style>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  </head>
  <body>
    <div>airplane</div>
    <select name="" id="selectBtn">
      <option value="0">airplane 1</option>
      <option value="1">airplane 2</option>
      <option value="2">airplane 3</option>
    </select>
    <div id="content"></div>
  </body>
  <script>
    window.onload = () => {
      // connect 메소드를 사용하여 연결
      // io는 /socket.io/socket.io.js"에서 가져온 전역객체
      const socket = io.connect();
      // on 메소드 : 특정 이벤트가 발생했을때 실행할 콜백 함수를 등록
      socket.on("reserve", (data) => {
        if (data.selectCount == selectBtn.selectedIndex) {
          let target = document.querySelector(
            `div[data-x="${data.x}"][data-y="${data.y}"]`
          );
          target.classList.remove("enable");
          target.classList.add("disable");
        }
      });

      let selectCount = 0;
      selectBtn.onchange = function () {
        content.innerHTML = "";
        // selectedIndex : select tag의 옵션의 인덱스 번호 호출
        selectCount = this.selectedIndex;
        // 시트 생성 함수
        getseats(selectCount);
      };

      const onClickSeat = function () {
        // 예약이 된 좌석이면 리턴시킴
        if (this.classList.contains("disable")) {
          return;
        }
        // 어트리뷰트 데이터 속성을 호출 getAttribute 메소드로 매개변수로 가져올 속성이름
        let x = this.getAttribute("data-x");
        let y = this.getAttribute("data-y");
        if (confirm("좌석을 예약하시겠습니까?")) {
          // socket 이벤트를 푸쉬
          socket.emit("reserve", {
            x,
            y,
            selectCount,
          });
        } else {
          alert("노노요");
        }
      };

      function getseats(selectIndex) {
        // 요청 응답으로 시트를 가져올 예정
        // 변수로 담을 예정
        // CDN으로 axios 활용
        // 요청은 get방식 매개변수는 아이디 값으로 요청
        // /seats/0 으로 get 요청을 보냄
        axios.get("/seats/" + selectIndex).then((e) => {
          console.log(e);
          let { data } = e;
          // data의 길이는 4 닌까 4줄 출력
          data.forEach((line, indexY) => {
            let lineElem = document.createElement("div");
            lineElem.classList.add("line");

            line.forEach((seat, indexX) => {
              let seatElem = document.createElement("div");
              seatElem.classList.add("seat");
              // setAttribute : 어트리뷰트 속성 추가
              // 첫번째 매개변수 : 속성의 이름
              // 두번째 매개변수 : 속성의 값
              seatElem.setAttribute("data-x", indexX);
              seatElem.setAttribute("data-y", indexY);

              // 빈공간, 예약 가능한 시트, 이미 예약된 시트
              if (seat == 1) {
                seatElem.classList.add("enable");
                seatElem.addEventListener("click", onClickSeat);
              } else if (seat == 2) {
                seatElem.classList.add("disable");
              }
              lineElem.appendChild(seatElem);
            });
            content.appendChild(lineElem);
          });
        });
      }
      getseats(0);
    };
  </script>
</html>

app.js

// 비행기 좌석 만들기
// 1, 2, 3번 비행기 좌석 예약

// 사용할 모듈
// socket.io express ejs

const express = require("express");
const path = require("path");
const socketIo = require("socket.io");
const app = express();

// 선택된 좌석을 보여줄 배열
let seats = [];

let temp = [
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
];

let temp2 = [
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
];

let temp3 = [
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
];

let seatsArr = [temp, temp2, temp3];
// 선택한 비행기의 인덱스
let index = 0;

app.set("views", path.join(__dirname, "page"));
app.set("view engine", "ejs");

app.use(express.urlencoded({ extended: false }));

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

app.get("/seats/:id", (req, res) => {
  index = req.params.id;
  seats = seatsArr[index];
  res.send(seats);
});

const server = app.listen(8080, () => {
  console.log("Server On");
});

const io = socketIo(server);

io.sockets.on("connection", (socket) => {
  socket.on("reserve", (data) => {
    console.log("Reservation");
    let seatTemp = seatsArr[data.selectCount];
    seatTemp[data.y][data.x] = 2;
    io.sockets.emit("reserve", data);
  });
});

 

결과

왼쪽 브라우저에서 좌석을 눌러 예매를 하면
오른쪽 브라우저도 실시간으로 예매 되는것을 볼 수 있다

728x90