μ€λμ BoB 10κΈ° 보μμ νκ°λ° νΈλμ 보μ μ루μ μ μ μμ μμ νλ¬λμ μ§νν 1μ°¨ ν νλ‘μ νΈμ λν΄μ μ΄μΌκΈ°ν΄λ³΄λ € νλ€.
ν΄λΉ κΈμ μ΄ 5λΆμμΌλ‘ ν λΉλ©κ³Ό νμ κ³Όμ κ·Έλ¦¬κ³ μλΉμ€ μ€λͺ λ° κ°λ° κ³Όμ μΌλ‘ λλμ΄μ Έ μμ΅λλ€.
- 1μ°¨ ν νλ‘μ νΈ ν λΉλ© λ° νμ μ κ³ λ―Όλ€
- 1μ°¨ ν νλ‘μ νΈ νλ‘ νΈμλλ₯Ό κ°λ°νλ©° νλ κ³ λ―Όλ€
- 1μ°¨ ν νλ‘μ νΈ λ°±μλλ₯Ό κ°λ°νλ©° νλ κ³ λ―Όλ€
- 1μ°¨ ν νλ‘μ νΈ μΈνλΌλ₯Ό κ°λ°νλ©° νλ κ³ λ―Όλ€
νλ‘μ νΈ github λ°λ‘κ°κΈ° -> 보μ μν νΈλν½ λΆμ μ루μ github
μ§λ μκ° μ°λ¦¬κ° νλ κ³ λ―Όλ€κ³Ό λ¬Έμ λ€, κ·Έλ¦¬κ³ νμ μ λν λ΄μ©μ μ 리ν΄λ³΄μλ€.
μ€λμ μ°λ¦¬κ° κ°λ°ν μλΉμ€λ₯Ό μ’ λ κΈ°μ μ μΈ κ΄μ μμ μμλ³΄λ € νλ€.
κ°λ°νλ κ³Όμ μ΄ μ΄λ»κ² μ§νλκ³ μ΄λ€ λ¬Έμ λ€μ λ§λ¬μΌλ©° μ΄λ€ λ°©λ²μ μ·¨νλμ§!
λλ Web ννΈλ₯Ό 맑μκΈ° λλ¬Έμ λ΄κ° κ°λ°ν κΈ°λ₯κ³Ό APIμ λν΄μλ§ μ€λͺ μ ν μλ μλ€ γ γ ..
μλΉμ€ ꡬ쑰
μ°μ μλΉμ€μ λͺ©μ μ μ§λ μκ°μ μ΄μΌκΈ°νλ κ² μ²λΌ Access Log κΈ°λ° νΈλν½ λΆμ λ° λ³΄μ μν λΆμ μ΄λ€.
μ¬λ΄μ Web Application μ΄ κΈ°μ‘΄μ μμλλ Access Log λ₯Ό κΈ°λ°μΌλ‘ νμ¬ λΆμνκ³ λ³΄μ μνμ μκ°ν ν΄μ€λ€.
μλΉμ€μ ν° νλ‘μ°λ λ€μκ³Ό κ°λ€.
μλΉμ€ νλ‘μ°
- κ³ κ°μ¬λ κΈ°μ‘΄μ μ΄μμ€μ΄λ μλ²μ ν΄λΉ μλ²κ° μ μ₯νλ access.log κ° μ‘΄μ¬νλ€.
- μ°λ¦¬κ° κ°λ°ν Agent ν¨ν€μ§λ₯Ό μ€μΉνλ€.
- ν΄λΉ Agentμμ access log μ μμΉλ₯Ό μ§μ νκ³ λΆμ μλ²λ‘ access log λ₯Ό μ λ¬νλ€.
- μ΄μ μλ²μ μ±λ₯μ μν΄μ λΆμμ λ€λ₯Έ μλ²μμ μ§ννλ€.
- λΆμ μλ²λ‘ λ€μ΄μ¨ access log λ λΆμμ μ§ννμ¬ κ³΅κ²© μ νμ λ°λΌμ DBμ μ μ₯νλ€.
- ν΄λΉ DB μ κ°λ€μ ν λλ‘ λ³΄μ λ 벨μ μ°μΆνκ³ κ°μ’ μκ°νμ νμν λ°μ΄ν°λ₯Ό μ μ νμ¬ Frontλ‘ λ°ννλ€.
- Front Serverλ Backend μκ² λ°μμ¨ λ°μ΄ν°λ₯Ό κ°μ§κ³ λμ보λμμ μκ°νλ₯Ό μννλ€.
μλ μ²μ κΈ°νμ SaaS ννμκΈ° λλ¬Έμ λΆμ μλ²λ μ°λ¦¬κ° μ΄μνλ μλ²μ¬μΌ νμ§λ§ μκ°μ λ¬Έμ λ‘ μΈν΄ On-Premise ννλ‘ κ΅¬μ±νλ λ°©ν₯μΌλ‘ μ§ννλ€.
μ¦, Clientλ κΈ°μ‘΄μ μ΄μμ€μ΄λ μλ² + λΆμ μλ²λ₯Ό μ΄μνλ λ°©ν₯μΈλ°, μ΄κ² μ‘°κΈ μλΉμ€ κ΄μ μμ λ§μ μλ¬Έκ³Ό λΉν¨μ¨μ΄ μ‘΄μ¬νλ€.
μ΄μ© μ μλ€κ³ νννμ§λ§ μμ§ λ§μ΄ μμ½λ€..
νλ‘ νΈμλμ κΈ°μ μ κ³ λ―Ό
μμ μ΄μΌκΈ°νλ―, μ°λ¦¬λ Front Endλ₯Ό Reactλ‘ κ°λ°νμλ€.
μ΄ κ³Όμ μμ νλ κ³ λ―Όλ€μ ν¬κ² 3κ°μ§ μ΄λ€.
- HTML Rendering Server μ κ²°μ
- 리μ‘νΈμ state κ΄λ¦¬ λꡬ
- ν΅μ λͺ¨λμ μ ν
- λμμΈ ν¨ν΄μ λμ
νλμ© μμ보μ!
HTML Rendering Server μ κ²°μ
Front Endλ₯Ό μ²μλΆν° Reactλ‘ νλ €λ μκ°μ μμλ€.
μ²μμλ μμ HTMLκ³Ό Vanila Javascript λ₯Ό μ΄μ©ν μκ°μ΄μλ€.
κ·Έλ¦¬κ³ μ¬λ¬ κΈ°μ μ‘°μ¬λ₯Ό νμ λ, κ°λ¨ν λ€μλ μκ°μ λ°λ‘ Express.jsλ₯Ό μ΄μ©ν΄ static file render μλ²λ₯Ό ꡬμΆνλ κ²μ΄μλ€.
Expressjs λ Template Engine νλ μμν¬μ΄κΈ° λλ¬Έμ html render server λ‘μ¬μ©νκΈ° μν΄μ λͺ κ°μ§ μμ μ ν΄μ€μΌ νλ€.
μ°μ app.js μμ express.static()
μ μ΄μ©ν΄μ static νμΌμ λ λνλλ‘ κ΅¬μ±νλ€.
import express from "express";
import path from "path";
const __dirname = path.resolve();
const app = express();
const port = 3000;
const setRenderPage = (filename) => __dirname + "/views/" + filename;
app.use("/script", express.static("script"));
app.use("/static", express.static("static"));
app.get("/", (req, res) => {
res.sendFile(setRenderPage("index.html"));
});
app.listen(port, () => {
console.log("server started on " + port);
});
μ΄ λ°©λ²μλ ν κ°μ§ λ¬Έμ κ° μκ²Όλλ°, λ°λ‘ css, images, js νμΌμ κ°κ° render ν url μ μ΄μ΄μ€μΌ νμλ€.
κ·Έλμ <head>
νκ·Έ λ΄λΆμ url routing path λ₯Ό μκ°νλ©΄μ static file μ λ°ννμ§λ§, μ΄λ μμ°μ±μ μ ν΄μν€λ κ²μΌλ‘ 보μλ€.
μ΄κ±΄ κ·Έλ ν΄κ²° κ°λ₯νλ°, λ¬Έμ λ λ°λ‘ es6 μμ Moduleμ Bundling νλλ° μ λ§ νλ€μλ€.
μλ₯Ό λ€λ©΄ es6 μ΄μ μλ λͺ¨λμ κ°μ Έμ¬ λ, const express = require('express')
μ κ°μ λ°©μμ μ΄μ©νμ§λ§ es6 μ΄μμ import express from 'express'
ννλ‘ μ¬μ©νκΈ° λλ¬Έμ μ΄λ€ μ¬μ΄μ ν¨λ¬λ€μ λΆμΌμΉ?λ₯Ό ν΄κ²°νμ΄μΌ νκ³ , κ°κ° λ°λ‘ λ²λ€λ§μ νλ λ°©λ²μ΄ νμνλ€.
μ λ¬Έ Front κ°λ°μκ° μλ λμκ²λ μ‘°κΈ μ΄λ €μ λ€..
κ·Έλμ μκ°ν΄λΈ λ°©λ²μ΄ λ°λ‘ Webpack μ΄μλ€.
μΉν©μ λͺ¨λ jsλ₯Ό μν static λͺ¨λ bundler λΌκ³ νλ€.
κ°λ¨νκ² μΉν©μ λν΄μ μ΄μΌκΈ°νμλ©΄, main.js νμΌμ λ§λ€μ΄μ νλμ main.js μ μ°λ¦¬κ° λ§λ λ€μν λͺ¨λλ€μ λ£κ³ main.js νλλ§ url λ‘ κ°λ°©ν΄μ£Όλ λ°©λ²κ³Ό λΉμ·νκ² κ°μλ€.
κ·Έλμ μμ λ°μνλ λ¬Έμ λ€μ λ κΉλνκ³ νλμ μΈ λ°©λ²μΌλ‘ ν΄κ²°ν μ μμλ€.
μ¬μ€ 리μ‘νΈλ μΉν©μ μ΄μ©νκ³ μκ³ λλ μΉν©μ λν μΈκΈμ λ€μ΄λ΄€μ§λ§ κΉκ² 곡λΆν΄λ³Έ μ μ΄ μμλλ°, μ΄μ μΉν©μ΄ 무μμ νλ κΈ°μ μΈκ°? μ λν λ΅μ μ΄λμ λ ν μ μκ² λμ΄μ λ§€μ° μ λ¬μλ€ γ γ ..
μμΈν μ¬νμ κΈ°μ κ³ λ―Όμ μ 리ν githubμμ νμΈν μ μμ΅λλ€ -> Webpack μΌλ‘ Front-Server ꡬμ±νκΈ°
νμ§λ§ μ΄ λ§μ λ μλ²½ν κΈ°μ μ μ μ μλμλ€.
λλ Vanila js λ‘ νλμ μΉμ κ°λ°ν΄λ³Έ κ²½νμ΄ μμκΈ°μ λ§μ½ νλ‘ νΈ κ°λ° νμμ΄ λμμ μμ²ν λ, ν° λμμ μ€ μ μμκ² κ°μλ€.
리μ‘νΈμμλ data fetching μ νλ©΄ stateλ₯Ό λ°κΏμ£Όμ΄ λ λλ§μ μννμ§λ§, λ°λλΌ js μμλ μ§μ document κ°μ²΄λ₯Ό μ΄μ©ν΄μ dom μ μ‘°μν΄μΌ νκ³ , ajax ν΅μ μμλ μ΄λ»κ² λ λλ₯Ό λ°κΏμΌ νλμ§ νμ€ν μ΄ν΄κ° λΆμ‘±νμλ€.
κ°λ¨ν κ²μν μ λλ κ°λ°ν μ μμ΄μ 머리μμΌλ‘λ μ΄λ»κ² ν΄μΌκ² λ€! μΆμ§λ§ λ§μ κ·λͺ¨κ° μλ μ±μ κ°λ°ν λ, λ°μν λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ μμ κ°μ΄ λΆμ‘±νλ€.
μ λ§ λ€νμΈ κ²μ νλ‘ νΈλ₯Ό 맑μ νμμ΄ λ¦¬μ‘νΈ κ²½νμ΄ μλ€κ³ νμ¬ λ¦¬μ‘νΈλ‘ νλ κ²μ μ΄λ»κ² λλ μ견μ λ΄μκ³ , κΈμ μ μΌλ‘ λ°μλ€μ¬μ€μ μ°λ¦¬λ νλ‘ νΈλ₯Ό 리μ‘νΈλ‘ ꡬμ±νκΈ°λ‘ νμλ€.
κ²°κ΅ νμλ€μ μν΄λ₯Ό κ΅¬ν΄ λ¦¬μ‘νΈλ‘ λ³κ²½!
μ§λ λ΄ κ²½νμμλ μ§μ Designκ³Ό Style κ°λ°μ νμμ§λ§, μ΄λ² νλ‘μ νΈμμλ Backend μμ ν΄μΌν μΌλ€μ΄ μ‘°κΈ μμκ³ , λ΄κ° μΈνλΌκΉμ§ ꡬμ±μ νμ΄μΌ νκΈ° λλ¬Έμ λμμΈ μͺ½μ μμ ν μ μμλ€.
λν UIλ₯Ό μ λ¬Έμ μΌλ‘ 곡λΆνλ νμλ€μ΄ μμκΈ°μ React Bootstrapμ μ΄μ©νκΈ°λ‘ νλ€.
λλ Bootstrap μ ν λ²λ μ¬μ©ν΄λ³Έ μ μ΄ μμκΈ°μ νλ‘ νΈλ₯Ό 맑μ νμμ΄ Bootstrap μ λ§μ Έλ³΄λ©° μ°λ¦¬μκ² νμν Chart λ€κ³Ό μ»΄ν¬λνΈλ₯Ό λ°λ‘ λΉΌμ λͺ¨λνλ₯Ό ν΄ μ£Όμλ€.
κ·Έλ¦¬κ³ νλ‘μ νΈ Repository μμ create-react-app
μ μ΄μ©ν΄μ κΈ°λ³Έ Building μ νκ³ , ν΄λΉ μ»΄ν¬λνΈλ€μ κ°μ Έμ μ¬μ©μ νμλ€.
리μ‘νΈμ state κ΄λ¦¬ λꡬ
React μ ν° νΉμ§ λ κ°μ§λ₯Ό μ΄μΌκΈ° νμλ©΄ λ°λ‘ Stateμ Props μ΄λ€.
Propsμ Stateλ μΌλ° Js κ°μ²΄λ‘ μ»΄ν¬λνΈλ₯Ό λ λλ§ν λμ μν₯μ μ£Όλ λ°μ΄ν°λ₯Ό μλ―Ένλ€.
stateλ νλμ μ»΄ν¬λνΈ λ΄λΆμμ μ¬μ©λλ λ³μν λ°μ΄ν°μΈλ°, ν΄λΉ stateλ₯Ό μ΄μ©ν΄μ λμ μΈ λ°μ΄ν°λ₯Ό κ²°μ νκ³ μ»΄ν¬λνΈ UIμ μ½μ ν΄μ λ λλ§νλ€.
μ΄ κ³Όμ μμ stateλ νλμ μ»΄ν¬λνΈ λ΄λΆμ μμΉνμ¬ μ»΄ν¬λνΈ λ λ νΈλ¦¬λ₯Ό μ μκ°ν΄μ μ»΄ν¬λνΈλ₯Ό ꡬμ±ν΄μΌ νλ€.
μ΄λ° νΉμ±μ μλͺ» μ΄μ©νλ€λ©΄ μνλ κ²°κ³Όκ° μ λ λλ§λμ§ μκ² λλλ°, μ΄λ₯Ό μ λλ‘ μ¬μ©νκΈ°λ μ‘°κΈ κΉλ€λ‘λ€.
κ·Έλμ μ΄ λ¬Έμ λ₯Ό ν΄κ²°νλ λ°©λ²μΌλ‘λ λ€μν μ νμ§κ° μμλ€.
- μμ State + Props μ΄μ©νκΈ°
- μ μ State κ΄λ¦¬ λꡬ μ΄μ©νκΈ° (Mobx, Context API, Redux)
μμ State + Props μ΄μ©νκΈ°
μμ stateλ₯Ό μ¬μ©νλ€λ©΄ μ»΄ν¬λνΈ λ λ νΈλ¦¬μ ꡬ쑰λ₯Ό μ νμ νκ³ μ μ ν propsλ‘ λ΄λ €μ€μΌ νλ€.
κ·Έλμ μ½λκ° μμΉ« μλͺ»νλ©΄ μ’ λλ¬μμ§κ±°λ κ°λ μ±μ΄ λλΉ μ§λ€.
μ μ state κ΄λ¦¬ λꡬ μ΄μ©νκΈ°
νμ¬ κ°μΈμ μΈ νλ‘μ νΈμμ νλ‘ νΈμλλ₯Ό reduxμ redux-thunk λ₯Ό μ¬μ©νκ³ μλ€.
νμ€ν μμ stateμ props λ₯Ό μ¬μ©ν λ λ³΄λ€ λ€μνκ³ λ μ¬μ΄ κ°λ°μ΄ κ°λ₯νμ§λ§ νκ²½μ ꡬμ±νκΈ° κΉμ§ μ‘°κΈ μκ°μ΄ 걸리며, 무μλ³΄λ€ μ΄ μκ°μ΄ μμ°λ€.
κ³Όμ° μ°λ¦¬ μλΉμ€μμ Reduxκ° νμν κΉ??
μ λ΅μ No μ΄λ€.
μ¬μ€ λμ Data Fetching λ μκ³ λ¨μ§ μ»΄ν¬λνΈμ Depth λ κΉμ΄λ΄€μ 5κ°? μ λμλ€.
κ·Έλμ Reduxλ κ³ΌκΉν Pass νκ³ μμ stateμ propsμ useState ν μ μ£Όλ‘ μ΄μ©νκΈ°λ‘ νμλ€.
ν΅μ λͺ¨λμ μ ν
λΈλΌμ°μ μμ Ajax λ₯Ό νκΈ° μν΄μλ λ΄κ° μ¬μ©νλ ν΅μ λͺ¨λμ 2κ°μ§ μ΄λ€.
- Fetch API
- Axios
λ λ€ Ajax μ Request λ₯Ό μΆμνν λͺ¨λλ‘ κ°μΈμ μΌλ‘ Axiosλ₯Ό λ λ§μ΄ μ νΈνλ€.
κ·Έ μ΄μ λ λͺ κ°μ§κ° μλλ°,
- Promise μ²λ¦¬κ° μ½λ€
- μ½λκ° κΉλνλ€
- json μ²λ¦¬κ° λ μ½λ€
- κ²½νμ΄ λ λ§λ€ γ γ
κ²°κ΅ Axios λ₯Ό μ΄μ©νκΈ°λ‘ νμκ³ , λ€μκ³Ό κ°μ΄ API λͺ¨λμ ꡬμ±νλ€.
import axios from "axios";
export const SERVER = axios.create({
baseURL: "http://" + process.env.REACT_APP_HOST_IP,
headers: {
"Content-Type": "application/json",
},
});
export const TEST_SERVER = axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-Type": "application/json",
},
});
SERVER.js λΌλ νμΌμ λ§λ€κ³ μμ κ°μ΄ μλ²μ νΈμΆ ipλ₯Ό λ£μ΄μ axios instance λ₯Ό μμ±νλ€.
κ·Έλ¦¬κ³ κ°κ°μ κ΄μ¬μ¬μ λ§κ² λ―Όλ Service.js νμΌμμ axios instance λ₯Ό import νμ¬ μ¬μ©νλ λ°©λ²μ΄λ€.
import { SERVER, TEST_SERVER } from "util/SERVER";
export const fetchAllLog = async () => {
const { data } = await SERVER.get("/api/logs/all");
return data;
};
export const fetchUnknownLog = async () => {
const { data } = await SERVER.get("/api/logs/unknown");
return data;
};
λμμΈ ν¨ν΄μ λμ
λλ λμμΈ ν¨ν΄μ μννΈμ¨μ΄ κ°λ°μ μμ΄μ 맀μ°λ§€μ°λ§€μ° μ€μνλ€κ³ μκ°νλ μ¬λμ΄λ€
κ·Έλμ κ°λ¨νλ€κ³ λ³Ό μ μλ μ΄λ² νλ‘μ νΈμμλ κ°μ₯ λ¨Όμ λμμΈ ν¨ν΄μ κ³ λ―Όνμλ€.
λ΄κ° νλ‘μ νΈμμ κ²½ννλ λμμΈ ν¨ν΄μ ν¬κ² 2κ°μ§μλ€.
- Container-Presenter Pattern
- Atomic Design Pattern
Atomic Design Pattern μ μμκ° λλ μ»΄ν¬λνΈλ₯Ό μ¬μ¬μ©νλ λ°μ νΉνλμ΄ μλλ°, μ°λ¦¬λ μ¬μ€μ Single Page λ‘ μ΄μλκ³ Routing μ‘°μ°¨ νμ§ μκΈ° λλ¬Έμ κ²°κ΅ Container-Presenter Pattern μ μ¬μ©νμλ€.
μμ μ΄μΌκΈ°νλ ν΅μ λͺ¨λκ³Ό Service λ₯Ό Container μμ λ°μμ κ·Έ μλμ Presenter λ€μκ² Props λ‘ μ λ¬ν΄μ£Όκ² λλ€.
μλ μ½λλ μ€μ Log λ₯Ό ν μ΄λΈ νμμΌλ‘ λ λνλ μ»΄ν¬λνΈ μμ μ¬μ©νλ Container μ½λμ΄λ€.
import React, { useEffect, useState } from "react";
import LogTable from "components/presenter/LogTable/index";
import { fetchAllLog } from "service/LogService";
const LogTableContainer = () => {
const [logDatas, setLogDatas] = useState([]);
useEffect(async () => {
const data = await fetchAllLog();
setLogDatas(data);
}, []);
return <LogTable logDatas={logDatas} />;
};
export default LogTableContainer;
λ¨Όμ ν΄λΉ μ»΄ν¬λνΈκ° λΈλΌμ°μ μ λ‘λλλ μκ° API νΈμΆμ μλνκ² νλ €κ³ useEffect
λ΄λΆμμ data fetching μ νλ€.
λ°μμ¨ λ°μ΄ν°λ₯Ό <LogTable>
μ props λ‘ λ겨주면, λ€μκ³Ό κ°μ΄ μ μ ν μμ μ»΄ν¬λνΈλ‘ λ΄λ €μ£Όλ©΄μ μμ°μ€λ½κ² UIλ₯Ό λ λλ§νκ² λλ€.
μ΄λ° κ΅¬μ‘°λ‘ Front End React Application μ ꡬμ±λμ΄ μλ€.
μ¬μ€ μ΄ κ΅¬μ‘°κ°, νλ‘ νΈλ₯Ό 리μ‘νΈλ‘ μ μ ν μ΄μ μ‘°μ°¨κ° νλΉνμ§ μμ μ μλ€.
λν κΈ°μ μ체μ μ¬μ©λ²λ μ¬λ°λ₯΄μ§ μμ λ°©ν₯μΌλ‘ ꡬνλμ΄μμ μ μμ§λ§ λλ¦ 1λ¬μ΄λΌλ 짧μ κΈ°κ°λμ μ μ©νκ³ κ½€λ ꡬ쑰μ μΌλ‘ μ ꡬμ±νμ¬ νμ μ μ§ννμλ€.
νλ‘ νΈμλλ λ¨μν μ·¨λ―Έ μ―€μΌλ‘ μκ°νλ μ§λμ κ²½νλ€μ΄ μ΄λ κ² λΉμ λΌ μ μλ€λ μ¬μ€μ΄ λΏλ―νκ³ , λλ¦ μλμ€λ¬μ λ° γ γ .
λ€μ μκ°μ λ°±μλμ Spring Boot μ λν΄μ μ΄μΌκΈ°ν΄λ³΄λ € νλ€!
λκΈ