멋쟁이v의 개발일지

익스프레스 템플릿을 사용한 콘텐츠(EJS) 본문

0년차/Nodejs

익스프레스 템플릿을 사용한 콘텐츠(EJS)

멋쟁이v 2023. 9. 1. 15:46
728x90
320x100


📌
사용자가 웹 사이트를 사용함에 따라 변경되는 데이터가 있다.

제출된 데이터를 처리하고 저장하기 위해서

사용자 정의 백엔드인 서버 측 코드가 필요하고

미리 작성된 정적 HTML 파일을 반복해서 사용해서 동적 응답을 생성해 준다.

01. 익스프레스 기본 세팅

💡
➡️ npm install
  • 새 프로젝트를 생성했을 때 기존에 package.json 파일에 종속성으로 지정되어 있는 라이브러리들을 설치한다.

➡️ express 임포트 후 상수에 저장

  • const express = require(’express’);

➡️ app 객체 생성 후 상수에 저장

  • const app = express();

➡️ 서버 포트 설정

  • app.listen(3000);

➡️ 기본 라우트 설정

  • app.get(’/’, function(req, res) { … });

02. HTML 파일 제공

💡
➡️ 응답으로 파일 다시 보내기
  • res.sendFile();
  • 파일이 html 내용이 포함되어 있는지 확인한 다음 브라우저가 자동으로 수신 및 취급

➡️ 경로 패키지

  • const path = require(’path’);

➡️ 해당 파일 경로를 가져온 후 상수에 저장

  • const filePath = path.join(__dirname, ‘경로’, ‘파일명’);
    • __dirname : 절대경로
const path = require('path');

const express = require('express');
const app = express();

// 요청-응답 메서드
app.get('/', (req, res) => {
    const htmlFilePath = path.join(__dirname, 'views', 'index.html');
    res.sendFile(htmlFilePath);
});

app.get('/restaurants', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'restaurants.html');
    res.sendFile(htmlFilePath);
});

app.get('/recommend', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'recommend.html');
    res.sendFile(htmlFilePath);
});

app.get('/confirm', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'confirm.html');
    res.sendFile(htmlFilePath);
});

app.get('/about', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'about.html');
    res.sendFile(htmlFilePath);
});

// 포트설정
app.listen(3000);

03. 정적파일(static) 제공

💡
정적 파일이란, 직접 값에 변화를 주지 않는 이상 변하지 않는 파일을 의미

ex) image, css, js 등

➡️ express는 이러한 정적 파일들을 손쉽게 제공할 수 있는 기능을 가지고 있다.

  • app.use(express.static(’public’));
    • express 변수에는 stastic이라는 메서드가 포함되어있다.
    • 이 메서드를 use를 사용하여 미들웨어로서 로드해준다.
    • static의 인자로 전달되는 'public'은 디렉터리의 이름이다. 따라서 'public' 이라는 디렉터리 밑에 있는 데이터들은 웹브라우저의 요청에 따라 서비스를 제공해줄 수 있다.

      ex) 127.0.0.1:3000/images/cat.jpg → public/images/cat.jpg

04. form 전송 및 리다이렉트

💡
form이 제출됐을 때 → POST 요청 처리

➡️ app.post(’경로’, function(req, res) { });

  • app.use(express.urlencoded({extended: false}));
    • POST 방식으로 요청을 하게 되면, Header 필드에는 body안의 데이터가 어떤 형식의 인코딩 방법을 썼는지가 명시 되어있다.
    • 옵션이 false면 노드의 querystring 모듈을 사용하여 쿼리스트링을 해석하고, true면 qs 모듈을 사용하여 쿼리스트링을 해석한다.

📌 body-parser란 요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어이다.

📌 redirect를 해주는 이유?

post 요청이 전송되고 처리되면 브라우저가 다른 페이지로 전환해야 한다. 동일한 데이터를 다시 제출해서 같은 데이터가 저장되는 것을 방지할 수 있다.

➡️ form 데이터 추출

1) request.body → 전체적으로 데이터 추출

2) 파일시스템 패키지 설정

3) 데이터를 저장할 json파일 생성

4) json 경로 설정 후 json 파일 읽기

5) json파일을 javascript 텍스트 형태로 변환

6) 배열안에 데이터를 push

7) 다시 json 형태로 변환

8) 페이지 redirect

// 파일시스템 패키지
const fs = require('fs');
// 경로 패키지
const path = require('path');

const express = require('express');
const app = express();

// 미들웨어
app.use(express.urlencoded({extended:false}));
app.use(express.static('public'));

// 요청-응답 메서드
app.get('/', (req, res) => {
    const htmlFilePath = path.join(__dirname, 'views', 'index.html');
    res.sendFile(htmlFilePath);
});

app.get('/restaurants', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'restaurants.html');
    res.sendFile(htmlFilePath);
});

app.get('/recommend', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'recommend.html');
    res.sendFile(htmlFilePath);
});

app.post('/recommend', function(req, res){
    // body 전체를 저장
    const restaurant = req.body;

    // json 경로
    const filePath = path.join(__dirname, 'data', 'restaurants.json');

    // 파일 읽기
    const fileData = fs.readFileSync(filePath);

    // JSON 파일을 javascript 텍스트로 변환
    const storedRestaurants = JSON.parse(fileData);
    storedRestaurants.push(restaurant);
    console.log(storedRestaurants);

    // json 파일에 json 형태로 쓰기
    fs.writeFileSync(filePath, JSON.stringify(storedRestaurants));

    res.redirect('/confirm');
});

app.get('/confirm', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'confirm.html');
    res.sendFile(htmlFilePath);
});

app.get('/about', function(req, res) {
    const htmlFilePath = path.join(__dirname, 'views', 'about.html');
    res.sendFile(htmlFilePath);
});

// 포트설정
app.listen(3000);

05. EJS 템플릿 엔진

💡
템플릿이란?

➡️ 특정 모양을 만들기 위해 사전에 준비된 틀

Node.js 에서 템플릿이란 HTML 태그로 이루어진 기초 문서를 의미한다.

어느정도 완성된 HTML 문서의 형틀을 미리 만들어 놓고, 그 중 일부를 필요한 정보로 채워넣는 것이다.

➡️ 적용 방법

1) ejs 설치 - npm install ejs

2) app 객체에 set 메서드를 사용해서 세팅

  • app.set(’views’, ‘뷰경로’) - 템플릿 문서가 보관된 폴더는 views 폴더라는 세팅
  • app.set(’view engine’, ‘ejs’) - express 에게 템플릿 문서로 사용할 엔진이 ejs 라는 세

3) html 확장자를 ejs 로 변경

4) 모든 get 메서드에 res.render를 호출해서 ejs 파일을 다시 전달한다.

res.render(’파일명’);

const fs = require('fs');
const path = require('path');

const express = require('express');
const app = express();

// 미들웨어
app.use(express.urlencoded({extended:false}));
app.use(express.static('public'));

// 세팅
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// 요청-응답 메서드
app.get('/', (req, res) => {
    res.render('index');
});

app.get('/restaurants', function(req, res) {
    res.render('restaurants');
});

app.get('/recommend', function(req, res) {
    res.render('recommend');
});

app.post('/recommend', function(req, res){
    // body 전체를 저장
    const restaurant = req.body;

    // json 경로
    const filePath = path.join(__dirname, 'data', 'restaurants.json');

    // 파일 읽기
    const fileData = fs.readFileSync(filePath);

    // JSON 파일을 javascript 텍스트로 변환
    const storedRestaurants = JSON.parse(fileData);
    storedRestaurants.push(restaurant);
    console.log(storedRestaurants);

    // json 파일에 json 형태로 쓰기
    fs.writeFileSync(filePath, JSON.stringify(storedRestaurants));

    res.redirect('/confirm');
});

app.get('/confirm', function(req, res) {
    res.render('confirm');
});

app.get('/about', function(req, res) {
    res.render('about');
});

// 포트설정
app.listen(3000);

06. 템플릿으로 동적 콘텐츠 렌더링

💡
<%= 변수 %>

➡️ res.render(’ejs파일’, { 변수 : 값 });

  • 렌더링 메서드에 두번째 매개변수 값에 자바스크립트 객체를 전달할 수 있다.

➡️ restaurants.ejs 파일에 <%= restaurantOfNumber %> 구문 삽입

const fs = require('fs');
const path = require('path');

const express = require('express');
const app = express();

// 미들웨어
app.use(express.urlencoded({extended:false}));
app.use(express.static('public'));

// 세팅
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// 요청-응답 메서드
app.get('/restaurants', function(req, res) {

    // json 파일 읽은 후 자바스크립트 형태로 변환
    const filePath = path.join(__dirname, 'data', 'restaurants.json');
    const fileData = fs.readFileSync(filePath);
    const storedRestaurants = JSON.parse(fileData);

    // 렌더링 메서드 두번째 인자에 자바스크립트 객체를 전달 가능
    res.render('restaurants', { restaurantOfNumber : storedRestaurants.length });
});

07. ejs 반복문 사용

💡
데이터가 포함된 목록 항목을 반복해서 보여주고 싶을 때

ejs에서 지원이 내장되어 있어서 작업이 간편하다.

➡️ ejs 파일 내부에 고유한 자바스크립트 논리를 작성할 수 있다.

  • <% for(const restaurant of restaurants) { %>

    — html —

    <%= restaurant.name %> → ejs 구문인 등호를 다시 사용, 단일 값 출력

    ….

    — html —

    <% } %>

➡️ 반복문에 던져진 객체 restaurants를 app.js에서 렌더링 메서드를 통해 전달한다.

const fs = require("fs");
const path = require("path");

const express = require("express");
const app = express();

// 미들웨어
app.use(express.urlencoded({ extended: false }));
app.use(express.static("public"));

// 세팅
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");

// 요청-응답 메서드
app.get("/restaurants", function (req, res) {
  // json 파일 읽은 후 자바스크립트 형태로 변환
  const filePath = path.join(__dirname, "data", "restaurants.json");
  const fileData = fs.readFileSync(filePath);
  const storedRestaurants = JSON.parse(fileData);

  // 렌더링 메서드 두번째 인자에 자바스크립트 객체를 전달 가능
	// 쉼표를 사용해서 여러개 전달 가능
  res.render("restaurants", {
    restaurantOfNumber: storedRestaurants.length,
    restaurants: storedRestaurants,
  });
});

08. 조건부 콘텐츠 렌더링

💡
조건문 사용

➡️ <% if ( 조건 ) { %>

…html

<% } else { %>

…html

<% } %>

<!-- 생략 -->
<main>
  <h1>Recommended restaurants</h1>
  <% if(restaurantOfNumber === 0) { %>
    <p>검색된 레스토랑이 없습니다. 추가해주세요.</p>
  <% } else { %>
    <p>Find your next favorite restaurants with help of our other users!</p>
    <p>We found <%= restaurantOfNumber %> restaurants.</p>
    <ul id="restaurants-list">
      <% for(const restaurant of restaurants) { %>
      <li class="restaurant-item">
        <article>
          <h2><%= restaurant.name %></h2>
          <div class="restaurant-meta">
            <p><%= restaurant.cuisine %></p>
            <p><%= restaurant.address %></p>
          </div>
          <p>
            <%= restaurant.description %>
          </p>
          <div class="restaurant-actions">
            <a href="<%= restaurant.website %>">View Website</a>
          </div>
        </article>
      </li>
      <% } %>
    </ul>
    <% } %>
</main>
<!-- 생략 -->

09. 콘텐츠 include

💡
파일에서 동일한 부분(header, aside 등)을 복제할 때마다

코드를 변경하려면 여러 곳에서 수정이 필요하다.

이러한 문제를 includes라는 기능을 사용해서 해결할 수 있다.

➡️ includes

  • 여러 페이지에서 잠재적으로 사용할 수 있는(페이지의 일부를 포함하는) ejs 파일
  • 큰 html 파일을 더 작고 관리하기 쉬운 조각으로 나눌 수 있다.
  • includes(’경로’, { 객체 });
    • 두번째 인수로 자바스크립트 객체를 전달해 줄 수 있다.

📌 <%= %> : 원시 텍스트로 변환

<%- %> : html 코드로 변환

<!DOCTYPE html>
<html lang="en">
  <head>
    <%- include('includes/head') %>
    <link rel="stylesheet" href="styles/restaurants.css" />
  </head>
  <body>
    <%- include('includes/header') %>
    <%- include('includes/aside') %>
    <main>
      <h1>Recommended restaurants</h1>
      <% if(restaurantOfNumber === 0) { %>
        <p>검색된 레스토랑이 없습니다. 추가해주세요.</p>
      <% } else { %>
        <p>Find your next favorite restaurants with help of our other users!</p>
        <p>We found <%= restaurantOfNumber %> restaurants.</p>
        <ul id="restaurants-list">
          <% for(const restaurant of restaurants) { %>
            <%- include('includes/restaurants/restaurant-item', { restaurant : restaurant }) %>
          <% } %>
        </ul>
        <% } %>
    </main>
  </body>
</html>



Uploaded by N2T

728x90
320x100

'0년차 > Nodejs' 카테고리의 다른 글

익스프레스JS로 노드JS 향상  (0) 2023.09.01
노드JS소개 - 백엔드 개발 시작하기  (0) 2023.09.01