본문 바로가기
Web/Node.js

18. MongoDB

by 사라리24 2024. 5. 9.
SMALL

 

1. MongoDB


- NoSQL 데이터베이스 시스템 중 하나로, 문서 기반 데이터 저장 방식을 채택한 오픈소스 DBMS
- 관계형 데이터 베이스와는 달리 스키마가 없다.
- JSON 형식의 BSON(Binary JSON) 문서를 시용하여 데이터를 저장
- 유연하고 확장 가능해서 대량의 데이터를 다루는 대규모 어플리케이션과 웹 서비스에서 주로 사용
- NoSQL 데이터베이스는 관계형 데이터베이스와 다르게 스키마가 고정되어 있지 않아 유동적인 데이터 구조를 다를 수 있다
- 문서 데이터베이스 환경에서 잘 작동 (수평적 확장이 가능 )

 

 

MongoDB: 개발자 데이터 플랫폼

업계 최고의 최신 데이터베이스를 토대로 구축된 개발자 데이터 플랫폼을 사용해 아이디어를 더욱 빠르게 실현하세요. 공통 쿼리 인터페이스와 개발자들이 원하는 데이터 모델을 사용하는 동

www.mongodb.com

 

  • 다운로드(최근에는 하지 않음)

 

 

 

2. MongoDB Atlas


 - MongoDB의 관리형 클라우드 데이터베이스 서비스
 - MongoDB 데이터베이스를 클라우드에서 호스팅하고 관리하는 것을 중심으로 하며,
   개발자 및 기업이 손쉽게 애플리케이션을 빌드하고 배포할 수 있도록 지원

 

 

  • 새로운 branch 생성
  
 
      git checkout -b mongodb
  
 

 

  • 설치
 
 
      npm install monogdb
  
 

 

  • db>database.js
  
      < db > database.js>
 
            // import SQ from 'sequelize'; // 삭제
            import { config } from  '../config.js';
            import MongoDb from 'mongodb'; // 추가

            // 삭제
            // const { host, user, database, password, port } = config.db;

            // export const sequelize = new SQ.Sequelize(database, user, password, {
            //     host,
            //     dialect: 'mysql',
            //     logging: false
            // })
 
            // 추가
            let db;

            export async function connectionDB(){
                return (await MongoDb.MongoClient.connect(config.db.host)).withSession((client)=> db = client.db());
            }
 
 

 

  • .env
 
      < .env >

 
            # DB
            # DB_HOST=127.0.0.1 //삭제
            DB_HOST=mongodb+srv://leesarah721:password@cluster0.lp3pryi.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0  //추가 //비밀번호 넣기
            DB_PORT=3306
            DB_USER=root
            DB_PASSWORD=1234
            DB_DATABASE=kdt

            # JWT
            JWT_SECRET=abcd1234%^&*
            JWT_EXPIRE_SEC=172800

            # BCRYPT
            BCRYPT_SALT_ROUNDS=10

            # SERVER
            PORT=8080
 
  




 

  • app.js
  
      <app.js >

            import express from "express";
            import morgan from "morgan";
            import tweetsRouter from './router/tweets.js';
            import authRouter from './router/auth.js';
            import { config } from './config.js';
            // import { sequelize } from "./db/database.js" //삭제
            import { connectDB } from './db/database.js'; //추가


            const app = express();

            app.use(express.json());
            app.use(morgan("dev"));

            app.use('/tweets', tweetsRouter);  
            app.use('/auth', authRouter);

            app.use((req, res, next) => {
                res.sendStatus(404);
            });

            //DB 연결 테스트

            //1.
            //db.getConnection().then(connection => console.log(connection)); //추가

            //2.
            // sequelize.sync().then(()=>{
            //     app.listen(config.host.port);
            // })

            //3.
            connectDB().then((db) => {
                console.log('몽고DB 연결 성공!')
                app.listen(config.host.port);
            }).catch(console.error);
  
 


 

  • data > auth.js 다 주석처리
  
      < data > auth.js >

            //import SQ from 'sequelize';//삭제
            import MongoDB from 'mongodb'; //추가
            import { sequelize } from '../db/database.js';
            const DataTypes = SQ.DataTypes;
 
  

 

  • data > tweet.js 다 주석처리
 
      <  data > tweet.js  >

   
  
  • 에러남
  • 비밀번호 변경


 

* npm start 연결완료

 


3. MongoDB에 회원가입으로 Data 넣기


 

 

  • db > database.js 
  
      < db > database.js >
  
 
 
            import { config } from  '../config.js';
            import MongoDb from 'mongodb';

            let db;

            export async function connectDB(){
                return (await MongoDb.MongoClient.connect(config.db.host)).then((client)=> db = client.db());
            }
 
 
           //추가
            export function getUsers(){
                return db.collection('users');
            }
 
           //추가
            export function getTweets(){
                return db.collection('tweets');
            }
 
 
db.collection: 몽고DB는 테이블이 없고 컬렉션이 있음, 근데 스키마가 없음, 묶어줌
 (ex) db.collection('Users') => 데이터를 넣을 때 users에 넣겠다

 

  • data > auth.js  다 삭제 후 새로 작성
  
      < data > auth.js  >
 
 
            import MongoDB from 'mongodb';
            import { getUsers } from '../db/database.js';


            const ObjectID = MongoDB.ObjectId;

            // 아이디(username) 중복 검사
            export async function findByUsername(username){
                return getUsers().find({username}).next().then(mapOptionalUser);
            }
            // id 중복 검사
            export async function findById(id){
                return getUsers().find({_id: new ObjectID(id)}).next().then(mapOptionalUser);
            }

            //회원가입
            export async function createUser(user){
                return getUsers().insertOne(user).then((result) => console.log(result.insertedId.toString()))
            }
  
 
 
 
 
            function mapOptionalUser(user){
                return user ? { ...user, id: user._id.toString() } : user;
            }
 
 
 
MongoDB 컬렉션에는 ObjectId 가 무조건 들어감






 

 

  • Postman  확인 (회원가입, 로그인)

 

 

  • MongoDB  확인 (회원가입한 데이터가 데이터베이스 안에 들어감)

 

 

 

 

MongoDB Node Driver - Node.js Driver v6.5

Docs Home → Develop Applications → MongoDB Drivers → Node.js Driver Welcome to the documentation site for the official MongoDB Node.js driver. You can add the driver to your application to work with MongoDB in JavaScript or TypeScript. For more infor

www.mongodb.com

 

 

 


4. MongoDB에 tweets 연결


 

 

  • data > tweet.js
  
      < data > tweet.js>

 
            import MongoDB from 'mongodb';
            import { getTweets, getUsers } from '../db/database.js';
            import * as authRepository from './auth.js';

            const ObjectID = MongoDB.ObjectId;


            // 모든 트윗을 리턴(3)
            export async function getAll() {
                return getTweets().find().sort({ createdAt: -1 }).toArray().then(mapTweets);
            }

            // 해당 아이디에 대한 트윗을 리턴(3)
            export async function getAllByUsername(username){
                return getTweets().find({username}).sort({ createdAt: -1 }).toArray().then(mapTweets);
            }


            // 글번호에 대한 트윗을 리턴(3)
            export async function getById(id){
                return getTweets().find({_id: new ObjectID(id)}).next().then(mapOptionalTweet);
            }

            // 트윗을 작성(3)
            export async function create(text, userId){
                return authRepository.findById(userId).then((user) => getTweets().insertOne({
                    text,
                    userId,
                    username: user.username,
                    url: user.url
                })).then((result) => getById(result.insertedId)).then(mapOptionalTweet);
            }

            // 트윗을 변경(3)
            export async function update(id, text){
                return getTweets().findOneAndUpdate({_id: new ObjectID(id)}, {$set: {text}}, {returnDocument: 'after'}).then((result) => result).then(mapOptionalTweet);
            }


            // 트윗을 삭제(3)
            export async function remove(id){
                return getTweets().deleteOne({_id: new ObjectID(id)});
            }


            function mapTweets(tweets){
                return tweets.map(mapOptionalTweet);
            }

            function mapOptionalTweet(tweet){
                return tweet ? { ...tweet, id: tweet.insertedId } : tweet;
            }
 
  
 
더보기

 

 

 

 

 

 

 

 

 

 

 

 

  • Postman 확인

 

 

 

 

 

 

 

 

  • git-hub에 올리기_MongoDB적용

 

더보기
  • 데이터 insert
 
 
      kdt.users.insertOne({
              "name": "apple",
              "age": 20,
               "gender": "여자" })

 

 

 

  • 여러개 데이터 insert
  
 
         kdt.users.inserOne([
                {"name": "apple","age": 20,"gender": "female"},
                {"name": "banana","age": 30,"gender": "male"},
               {"name": "melon","age": 27,"gender": "male"}
 
         ]) zzzxxcc
 
  
 

단, Compass에서 사용하면 문법 사용할 필요는 없고, 그냥 데이터를 입력 하면 됨

 

 


 

❗ 전체코드

  • controllar 폴더 (동일)
더보기
  • auth.js
 
 
            import * as authRepository from '../data/auth.js';
            import bcrypt from 'bcrypt';
            import jwt from 'jsonwebtoken';
            import { config } from '../config.js';

            //삭제
            //const secretKey = "abcd1234%^&*" ;
            //const jwtExpiresInDays = '2d';
            //const bcryptSaltRounds = 10;

            /*
            문제
            jwt.js를 참고하여 controller/auth.js 에 토큰을 발행하고 login()에 로그인 완료되면 클라이언트에 토큰을 출력하는 프로세스를 만들어보자
            */

            // jwt 토근생성
            function createJwtToken(id){
                return jwt.sign({id}, config.jwt.secretKey, {expiresIn: config.jwt.expiresInSec});
            }

            /*
            문제.
            회원가입시 아이디 중복체크 하기
            단. 중복이라면 409을 리턴
            */

            // 회원가입 함수
            export async function signup(req, res, next){
                const {username, password, name, email, url} = req.body;
                const found = await authRepository.findByUsername(username);
                if(found){
                    return res.status(409).json({message:`${username}이 이미 있습니다`});
                }
                const hashed = await bcrypt.hash(password, config.bcrypt.saltRounds);
                const userId = await authRepository.createUser({username, hashed, name, email, url});
                const token = createJwtToken(userId);
                res.status(201).json({token, username});
            }

            /*
            문제
            controller/auth.js 에서 login()를 bcrypt를 적용하여 로그인 프로세스를 만들어보자
            */
           
            // 로그인하는 함수
            export async function login(req, res, next){
                const {username, password} = req.body;
                // const user = await authRepository.login(username);
                const user = await authRepository.findByUsername(username);
                console.log(user);
                if(!user){
                    return res.status(401).json({message: `아이디를 찾을 수 없음`});
                }
                const isValidpassword = await bcrypt.compareSync(password, user.password);
                if(!isValidpassword){
                    return res.status(401).json({message: `비밀번호가 틀렸음`});
                }
                const token = createJwtToken(user.id);
                res.status(200).json({token, username});
            }

            // export async function verify(req, res, next){
            //     const token = req.header['Token'];
            //     if(token){
            //         res.status(200).json(token);
            //     }
            // }

            //me
            export async function me(req, res, next){
                const user = await authRepository.findById(req.userId);
                console.log(user);
                if(!user){
                    return res.status(404).json({message: `일치하는 사용자가 없음`});
                }
                res.status(200).json({token: req.token, username: user.username});
            }
 
 
  • tweets.js
 
 
            import * as tweetRepository from '../data/tweet.js';

            // 여러 트윗을 가져오는 함수
            export async function getTweets(req, res){
                const username = req.query.username;
                const data = await (username ? tweetRepository.getAllByUsername(username)
                                            : tweetRepository.getAll());
                res.status(200).json(data);
            }

            // 하나의 트윗을 가져오는 함수
            export async function getTweet(req, res, next) {
                const id = req.params.id;
                const tweet = await tweetRepository.getById(id);
                if(tweet){
                    res.status(200).json(tweet);
                }else{
                    res.status(404).json({message: `${id}의 트윗이 없습니다`})
                }
            }

            // 트윗을 생성하는 함수
            export async function createTweet(req, res, next) {
                const { text } = req.body;
                const tweet = await tweetRepository.create(text, req.userId);
                res.status(201).json(tweet);
            }

            // 트윗을 변경하는 함수
            export async function updateTweet(req, res, next) {
                const id = req.params.id;
                const text = req.body.text;
                const tweet = await tweetRepository.update(id, text);
                if(tweet){
                    res.status(201).json(tweet);
                }else{
                    res.status(404).json({message: `${id}의 트윗이 없습니다`})
                }
            }

            // 트윗을 삭제하는 함수
            export async function deleteTweet(req, res, next) {
                const id = req.params.id;
                await tweetRepository.remove(id);
                res.sendStatus(204);
            }
 
 
 

 

 

  • data 폴더
더보기
  • auth.js
 
 
 
            import MongoDB from 'mongodb';
            import { getUsers } from '../db/database.js';

            const ObjectID = MongoDB.ObjectId;

            // 아이디(username) 중복검사
            export async function findByUsername(username){
                return getUsers().find({username}).next().then(mapOptionalUser);
            }

            // id 중복검사
            export async function findById(id){
                return getUsers().find({_id: new ObjectID(id)}).next().then(mapOptionalUser);
            }

            // 회원가입
            export async function createUser(user){
                return getUsers().insertOne(user).then((result) => console.log(result.insertedId.toString()));
            }


            function mapOptionalUser(user){
                return user ? { ...user, id: user._id.toString() } : user;
            }
 
 
  • tweets.js
 
 
 
 
            import MongoDB from 'mongodb';
            import { getTweets, getUsers } from '../db/database.js';
            import * as authRepository from './auth.js';

            const ObjectID = MongoDB.ObjectId;


            // 모든 트윗을 리턴(3)
            export async function getAll() {
                return getTweets().find().sort({ createdAt: -1 }).toArray().then(mapTweets);
            }

            // 해당 아이디에 대한 트윗을 리턴(3)
            export async function getAllByUsername(username){
                return getTweets().find({username}).sort({ createdAt: -1 }).toArray().then(mapTweets);
            }


            // 글번호에 대한 트윗을 리턴(3)
            export async function getById(id){
                return getTweets().find({_id: new ObjectID(id)}).next().then(mapOptionalTweet);
            }

            // 트윗을 작성(3)
            export async function create(text, userId){
                return authRepository.findById(userId).then((user) => getTweets().insertOne({
                    text,
                    userId,
                    username: user.username,
                    url: user.url
                })).then((result) => getById(result.insertedId)).then(mapOptionalTweet);
            }

            // 트윗을 변경(3)
            export async function update(id, text){
                return getTweets().findOneAndUpdate({_id: new ObjectID(id)}, {$set: {text}}, {returnDocument: 'after'}).then((result) => result).then(mapOptionalTweet);
            }


            // 트윗을 삭제(3)
            export async function remove(id){
                return getTweets().deleteOne({_id: new ObjectID(id)});
            }


            function mapTweets(tweets){
                return tweets.map(mapOptionalTweet);
            }

            function mapOptionalTweet(tweet){
                return tweet ? { ...tweet, id: tweet.insertedId } : tweet;
            }
 

 

  •  db 폴더
더보기
  • database.js
 
 
            import { config } from '../config.js';
            import MongoDb from 'mongodb';

            let db;

            export async function connectDB(){
                console.log(config.db.host);
                return MongoDb.MongoClient.connect(config.db.host).then((client) => db = client.db());
            }

            export function getUsers(){
                return db.collection('users');
            }

            export function getTweets(){
                return db.collection('tweets');
            }
 
 

 

  • middleware 폴더 (동일)
더보기
  • auth.js
 
 
            import jwt from 'jsonwebtoken';
            import * as authRepository from '../data/auth.js';

            const AUTH_ERROR = {message: "인증에러"};

            export const isAuth = async (req, res, next) => {
                const authHeader = req.get('Authorization');
                console.log(authHeader);

                if(!(authHeader && authHeader.startsWith('Bearer '))){
                    console.log('에러1');
                    return res.status(401).json(AUTH_ERROR);
                }
                const token = authHeader.split(' ')[1];
               
                jwt.verify(
                    token, 'abcd1234%^&*', async(error, decoded) => {
                        if(error){
                            console.log('에러2');
                            return res.status(401).json(AUTH_ERROR);
                        }
                        const user = await authRepository.findById(decoded.id);
                        if(!user){
                            console.log('에러3');
                            return res.status(401).json(AUTH_ERROR);
                        }
                        req.userId = user.id;
                        next();
                    }
                );
            }
 
  • validator.js
 
 
            import { validationResult } from 'express-validator';

            export const validate = (req, res, next) => {
                const errors = validationResult(req);
                if(errors.isEmpty()){
                    return next();
                }
                return res.status(400).json({message:errors.array()[0].msg})
            }
 

 

  • router 폴더 (동일)
더보기
  • auth.js
 
 
            import express from 'express';
            import { body } from 'express-validator';
            import * as authController from '../controller/auth.js';
            import { validate } from '../middleware/validator.js';
            import { isAuth } from '../middleware/auth.js';

            const router = express.Router();

            const validateLogin = [
                body('username').trim().notEmpty().withMessage('username을 입력하세요'),
                body('password').trim().isLength({min:4}).withMessage('password는 최소 4자 이상 입력하세요'), validate
            ];  
            const validateSignup = [
                ... validateLogin,
                body('name').trim().notEmpty().withMessage('name을 입력하세요'),
                body('email').isEmail().withMessage('이메일 형식을 확인하세요'),
                body('url').isURL().withMessage('URL 형식을 확인하세요'), validate
            ]
            router.post('/signup', validateSignup, authController.signup);

            router.post('/login', authController.login);

            router.get('/me', isAuth, authController.me);

            export default router;
 
  • tweets.js
 
 
            import express from "express";
            import * as tweetController from '../controller/tweet.js';
            import { body } from 'express-validator';
            import { validate } from "../middleware/validator.js";
            import { isAuth } from "../middleware/auth.js"

            const router = express.Router();

            /*
                Post, Put에 text에 대해 빈문자열을 없애고, 최소 3자 이상 입력해야 데이터를 저장하도록 API에 적용
            */
            const validateTweet = [
                body('text').trim().isLength({min: 3}).withMessage('최소 3자 이상 입력'), validate
            ]


            // 해당 아이디에 대한 트윗 가져오기
            // GET
            // http://localhost:8080/tweets?username=:username
            router.get('/', isAuth, tweetController.getTweets);


            // 글번호에 대한 트윗 가져오기
            // GET
            // http://localhost:8080/tweets/:id
            router.get('/:id', isAuth, tweetController.getTweet);


            // 트윗하기
            // POST
            // http://localhost:8080/tweets
            // name, username, text
            // json 형태로 입력 후 추가된 데이터까지 모두 json으로 출력
            router.post('/', validateTweet, isAuth, tweetController.createTweet);


            // 트윗 수정하기
            // PUT
            // http://localhost:8080/tweets/:id
            // id, username, text
            // json 형태로 입력 후 변경된 데이터까지 모두 json으로 출력
            router.put('/:id', validateTweet, isAuth, tweetController.updateTweet);


            // 트윗 삭제하기
            // DELETE
            // http://localhost:8080/tweets/:id
            router.delete('/:id', isAuth, tweetController.deleteTweet);

            export default router;
 
 

 

  • app.js
더보기
 


            import express from "express";
            import morgan from "morgan";
            import tweetsRouter from './router/tweets.js';
            import authRouter from './router/auth.js';
            import { config } from "./config.js";
            import { connectDB } from "./db/database.js";

            const app = express();

            app.use(express.json());
            app.use(morgan("dev"));

            app.use('/tweets', tweetsRouter);  
            app.use('/auth', authRouter);

            app.use((req, res, next) => {
                res.sendStatus(404);
            });

            //DB 연결 테스트

            //1.
            //db.getConnection().then(connection => console.log(connection)); //추가

            //2.
            // sequelize.sync().then(()=>{
            //     app.listen(config.host.port);
            // })

            //3.
            connectDB().then((db) => {
                console.log('몽고DB 연결 성공!')
                app.listen(config.host.port);
            }).catch(console.error);    
 
 
 
  • .env
더보기
 
 
            # DB
            # DB_HOST=127.0.0.1 //삭제
            DB_HOST=mongodb+srv://leesarah721:password@cluster0.lp3pryi.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0  //추가 //비밀번호 넣기
            DB_PORT=3306
            DB_USER=root
            DB_PASSWORD=1234
            DB_DATABASE=kdt

            # JWT
            JWT_SECRET=abcd1234%^&*
            JWT_EXPIRE_SEC=172800

            # BCRYPT
            BCRYPT_SALT_ROUNDS=10

            # SERVER
            PORT=8080
 
 
 

 

  • .ignore
더보기
 
            node_modules/
            .gitignore
            .env
            package-lock.json
            memo.txt
            validation.js
            bcrypt.js
            jwt.js
            client.html
            server.js
            script.sql
 

 

 

  • bycrpt.js (동일)
더보기
 
 
            import * as bcrypt from "bcrypt";

            const password = 'abcd1234';
            const hashed = bcrypt.hashSync(password, 10)
            //hashSync(매개변수, 솔트값) // 솔트값: 숫자가 높을 수록 속도가 느림 // 10이하 추천
            console.log(`password: ${password}, hashed: ${hashed}`);


            const result = bcrypt.compareSync('abcd1234',hashed);
            console.log(result);
   
 
 

 

  • client.html (동일)
더보기
 
 
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>클라이언트</title>
                <script src="https://cdn.socket.io/4.7.5/socket.io.min.js" integrity="sha384-2huaZvOR9iDzHqslqwpR87isEmrfxqyWOF7hr7BY6KG0+hVKLoEXMPUJw3ynWuhO" crossorigin="anonymous"></script>
                <script>
                    const socket = io();

                    function setNickname(){
                        const nickname = document.getElementById('nickname').value;
                        socket.emit('setNickname', nickname);
                    }

                    function sendMessage(){
                        const message = document.getElementById('message').value;
                        socket.emit('message', message);
                    }

                    function addEmoji(emoji){
                        const message = document.getElementById('message');
                        message.value += emoji;
                    }

                    function setChannel(){
                        const channel = document.getElementById('channel').value;
                        socket.emit('setChannel', channel);
                    }

                    // 메세지 수신 이벤트 처리
                    socket.on('setNickname', (message) => {
                        const chatBox = document.getElementById('chatBox');
                        const newMessage = document.createElement('p');
                        newMessage.textContent = message;
                        chatBox.appendChild(newMessage);
                    });

                    socket.on('message', (message) => {
                        console.log(message);
                        const chatBox = document.getElementById('chatBox');
                        const newMessage = document.createElement('p');
                        newMessage.textContent = `${message.sender}: ${message.message}`;
                        chatBox.appendChild(newMessage);
                        document.getElementById('message').value = '';
                    });

                    socket.on('updateChannelList', (channelList) => {
                        const channelListElement = document.getElementById('channelList');
                        channelListElement.innerHTML = '';
                        channelList.forEach((channel) => {
                            const channelItem = document.createElement('li');
                            channelItem.textContent = channel;
                            channelListElement.appendChild(channelItem);
                        });
                    })
                </script>
            </head>
            <body>
                <h2>간단한 채팅</h2>
                <form>
                    <p>닉네임: <input type="text" id="nickname"> <button type="button" onclick="setNickname()">설정</button></p>
                    <p>채널: <input type="text" id="channel"> <button type="button" onclick="setChannel()">입장</button></p>
                    <p><ul id="channelList"></ul></p>
                    <p><input type="text" id="message"> <button type="button" onclick="sendMessage()">보내기</button> <button type="button" onclick="addEmoji('😎')">😎</button> <button type="button" onclick="addEmoji('🎃')">🎃</button> <button type="button" onclick="addEmoji('😛')">😛</button> <button type="button" onclick="addEmoji('😊')">😊</button> <button type="button" onclick="addEmoji('🤣')">🤣</button></p>
                </form>
                <div id="chatBox"></div>
            </body>
            </html>
 
 
  • config.js(동일)
더보기
 
 
 
            import dotenv from 'dotenv';

            dotenv.config();

            function required(key, defaultValue=undefined){
                const value = process.env[key] || defaultValue
                // process.env() : 시스템에 접근 관련한 모듈
                // env 다룰 수 있는 기능이 들어있음
                // 먼저 전달받은 키가 있는지 확인,
                // or 앞의 값이 True로 판별되면 앞의 값이 대입,
                // or 앞의 값이 False로 판별되면 뒤의 값이 대입
                if(value == null){
                    throw new Error(`키 ${key}는 undefined!!`);
                }
                return value;
            }

            //외부에서 가져다 쓸 수 있게 작성
            export const config = {
                jwt: {
                    secretKey: required('JWT_SECRET'),
                    expiresInSec: parseInt(required('JWT_EXPIRES_SEC', 172800))
                },
                bcrypt: {
                    saltRounds: parseInt(required('BCRYPT_SALT_ROUNDS', 10))
                },
                host: {
                    port: parseInt(required('HOST_PORT', 8080))
                },
                db: {
                    host: required('DB_HOST'),
                    user: required('DB_USER'),
                    database: required('DB_DATABASE'),
                    password: required('DB_PASSWORD'),
                    port: required('DB_PORT')
                }
            }
 
 

 

  • jwt.js(동일)
더보기
 
 
            import jwt from 'jsonwebtoken';

            const secret='abcdefg1234%^&*';

            const token = jwt.sign(
                {
                    id:'apple',
                    isAdmin:false
                },
                secret,
                {expiresIn: "1h"} // 얼마만큼 토근이 유지될 것인가
            );

            //expiresIn: "1h"
            //expiresIn: 2 유지되다 에러

            setTimeout(()=>{
                jwt.verify(token,secret,(error,decoded)=>{
                    console.log(error,decoded);
                });
            }, 3000); // 3초마다 찍어주기

            console.log(token);

            // 일단 토큰찍고 4초 뒤에 set timeout에서 토큰, 시크릿 확인해보니 에러
            // (4초 지나서 만료시간 지남 jwt expired)
            // 2초로 바꾸면 decoded 잘 뜸
 
 
 
  • script.sql (동일)
더보기
 
 
            use kdt;

            drop table tweets;

            create table users (
                id int auto_increment primary key,
                username varchar(50) unique not null,
                password varchar(150) not null,
                name varchar(50) not null,
                email varchar(50) not null,
                url varchar(200)
            );


            create table tweets (
                id int auto_increment primary key,
                userId int,
                createdAt datetime default now(),
                text varchar(2000) not null,
                foreign key(userId) references users(id)
            );

            select * from users;
            select * from tweets;

            delete from users where username='apple';
 
  • server.js (동일)
더보기
 
            import express from 'express';
            import http from 'http';
            import { Server } from 'socket.io';
            import path from 'path';
            import { fileURLToPath } from 'url';
            import { channel } from 'diagnostics_channel';

            const app = express();
            const server = http.createServer(app);
            const io = new Server(server);
            const __filename = fileURLToPath(import.meta.url);
            const __dirname = path.dirname(__filename);



            // 정적 파일 서빙
            // localhost:8080/client.html
            app.use(express.static(__dirname));

            const channels = new Set(); //추가

            io.on('connection', (socket) => {
                console.log('사용자가 연결되었습니다');

                let nickname = '';
                let channel = ''; //추가

                // 닉네임 설정
                socket.on('setNickname', (name) => {
                    nickname = name;
                    console.log(`닉네임 설정: ${nickname}`);
                    io.emit('setNickname', `알림: 닉네임 설정됨 ${nickname}`);
                });

                // 메세지 설정
                socket.on('message', (message) => {
                    console.log(`클라이언트: ${nickname} -> ${message}`)
                    io.to(channel).emit('message', {sender: nickname, message})
                });

                //채널 설정 //추가
                socket.on('setChannel', (ch) => {
                    channel = ch;
                    socket.join(channel);
                    channels.add(channel);
                    console.log(`클라이언트: ${nickname}님이 채널 ${channel}에 입장`);
                    io.emit('updateChannelList', Array.from(channels))
                });

                // 소켓 종료
                socket.on('disconnect', () => {
                    console.log(`클라이언트: ${nickname} 접속 종료`)
                });
            });

            server.listen(8080, () => {
                console.log('서버가 8080포트에서 실행중!!');
            })
 

 

  • validation.js(동일)
더보기
 
 
 
 
            import express from 'express';
            import { body, param, validationResult } from "express-validator";

            const app = express();
            app.use(express.json());

            const validate = (req, res, next) => {
                const errors = validationResult(req);
                if(errors.isEmpty()){
                    return next();
                }
                console.log(errors.array());
                return res.status(400).json({message: errors.array()[0].msg});
            }

            app.get('/:email', [param('email').isEmail().withMessage('이메일을 입력하세요!'), validate], (req, res, next) => {
                res.send(':연애편지:');
            });


            //[]: validation 기능을 안에다 쓸 수 있다
            // 메서드 체이닝으로 벨리데이션 쓰기
            // trim: 공백 없애기
            // isLength: 최대최소 설정
            // post: 자료를 bbody로 받음
            // get: param로 받음

            app.post('/users', [
                body('name').trim().isLength({min:2}).withMessage('이름은 두글자 이상으로 입력!'),
                body('age').isInt().withMessage('나이는 숫자로 입력!'),
                body('height').isInt({min:100, max:200}).withMessage('키는 100이상 200이하로 입력하세요!'),
                body('job').notEmpty(),
                validate
            ], (req, res, next) => {
                console.log(req.body);
                res.sendStatus(201);
            })

            app.listen(8080);
 
 

 

 

'Web > Node.js' 카테고리의 다른 글

19. Mongoose  (0) 2024.05.10
17. Sequelize  (0) 2024.05.08
16. ORM  (0) 2024.05.03
15. 환경변수, 웹소켓  (0) 2024.05.03
14. Postman 정리, 아이디 중복체크  (0) 2024.05.02