SeSAC x CodingOn 웹 취업 부트캠프

[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 5주차 (2): Multer, Database

haeriyouu 2025. 1. 2. 18:13

Multer: 파일 업로드

💻 multer

  • 파일 업로드를 위해 사용되는 Node.js의 미들웨어

💡 미들웨어란?  

  • 양 쪽을 연결하여 데이터를 주고 받을 수 있도록 중간에서 매개 역할을 하는 소프트웨어.
    1. 양쪽을 연결
    2. 중간에서의 매개 역할
// app.js

// multer 불러오기
const multer = require("multer");

// multer 설정
const upload = multer({
  dest: "uploads/", // 어디에 저장 될지
});

const uploadDetail = multer({
  storage: multer.diskStorage({
    destination: function (req, file, done) {
      done(null, "uploads/"); // 어디에 저장될지 경로 설정!
      // uploads 라는 폴더가 미리 만들어져 있어야 함
    },
    filename: function (req, file, done) {
      // done(null, 우리가 설정 할 파일 이름)
      // const extension = path.extname(파일이름.확장자) -> 확장자만 return을 해주는 함수
      const extension = path.extname(file.originalname);

      //   path.basename(파일이름.확장자, 확장자) -> 파일 이름만 리턴
      done(
        null,
        path.basename(file.originalname, extension) + Date.now() + extension
      );
      console.log(path.basename(file.originalname, extension));
      console.log(path.extname(file.originalname));
    },
  }),

  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
});

💡 dest와 storage의 차이

  1. dest: 간단한 파일 저장이 필요하며 기본 설정이 충분 할 경우.
    • 파일 이름이나 저장 경로를 설정 할 필요가 없을 때.
      • 파일이름: 랜덤으로 자동 생성
    • 고정된 디렉토리 (dest: ‘path/’)
  2. storage: 파일 이름 또는 저장 경로를 동적으로 변경해야 할 때.
    • 동적으로 설정 가능 (diskStorage.destination) & (diskStorage.filename)
    • 파일을 메모리나 다른 방식으로(세부적으로) 저장하려 할 때.
// index.ejs

<form action="/upload" method="post" enctype="multipart/form-data"> </form>
// form 태그의 enctype 속성으로 "multipart/form-data" 반드시 설정 해야 한다!

💡 세부 설정

  • storage: 저장할 공간에 대한 정보
  • diskStorage: 파일을 저장하기 위한 모든 제어기능 제공 (파일 저장관련 설정)
  • destination: 업로드 할 파일을 저장할 폴더를 지정
  • filename: 파일이름 (요청객체, 업로드된 파일 객체, 콜백함수 순서)
  • extname(): 확장자를 추출
  • basename(): 파일이름을 추출 (파일의 원래 이름, 확장자) -> 확장자를 제외해서 파일이름만 추출

💻 multer: 하나의 input에 파일 여러개 업로드

// index.ejs

<h2>하나의 input에 파일 여러개 업로드</h2>
    <form action="/uploads/array" method="post" enctype="multipart/form-data">
      <input type="file" name="multifiles" multiple />
      <br />
      <input type="text" name="title" placeholder="사진 제목" />
      <br />
      <button>업로드</button>
    </form>
    
    // app.js
    
    // 하나의 input에 여러개 파일
app.post("/uploads/array", uploadDetail.array("multifiles"), (req, res) => {
  //   console.log(req.file); // undefined
  console.log(req.files); // 파일 여러개 일때
  /** 배열 안에 객체 형태로 들어온다.
   * [ << 배열
  {
    fieldname: 'multifiles',
    originalname: 'hachi.jpg',
    encoding: '7bit',
    mimetype: 'image/jpeg',
    destination: 'uploads/',
    filename: 'hachi1732518372784.jpg',
    path: 'uploads\\hachi1732518372784.jpg',
    size: 27487
  },
  {
    fieldname: 'multifiles',
    originalname: 'hachiwarae.png',
    encoding: '7bit',
    mimetype: 'image/png',
    destination: 'uploads/',
    filename: 'hachiwarae1732518372788.png',
    path: 'uploads\\hachiwarae1732518372788.png',
    size: 199533
  }
]
   */
  console.log(req.body);
  res.send("업로드 완료");
});
  • array(): 동일한 필드 이름으로 여러 파일을 업로드할 때 사용
    • req.files에 배열로 저장

💻 multer: 여러개의 input에 파일 업로드

// index.ejs

 <h2>여러 개 input에 파일 업로드</h2>
    <form action="/uploads/fields" method="post" enctype="multipart/form-data">
      <input type="file" name="file1" /> <br />
      <input type="text" name="title1" placeholder="사진 제목1" />

      <br /><br />

      <input type="file" name="file2" /> <br />
      <input type="text" name="title2" placeholder="사진 제목2" />

      <br /><br />

      <input type="file" name="file3" /> <br />
      <input type="text" name="title3" placeholder="사진 제목3" />

      <br /><br />
      <button>업로드</button>
    </form>
    
    // app.js
    // 여러개의 input에 파일 업로드
// .fields() 사용
// fields의 매개 변수는 배열[{name:'name값1'},...]
app.post(
  "/uploads/fields",
  uploadDetail.fields([
    { name: "file1" },
    { name: "file2" },
    { name: "file3" },
  ]),
  (req, res) => {
    // upload.fields() 로 받아주는 req.files 객체 형태로 들어옴
    console.log(req.files);
    /**
     * {filename1: [{업로드 파일 정보}], filename2:[{업로드 파일 정보}], filename3:[{업로드 파일 정보}]} // 객체 형태로 들어온다.
     */
    console.log(req.body);
    res.send("업로드 완료");
  }
);
  • fields(): 여러 다른 필드 이름으로 여러 파일들을 업로드할 때 사용
    • req.files에 객체로 저장 (필드별로 구분)

💻 axios 동적 폼 파일 업로드

// index.ejs script

  function fileOnlyUpload() {
        const file = document.getElementById("dynamicFile");
        console.log(file.files);
        console.dir(file.files[0]);

        const formData = new FormData();
        // 자바 스크립트에서 기본적을 제공하는 클래스
        // 파일을 페이지 전환없이 비동기로 제출하고 싶을 때 사용
        formData.append("dynamicFile", file.files[0]);

        axios({
          method: "post",
          url: "dynamicUpload",
          data: formData,
          headers: {
            "Content-Type": "multipart/form-data",
          },
        }).then((res) => {
          console.log(res.data.path);
          const img = document.querySelector("img");
          img.src = `/${res.data.path}`;
        });
      }

      // 2. 글과 파일을 함께 업로드
      function fileAndTextUpload() {
        const formData = new FormData();
        // input[type='file'], 파일 정보를 서버로 보내기 위해 선택
        const file = document.getElementById("dynamicFile");

        // input[type='text'], 이미지에 대한 제목, 즉, 글자 정보를 서버로 보내기 위해 선택
        const title = document.getElementById("dynamicText");

        // img태그, 사진의 src, alt 속성을 바꾸기 위해 선택
        const img = document.querySelector("img");

        console.log(file.files);
        formData.append("dynamicFile", file.files[0]);
        formData.append("dynamicFile", title.value);

        /*
        formData = {
          dynamicFile: 파일정보(fileList[0])
          dynamicTitle: "사진 제목 string"
        }
        */

        axios({
          method: "post",
          url: "/dynamicUpload",
          data: formData,
          headers: {
            "Content-Type": "multipart/form-data",
          },
        })
          .then((res) => {
            console.log(res.data);
            console.log(res.data.fileInfo.dynamicTitle);

            img.src = "/" + res.data.file.path;
            img.alt = res.data.fileInfo.dynamicTitle + "사진";
            img.classList.add("profile");
            document.querySelector(".tit").innerText =
              res.data.fileInfo.dynamicTitle;
          })
          .catch((err) => console.log("EROOR", err));
      }
      
      // app.js
      
// 동적 폼 파일 업로드
app.post("/dynamicUpload", uploadDetail.single("dynamicFile"), (req, res) => {
  // 하나의 객체에 합쳐서 보내는 방법
  // res.send(...req.file, ...req.body);

  res.send({ file: req.file, fileInfo: req.body });
});

app.listen(PORT, () => {
  console.log(`http://localhost:${PORT}`);
});

Database

  • 데이터를 저장하는 구조/자료의 모음

💻 DBMS (DataBase Management System)

  • 데이터베이스에 접근하고 이를 관리하기 위해 존재한다.
  • 관계형 데이터베이스(Relational DBMS)도 있다.

💻 DB구조

  • 열 (Column, Attribute, 속성)
  • 행 (Record, Tuple, 튜플)
  • 테이블 (Table, Relation)

💡키 (Key)

  • DB에서 튜플을 찾거나 순서대로 정렬할 때 구분하고, 정렬의 기준이 되는 속성
  • 기본키 (Primary Key) ⭐
    • 테이블을 대표하는 속성
    • 메인 키로 한 테이블에서 특정 튜플(행)을 유일하게 구별할 수 있는 속성
    • Null 값 불가
    • 중복 값 불가
  • 외래키 (Foreign Key) ⭐
    • 어떤 테이블의 기본키를 참조하는 속성
    • 참조되는 기본키 값이 변경되면 참조하는 외래키 값도 변경된다.
    • Null 값과 중복 값 등 허용
  • 관계 데이터베이스에서 키는 특정 튜플을 식별할 때 사용하는 속성이거나 혹은 속성의 집합이다.
  • 테이블간 관계를 맺는데도 사용된다.

💻 SQL (Structured Query Language)

  • 관계형 데이터베이스에 정보를 저장하고 처리하기 위한 프로그래밍 언어
  • 실행 순서가 없는 비절차적언어이다!
  • 크게 세개로 나눌 수 있다: DDL, DML, DCL

💡 DDL 데이터 정의어 (Data Definition Language)

  • 데이터베이스의 구조를 정의하는 언어
  • 주요 명령어:
    • CREATE: 새로운 테이블 생성
    • ALTER: 기존 테이블 구조 변경
    • DROP: 기존 테이블 삭제
    • TRUNCATE: 테이블 초기화
    • RENAME: 테이블 이름 변경

⭐ DROP 과 TRUNCATE의 차이

  • DROP은 테이블 삭제하기
  • TRUNCATE는 테이블 초기화 하기. 테이블의 모든 행(row) 일괄 삭제!

💡 DML 데이터 조작어 (Data Manipulation Language)

  • 데이터베이스 내의 데이터를 조작하는 언어
  • 주요 명령어:
    • SELECT: 데이터 조회
    • INSERT: 새로운 데이터 삽입
    • UPDATE: 기존 데이터 수정
    • DELETE: 데이터 삭제
    • DISTINCT: 중복된 행 제거
    • LIMIT: 결과로 반환되는 행 수를 제한하는데 사용, OFFSET과 함께 사용해 시작 지점을 지정 할 수 있다.
    • GROUP BY: 데이터를 그룹화 하는 역할
    • JOIN: 두 개 이상의 테이블을 연결하여 데이터를 검색

⭐ SELECT문은 데이터를 검색하는 기본 문장이다!

SELECT문의 순서: SELECT 속성이름, FROM 테이블이름 WHERE 검색조건 ORDER BY 속성이름

⭐ ORDER BY

  • SELECT문의 마지막에 위치한다.
  • 오름차순(ASC), 내림차순(DESC)으로 정렬할 수 있다. (ASC가 기본 값!)

💡 DCL 데이터 제어어 (Data Control Language)

  • 데이터베이스에 대한 접근 권한을 제어하는 언어
  • 주요 명령어:
    • GRANT: 사용자에게 권한 부여
    • REVOKE: 사용자로부터 권한 회수
더보기
SQL이 비절차적 언어라 순서 상관 없이 내가 실행시키고 싶은 줄에 가서 ctrl+enter 만 누르면 되는게 굉장히 흥미로웠다😮그나마 학부생때 기억이 나서 할만했던 SQL..!