본문 바로가기
내일배움캠프(Sparta)/웹개발 A to Z

[웹개발 A to Z] 4주차 (Firebase, Firestore)

by mmm- 2023. 9. 8.

Frontend

: 눈에 보이는 부분 (HTML, CSS, JAVASCRIPT)

 

Backend

: 눈에 보이지 않는 부분 (SERVER, DB, API)


1. Firebase

firebase

: 구글이 개발한 모바일 및 웹 애플리케이션 개발 플랫폼

 

개발자들이 백엔드 인프라를 구축하거나 관리하는 복잡한 작업없이 핵심 기능에 집중할 수 있도록 도와준다.

사용량만 넘어가지 않으면 무료로 사용할 수 있다는 장점이 있다.

 

타입을 모듈로 바꾸면 script가 맨 마지막에 불리고 onclick 과 같은 것이 안되기 때문에 클릭을 동적으로(코드로) 만들어줘야 한다.

 


2. DB

DB(데이터베이스)

: 데이터를 저장하는 곳

 

데이터베이스가 있으면 데이터를 저장하고 다시 가져다 쓸 수 있다.

 

DB가 필요한 이유는?

>> 책꽂이에 책을 꽂는 이유와 비슷하다. 잘 찾기 위해 잘 적재해 놓는 것이다.

 

관계형 데이터베이스 (SQL) 비관계형 데이터베이스 (NoSQL)
  • 정리된 정보를 다룰 때 사용.
  • 틀이 이미 짜여져 있고 사람의 실수가 나면 안되는 곳에서 주로 사용 (은행, 대기업)
  • 복잡하거나 유연한 정보를 다룰 때 사용.
  • 앞으로 바뀔 여지가 많은 곳에서 주로 사용 (스타트업)

 


3. Firestore

firestore

: 구글의 클라우드 기반 NoSQL 데이터베이스

 

  • 데이터 베이스 서비스로 데이터를 저장하고 관리하는 기능을 제공
 <script type="module">
    // Firebase SDK 라이브러리 가져오기
    import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
    import { getFirestore } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
    import { collection, addDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
    import { getDocs } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";

    // For Firebase JS SDK v7.20.0 and later, measurementId is optional
    const firebaseConfig = {
      // 본인 설정 내용
    };

    // Firebase 인스턴스 초기화
    const app = initializeApp(firebaseConfig);
    const db = getFirestore(app);
<script>

→ 파이어스토어 setting 코드.

 


4. [추억앨범] Firestore Database에 데이터 넣기 & 가져오기

위와 같이 코드 입력시, 이렇게 데이터가 들어와 있는 것을 볼 수 있다.

 

DB에 저장된 데이터를 가져와 나타내기 때문에 새로고침을 해도 사라지지 않고 유지된다.

 

<!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>나만의 추억앨범</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

  <style>
    @import url('https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap');

    * {
      font-family: 'Gowun Dodum', sans-serif;
    }

    .mytitle {
      height: 250px;
      background: green;
      color: white;

      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;

      background-image: url('https://images.unsplash.com/photo-1511992243105-2992b3fd0410?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1470&q=80');
      background-position: center;
      background-size: cover;
    }

    .mytitle>button {
      width: 150px;
      height: 50px;
      background-color: transparent;
      color: white;
      border: 1px solid white;
      border-radius: 5px;

      margin-top: 20px;
    }

    .mycards {
      width: 1200px;

      margin: 30px auto 0px auto;
    }

    .mypostingbox {
      width: 500px;

      margin: 30px auto 0px auto;
      padding: 20px;
      box-shadow: 0px 0px 3px 0px blue;
      border-radius: 5px;
    }

    .mybtn {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
    }

    .mybtn>button {
      margin-right: 5px;
    }
  </style>
  <script type="module">
    // Firebase SDK 라이브러리 가져오기
    import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
    import { getFirestore } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
    import { collection, addDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
    import { getDocs } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";


    // For Firebase JS SDK v7.20.0 and later, measurementId is optional
    const firebaseConfig = {
      // 본인 설정 내용
    };

    // Firebase 인스턴스 초기화
    const app = initializeApp(firebaseConfig);
    const db = getFirestore(app);

    $("#postingbtn").click(async function () {
      let image = $('#image').val();
      let title = $('#title').val();
      let content = $('#content').val();
      let date = $('#date').val();

      let doc = {
        'image': image,
        'title': title,
        'content': content,
        'date': date
      };
      await addDoc(collection(db, "albums"), doc); // 추가

      alert('저장 완료!');
      window.location.reload();
    })

    $("#savebtn").click(async function () {
      $('#postingbox').toggle();
    })



    let url = "http://spartacodingclub.shop/sparta_api/seoulair";
    fetch(url).then(res => res.json()).then(data => {
      let mise = data['RealtimeCityAir']['row'][0]['IDEX_NM']
      $('#msg').text(mise);
    })

    let docs = await getDocs(collection(db, "albums")); // 가져오기
    docs.forEach((doc) => {
      let row = doc.data();
      console.log(row);

      let image = row['image'];
      let title = row['title'];
      let content = row['content'];
      let date = row['date'];

      let temp_html = `
        <div class="col">
              <div class="card h-100">
                <img src="${image}" 
                  class="card-img-top" alt="...">
                <div class="card-body">
                  <h5 class="card-title">${title}</h5>
                  <p class="card-text">${content}</p>
                </div>
                <div class="card-footer">
                  <small class="text-body-secondary">${date}</small>
                </div>
              </div>
            </div>`;
      $('#card').append(temp_html);
    });
  </script>
</head>

<body>
  <div class="mytitle">
    <h1>나만의 추억앨범</h1>
    <p>현재 서울의 미세먼지 : <span id="msg">나쁨</span></p>
    <button id="savebtn">추억 저장하기</button>
  </div>
  <div class="mypostingbox" id="postingbox">
    <div class="form-floating mb-3">
      <input type="email" class="form-control" id="image" placeholder="앨범 이미지">
      <label for="floatingInput">앨범 이미지</label>
    </div>
    <div class="form-floating mb-3">
      <input type="email" class="form-control" id="title" placeholder="앨범 제목">
      <label for="floatingInput">앨범 제목</label>
    </div>
    <div class="form-floating mb-3">
      <input type="email" class="form-control" id="content" placeholder="앨범 내용">
      <label for="floatingInput">앨범 내용</label>
    </div>
    <div class="form-floating mb-3">
      <input type="email" class="form-control" id="date" placeholder="앨범 날짜">
      <label for="floatingInput">앨범 날짜</label>
    </div>
    <div class="mybtn">
      <button id="postingbtn" type="button" class="btn btn-primary">기록하기</button>
      <button type="button" class="btn btn-outline-primary">닫기</button>
    </div>
  </div>
  <div class="mycards">
    <div id="card" class="row row-cols-1 row-cols-md-4 g-4">
    </div>
  </div>
</body>

</html>

 

  • window.location.reload() => 새로고침하는 코드

JS는 싱글스레드 기반 언어이기 때문에 비동기 처리가 필수적이지만, 비동기 처리는 결과를 예측할 수 없기 때문에 동기식의 처리가 필요함. 대표적으로 promise, callback이 있는데 이 둘의 일부 단점을 보완하고 가독성 좋은 코드를 작성할 수 있게 도와주는 것이 바로 async, await

 

async await: JS의 비동기 처리 패턴.

 

promise

: JS에서 비동기 작업을 처리하는 객체

  • 3가지 상태
    • 대기(Pending): 처음 생성된 promise는 대기 상태. 대기상태에서는 작업이 아직 완료 X
    • 이행(Fulfilled): 작업이 성공적으로 완료되면 이행 상태로 전환. 해당 상태에서 작업의 결과가 반환됨
    • 거부(Rejected): 작업이 실패하면 거부 상태로 전환됨. 해당 상태에서 오류 정보가 반환됨
  • 후속처리 메서드
    • then
      • 두 개의 콜백 함수를 인자로 전달 받음 (첫 번째 콜백함수 => 성공시 실행 / 두 번째 콜백함수 => 실패시 실행)
      • then 메서드는 기본적으로 promise 반환
    • catch
      • 비동기 처리 혹은 then 메서드 실행 중 예외가 발생하면 호출
      • promise 반환

 

async

  • function앞에 사용되고, function 앞에 async를 붙이면 해당 함수는 항상 promise를 반환
    (promise가 아닌 것은 promise로 감싸 반환)

 

await

  • async 함수 안에서만 동작
  • promise가 처리될 때까지 기다리는 역할을