(31)-23.11.06[JS]

DANA·2023년 11월 6일

KDT-구디아카데미

목록 보기
31/56

와이어프레임

node js 기반에서 할 때는
js 패키지 필요
npm init -y

express generator 통해서 하나 만들었고
로그인 화면 구현

환경설정

전제조건 -NodeJS 설치되었다는 가정에서

노드환경 구성하기
익스프레스 프로젝트를 자동으로 생성해주는 express-generator 모듈을 설치
익스프레스 노드 기반에서 웹 어플리케이션 개발을 지원하는 프레임워크이다

npm install express-generator -g 엔터
프로젝트 생성할 땐
express -e 프로젝트명(myBook)

npm install [모듈명] -g 엔터
g옵션은 모듈을 전역적으로 설치할 때 사용함
특정프로젝트가 아닌 전체 프로젝트에서 공통으로 사용 가능함

npm install [모듈명] -save
현재 작업중인 프로젝트에 모듈을 설치할 때 사용하는 방식이다
-- 옵션으로 현재 플젝의 package.json에 모듈이름과 버전을 추가함

1. bin

www

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('mybook:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

2. public

javascripts

firebase.js

import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.1/firebase-app.js";

const firebaseConfig = {
   apiKey: "AIzaSyD1umOnWWMkZvIRvhEPIidtaNRwTsoFw40",
   authDomain: "gd20230918-5b0a0.firebaseapp.com",
   projectId: "gd20230918-5b0a0",
   storageBucket: "gd20230918-5b0a0.appspot.com",
   messagingSenderId: "615965924774",
   appId: "1:615965924774:web:d94bfca93853c43c3fc367"
 };

 // Initialize Firebase
 export const app = initializeApp(firebaseConfig);

stylesheets

style.css

@import url('https://fonts.googleapis.com/css2?family=Black+Han+Sans&family=Gasoek+One&family=Nanum+Brush+Script&display=swap');

* {
  font-family: 'Gasoek One', sans-serif;
  font-size: 25px;
}

a {
  color: white;
}

3. routes

index.js

var express = require('express'); // 외부 프레임워크 가져올 때 사용하는 예약어(require)
var router = express.Router(); // 페이지 전환

/* GET home page. 
express가 Restful API를 지원해서 웹 서비스를 제공할 수 있게 해준다(서블릿, JSP)
router는 페이지 전환 해주는 API로 여기서 화면에 대한 전환 처리 이벤트
*/
router.get('/', function(req, res, next) {
  res.render('index', { title: '도서관리시스템', pageName:"home.ejs" });
});
router.get('/login', function(req, res, next) {
  res.render('index', { title: '로그인', pageName:"auth/login.ejs"});
});

module.exports = router;

users.js

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

4. views

4-1.auth

login.ejs

<div class="row my-5 justify-content-center">
  <div class="col-8 col-md-6 col-lg-4">
    <h3 class="text-center mb-5">로그인</h3>
    <form name="frm" method="post">
      <div class="input-group my-2">
        <div class="input-group-text">이 메 일</div>
        <input class="form-control" name="email" value="tomato@hot.com" />
      </div>
      <div class="input-group">
        <div class="input-group-text">비밀번호</div>
        <input
          class="form-control"
          name="password"
          type="password"
          value="12345678"
        />
      </div>
      <div class="my-3">
        <!--
          <input type=button> or <button> 기본적으로 submit 속성이 내장됨
        -->
        <button class="btn btn-primary w-100">로그인</button>
      </div>
      <div class="text-end mt-3"><a href="/users/join">회원가입</a></div>
    </form>
  </div>
</div>
<script type="module">
  import { app } from "/javascripts/firebase.js";
  import { getAuth, signInWithEmailAndPassword } from "https://www.gstatic.com/firebasejs/9.22.1/firebase-auth.js"
  const auth = getAuth(app);
  console.log(auth);

  // 로그인 버튼을 눌렀을 때
  // submit 이슈 - submit 이벤트를 처리할 때 캡쳐링으로 인한 이벤트 전이가 발생함 - 방어해야함
  $(frm).on("submit", function(e){
    console.log('로그인버튼 클릭');
    e.preventDefault();
    // 사용자가 화면에 입력한 이메일 주소 담기
    let email = $(frm.email).val();
    // 사용자가 화면에 입력한 비번 담기
    let password = $(frm.password).val();
    console.log(`${email} ${password}`);
    
    // https://firebase.google.com/docs/auth/web/start?hl=ko&authuser=0
    // 기존 사용자가 자신의 이메일 주소와 비밀번호를 사용해 로그인할 수 있는 양식을 만듭니다. 
    // 사용자가 양식을 작성하면 signInWithEmailAndPassword 메서드를 호출합니다.
    signInWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    console.log(userCredential); // [object, Object]
    // Signed in 
    const user = userCredential.user;
    // JSON.stringify(user) 유저 정보를 감싸줌 
    console.log(`user ===> ${JSON.stringify(user)}`); // [object,Object] - JSON.parse(): 이걸 쓰면 JSON 형식을 Array로 바꿔준다
    console.log(`uid ====> ${user.uid}`);
    console.log(`email ====> ${user.email}`);
    localStorage.setItem("uid",`${user.uid}`)
    localStorage.setItem("email",`${user.email}`)
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
  });

  })

</script>

error.ejs

<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>

footer.ejs

<div class="row my-5">
  <div class="col">
    <hr>
    <h5 class="text-center"></h5>
    Copyright 2023.한빛출판사 all rights reserved.
  </div>
</div>

header.ejs

<nav class="navbar navbar-expand-lg navbar-light bg-primary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">한빛미디어</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">게시판</a>
        </li>
      </ul>
      <div class="d-flex" >
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item" id="login">
            <a class="nav-link active" aria-current="page" href="/login">로그인</a>
          </li>
        </ul>
      </div>
    </div>
  </div>
</nav>

home.ejs

<div class="row my-5">
  <div class="col">
    Home페이지
  </div>
</div>

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title>한빛출판사</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
  </head>
  <body>
    <div class="container">
      <%-include("header.ejs")%>
      <%-include(pageName)%>
      <%-include("footer.ejs")%>
    </div>
  </body>
</html>

app.js

/* 
웹 애플리케이션을 위한 기본적인 설정을 가지고 있다
모듈을 로딩하고 템플릿 엔진을 설정하여 라우터 설정함
파일 상단에는 사용할 모듈을 로딩하는 코드가 작성됨
외부 모듈을 해당 파일에서 사용하고 싶다면 require() 함수를 호출해야 함
*/
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
// 라우트 코드를 로딩하는 코드임. require()함수를 사용하며
// 로딩한 라우트 함수들을 지정된 변수로 사용할 수 있게 해줌
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// express객체를 app변수로 선언함
var app = express();

// view engine setup
// 익스프레스에서 사용할 템플릿 엔진을 설정하는 코드임
// __dirname은 현재 디렉토리를 의미하며 path.join()함수는 경로를 연결하는 기능을 함
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs'); // 템플릿엔진의 종류
// 파라미터에 지정된 인자를 실행하는 함수임
// 여기서는 각각의 모듈을 사용하도록 설정함
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// 라우트를 설정하는 코드임. 여기서 라우트는 url 경로의 뒷부분을 의미함
// '/'와 관련된 라우트는 routes 폴더의 index 파일에 설정된 라우트 함수를 통해 처리됨
app.use('/', indexRouter);
//  '/users'와 관련된 라우트는 users 파일에 작성된 라우트 함수를 통해 처리됨 - MyPage, 대시보드, 장바구니
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

index.js

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

// respond with "hello world" when a GET request is made to the homepage
app.get('/', function(req, res) {
  res.send('hello world');
});

app.listen(5000);

0개의 댓글