본문 바로가기

회고록(TIL&WIL)

TIL 2023.03.14 Node.js 2 (express Project, nodemon, mongoDB)

Node.js

프로젝트 초기화

아래 명령어를 실행하고 나면 maven에서 pom.xml과 비슷한 역할을 하는 package.json파일이 생긴다.

npm init

package.json 를 통한 프로젝트 관리

생성된 파일에 "dependencies" 추가할 수 있다. 필요한 모듈들을 추가 한 후 npm i 하면 해당 파일에 따라 모듈이 추가된다.
이후 npm i mysql 처럼 따로 설치하고 난 뒤에 해당 파일을 확인해보면 dependencies에 추가되어있는 것을 확인 할 수 있다.

{
  "name": "node02",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ejs": "^3.1.9",
    "express" : "^4.18.2",
    "mysql": "^2.18.1"
  }
}

docker mysql

docker run -it --rm -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=mysql \
-e MYSQL_DATABASE=lecture \
-e MYSQL_USER=scott -e MYSQL_PASSWORD=tiger \
--name mysql8 -v dummySql:/var/lib/mysql mysql

// mysql 8.0 이상 사용 시
alter user 'scott'@'%' identified with mysql_native_password by 'tiger';
flush privileges;

프로젝트 구조


src => app.js
view => ejs 파일들
public = > static 파일들

app.js

var express = require('express');
var ejs = require('ejs');
var path = require('path');

// Create Server
const PORT = 3000
var app = express();
// body-parser
app.use(express.json())
app.use(express.urlencoded({extended:false}))


// Set Static Directory
app.use(express.static(path.join(__dirname, './../public')));
// Set View Engine
app.set('views', path.join(__dirname, './../views'));
app.set('view engine', 'ejs');

// DB Connection
var mysql = require('mysql');
var con = mysql.createConnection({
    host: "192.168.99.100",
    user: "scott",
    password: "tiger",
    port: 3306,
    database: "mydb"
});
// var sql = "CREATE DATABASE mydb";
// var sql = "CREATE TABLE IF NOT EXISTS `dept` (`DEPTNO` int(11) DEFAULT NULL,`DNAME` varchar(14) DEFAULT NULL,`LOC` varchar(13) DEFAULT NULL)";
// var sql = "INSERT INTO dept values(3333,'회계팀', '창원')";
con.connect(function(err) {
    if (err) throw err;
    console.log("Connected!");
    // con.query(sql, function (err, result) {
        //     if (err) throw err;
        //     console.log("Database created");
        // });
});


// EJS Views
app.get('/intro', function(req,res){
    res.render('intro');
});
app.get('/dept/', function(req,res){
    var sql = "SELECT * FROM dept";
    con.query(sql, function (err, result, fields) {
        if (err) throw err;
        // console.log(result, fields);
        // result.forEach(function(ele,idx){
        //     console.log(ele.DEPTNO, ele.DNAME, ele.LOC);
        // });
        res.render('dept/list', {"result": result})
    });
});
app.post('/dept/', function(req,res){
    console.log(req.body);
    var sql = "insert into dept values(?,?,?)";
    var values = [req.body.deptno, req.body.dname, req.body.loc];
    con.query(sql, values, function(err, result){
        res.redirect('./');
    });
});
app.get('/dept/add', function(req,res){
    res.render('dept/add');
});


app.listen(PORT);

Select

<table class="table">
  <thead>
    <tr>
      <th>deptno</th>
      <th>dname</th>
      <th>loc</th>
    </tr>
  </thead>
  <tbody>
    <% result.forEach(function(ele, idx){ %>
    <tr>
      <td><%=ele.DEPTNO%></td>
      <td><%=ele.DNAME%></td>
      <td><%=ele.LOC%></td>
    </tr>
    <% });%>
  </tbody>
</table>
<p><a href="/dept/add" class="btn btn-primary btn-block" role="button">입력</a></p>

Insert

<form class="form-signin" action="./" method="post">
  <label for="deptno" class="sr-only">deptno</label>
  <input type="text" id="deptno" name="deptno" class="form-control" placeholder="deptno" required autofocus>
  <label for="dname" class="sr-only">dname</label>
  <input type="text" id="dname" name="dname" class="form-control" placeholder="dname" required>
  <label for="loc" class="sr-only">loc</label>
  <input type="text" id="loc" name="loc" class="form-control" placeholder="loc" required>

  <button class="btn btn-lg btn-primary btn-block" type="submit">입력</button>
</form>

nodemon - 개발 과정에서 서버를 자동으로 리프레쉬 해주는 도구

npm install -g nodemon # 글로벌옵션으로 설치, 의존성이 안붙음

npm install --save-dev nodemon # 개발모드로 설치, 의존성이 붙음
nodemon app.js

이후 package.json에 scripts 부분에 start에 해당하는 코드를 추가하고

"scripts": {
  "start": "nodemon src/app.js",
},

아래 명령어 둘 중 하나를 통해서 서버를 시작시킬 수 있다.

npm run start
npm start

refactoring - router module을 이용해서 app.js 코드 복잡성을 줄이기 위해서 경로에 따라 코드 분리

구조 변경

src/app.js

let express = require('express');
let ejs = require('ejs');
let path = require('path');

// Create Server
const PORT = 3000
let app = express();
// body-parser
app.use(express.json())
app.use(express.urlencoded({extended:false}))

// Set Static Directory
app.use(express.static(path.join(__dirname, './../public')));
// Set View Engine
app.set('views', path.join(__dirname, './../views'));
app.set('view engine', 'ejs');

// EJS Views
app.use('/', require('./routers/')); //index는 생략가능
app.use('/dept', require('./routers/dept'));

app.listen(PORT);

modules/mysqlPool.js - DBCP

// DBCP
const mysql = require('mysql');
const info = {
    connectionLimit : 10,
    host: "192.168.99.100",
    user: "scott",
    password: "tiger",
    port: 3306,
    database: "mydb"
}
    
const pool = mysql.createPool(info);
module.exports=pool;

routes/index.js

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

// 인트로 페이지
router.get('/intro', function(req,res){
    res.render('intro');
});

module.exports=router;

routes/dept.js

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

// DB Connection
// const conn = require('../modules/mysql');
// DBCP
const pool = require('../modules/mysqlPool');

// 리스트 페이지
router.get('/', function(req,res){
    let sql = "SELECT * FROM dept";
    pool.query(sql, function (err, result, fields) {
        if (err) throw err;
        // console.log(result, fields);
        // result.forEach(function(ele,idx){
        //     console.log(ele.DEPTNO, ele.DNAME, ele.LOC);
        // });
        res.render('dept/list', {"result": result})
    });
});
// 입력페이지
router.get('/add', function(req,res){
    res.render('dept/add');
});
// 입력
router.post('/', function(req,res){
    // console.log(req.body);
    let sql = "insert into dept values(?,?,?)";
    let values = [req.body.deptno, req.body.dname, req.body.loc];
    pool.query(sql, values, function(err, result){
        res.redirect('./');
    });
});
// 상세보기
router.get('/:deptno', function(req,res){
    let sql = "select * from dept where deptno=?";
    let values = [req.params.deptno]
    pool.query(sql, values, function(err, result ,fields){
        if(err) return res.render('dept/detail');
        // console.log(result);
        res.render('dept/detail', {dept:result[0]});
    });
});
// 수정
router.post('/:deptno', function(req,res){
    let arr = [req.body.dname, req.body.loc, req.body.deptno];
    let sql = "update dept set dname=?, loc=? where deptno=?";
    pool.query(sql, arr, function(err, result){
        // console.log(err);
        if(err) {
            res.render('dept/detail', {"dept":{DEPTNO:req.body.deptno, DNAME:req.body.dname, LOC:req.body.loc}});
        }
        // console.log(result);
        if(result.changedRows){
            res.redirect('./');
        } else {
            res.render('dept/detail', {"dept":{DEPTNO:req.body.deptno, DNAME:req.body.dname, LOC:req.body.loc}});
        }
    })
});
// 삭제
router.delete('/:deptno', function(req,res){
    let deptno = req.params.deptno;
    let sql = `delete from dept where deptno=${deptno}`;
    pool.query(sql, function(err, result){
        res.status(200).send();
    });
});

module.exports=router;

mongoDB 연동하기

모듈 설치 + 초기화

mongo 버전을 명시해주지 않으면 현재날짜 기준 5버전이 다운로드 되는데 최신버전으로 문법이 바뀌어서 기존 코드와 작동방법이 달라 낮은 버전으로 사용

npm install express ejs mongodb@4.14.0
npm init

프로젝트 구조 생성

app.js

// create server
const express = require('express');
const app = express();


// view template
const ejs = require('ejs');
const path = require('path');
app.set('views', path.join(__dirname,'../views'));
app.set('view engine', 'ejs');
// static file dir
app.use(express.static(path.join(__dirname, '../public')));

// body-parser
app.use(express.urlencoded({extended:false}));

// routing
const rootRouter = require('./routers');
app.use('/', rootRouter);
const deptRouter = require('./routers/dept');
app.use('/dept', deptRouter);

app.listen(3000);

modules/mongodb.js

// mongodb 5.X

// const mongo = require('mongodb');
// const MongoClient = mongo.MongoClient;
// // or as an es module:
// // import { MongoClient } from 'mongodb'

// // Connection URL
// const url = 'mongodb://127.0.0.1:27018';
// const client = new MongoClient(url);

// // Database Name
// const dbName = 'mydb';

// // async - await를 달아줌으로써 동기적 처리
// // async 함수만 await를 가질 수 있다.
// async function main() {
//   // Use connect method to connect to the server
//   await client.connect();
//   const db = client.db(dbName);
//   const collection = db.collection('dept');

//   // the following code examples can be pasted here...
  

//   return 'done.';
// }

// main()
// //   .then(console.log)
// //   .catch(console.error)
// //   .finally(() => client.close());

// mongodb 4.X
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://127.0.0.1:27018/";
// Create DB
// MongoClient.connect(url, function(err, db) {
//   if (err) throw err;
//   console.log("Database created!");
//   db.close();
// });

// Create Collection
// dbo.createCollection("dept", function(err, res) {
//     if (err) throw err;
//     console.log("Collection created!");
//     db.close();
// });

// var myobj = [
//     { deptno: 2222, dname: "물류팀", loc: "대전"},
//     { deptno: 3333, dname: "영업팀", loc: "서울"},
//     { deptno: 4444, dname: "전산팀", loc: "대구"}
//   ];
//   coll.insertMany(myobj, function(err, res) {
//     if (err) throw err;
//     console.log("Number of documents inserted: " + res.insertedCount);
//     db.close();
//   });

module.exports = {MongoClient, url};

routes/indexjs

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

router.get('/', (req,res) => {
    res.render('index');
    // res.send('test');
});

module.exports = router;

routes/dept.js

const express = require('express');
const router = express.Router();
const MongoClient = require('../modules/mongodb').MongoClient;
const url = require('../modules/mongodb').url;
const objectId = require('mongodb').ObjectId;

// 리스트
router.get('/', (req,res) => {
    MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo =  db.db("mydb");
        coll = dbo.collection('dept');
        //Find
        var result = coll.find({});
        result.toArray(function(err, result){
            if (err) throw err;
            console.log(result);
            db.close();
            res.render('dept/list', {result});
        });
    });
});

// 입력
router.get('/add',(req,res) =>{
    res.render('dept/add');
});
router.post('/', (req,res) => {
    MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo =  db.db("mydb");
        coll = dbo.collection('dept');
        // Insert
        var myobj = {"deptno":req.body.deptno, "dname": req.body.dname, "loc":req.body.loc};
        coll.insertOne(myobj, function(err, res) {
            if (err) throw err;
            console.log("1 document inserted");
            db.close();
        });
        res.redirect('./');
    });
});

// 상세보기
router.get('/:id', (req,res)=>{
    let param = req.params.id;
    MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo =  db.db("mydb");
        coll = dbo.collection('dept');
        coll.findOne({_id:objectId(param)}, (err, result)=>{
            if(err) throw err;
            res.render('dept/detail', {dept:result})
            db.close();
        });
    });
});


module.exports = router;