와이어프레임
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에 모듈이름과 버전을 추가함
#!/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);
}
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);
@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;
}
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;
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;
<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>
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>
<div class="row my-5">
<div class="col">
<hr>
<h5 class="text-center"></h5>
Copyright 2023.한빛출판사 all rights reserved.
</div>
</div>
<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>
<div class="row my-5">
<div class="col">
Home페이지
</div>
</div>
<!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>
/*
웹 애플리케이션을 위한 기본적인 설정을 가지고 있다
모듈을 로딩하고 템플릿 엔진을 설정하여 라우터 설정함
파일 상단에는 사용할 모듈을 로딩하는 코드가 작성됨
외부 모듈을 해당 파일에서 사용하고 싶다면 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;
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);