본문 바로가기
Web/Node.js

16. ORM

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

1. ORM 

  

 

  • ORM (객체 관계 매핑, Object Relational Mapping)
    - 객체 지향 프로그래밍 언어에서 사용되는 객체와 관계형 데이터베이스 간의 불일치를 해결하기 위한 기술
    - 객체 모델과 관계형 데이터베이스의 테이블 간의 매핑을 수행하여 개발자가 SQL 쿼리 대신 객체 지향 코드를 사용할 수 있도록 함
    (데이터 베이스의 모든 쿼리를 객체로 만들어서 실행하는 매개체, Node.js에도 노드로 존재) 

  • ODM(객체 문서 매핑, Object Document Mapping)
    - NoSQL 데이터베이스와 객체 지향 프로그래밍 언어 간의 매핑을 제공하는 기술

    - 주로 문서 지향 데이터베이스(MongoDB)와 함께 사용

    (SQL 문법을 사용하지 않고 자바스크립트, 트리로 데이터를 넣는 방법) 

 

2. Branch  

  

 

  • 현재 작업중인 브랜치 확인(목록확인)
  
        git branch

        * master
  
* 표시: 현재 작업중인 브랜치

 

  • branch  생성하기
 
 
        git branch  [브랜치 이름]
 
  

 

  • Master로 작업하다가 다른 branch 전환하기
  
 
       git switch [브랜치 이름]
       git checkout [브랜치 이름]
 
 
 
- checkout : 있으면 이동, 없으면 생성

 

  • branch 생성과 동시에 전환
 
 
       git checkout -[브랜치 이름]

 

 

        PS C:\Sarr\KDT\Web\Project\Server> git checkout -b mysql
        Switched to a new branch 'mysql'
        PS C:\Sarr\KDT\Web\Project\Server> git branch
          master
        * mysql

 

 

  • mysql 모듈 설치
 
       npm i mysql2
 
 
- sql 문법 사용가능
- table 단위로 처리: table 생성해야 함 : workbench로 이동

 

  • Workbench에서 Table 생성
    (폴더ㅣ server > script.sql 파일 생성)





 


 

3. DB와 연결하기

  

 

  • db > database.js 생성 
  
      < database.js >
 
 
 
            import mysql from 'mysql2';
            import { config } from  '../config.js';

            const pool = mysql.createPool({
                host: config.db.host,
                port: config.db.port,
                user: config.db.user,
                database: config.db.database,
                password: config.db.password
            });

            export const db = pool.promise();
 
 
 

 

  • config.js db 추가
 
      < config.js >

                db: {
                    host: required('DB_HST'),
                    user: required('DB_USER'),
                    database: required('DB_DATABASE'),
                    password: required('DB_PASSWORD'),
                    port: required('DB_PROT')
                }

 

 

  • .env 추가
  
      < .env >

            # DB
            DB_DATABASE=kdt //추가
 
 

 

  • app.js 연결 확인하고 삭제(주석처리)
 
      < app.js  >
 

            import { db } from '.db/database.js'; //추가
 
 
            db.getConnection().then(connection => console.log(connection)); //추가
 
 
 


 

  • npm start 확인

 


4. 회원가입, 중복확인

  

 

  • data > auth.js 변경
 
        < auth.js >
 

            //아이디 (username) 중복검사
            export async function findByUsername(username){
                return db.execute('selet * from users where username = ?', [username]).then
                ((result)=> result);
            }

            //id 중복검사
            export async function findById(id){
                return db.execute('selet * from users where id = ?', [id]).then((result)=> result);
            }

            //회원가입
            export async function createUser(user){
                const {username, password, name, email, url} = user;
                return db.execute('insert into users (username,password, name, email, url) values (?,?,?,?,?)',
                [
username, password, name, email, url]).then((result)=>result);

 
 

 

  • 회원가입, 중복검사 오류수정 
더보기

1. password -> hashed

2. controllar>auth.js 주석처리

3. terminal 확인

 

% 확인) 찍어보기

 

4. data > auth.js 수정

 

5. controlar > auth.js 수정

 

 

!! 회원가입, 중복체크 완료 !!

 

  • Postman 확인

* 회원가입 완료




* 중복검사 + 회원가입

 

  • SQL 확인

 


5. 로그인, 본인확인

  

 

  •  
  • controllar > auth.js 변경
  
      < controllar > auth.js >
 
 
            // 로그인하는 함수
            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});
            }
 
 



 

  • data > auth.js 변경
  
 
      < data > auth.js  >
 
            import { db } from '../db/database.js';


            //아이디 (username) 중복검사
            export async function findByUsername(username){
                return db.execute('select * from users where username = ?', [username]).then((result) => {
                    console.log(result);
                    return result[0][0];
                });
            }

            //id 중복검사
            export async function findById(id){
                return db.execute('select * from users where id = ?', [id]).then((result) => {
                    console.log(result);
                    return result[0][0];
                });
            }

            //회원가입
            export async function createUser(user){
                console.log(user);
                const {username, hashed, name, email, url} = user;
                return db.execute('insert into users (username, password, name, email, url) values (?, ?, ?, ?, ?)', [username, hashed, name, email, url]).then((result) => {
                    console.log(result);    // result[0].insertId
                    return result[0].insertId;
                });
            }

            // //로그인
            // export async function login(username){
            //     return users.find((users) => users.username === username);
            // }
 
 






 

 

 


6. DB와 tweet  연결하기

  

 

  • data > tweet.js
    : 데이터 삭제, 코드 추가
 
 
      < data > tweet.js >
 
 
            import { db } from '../db/database.js';

            const SELECT_JOIN = 'select tw.id, tw.text, tw.createdAt, tw.userId, us.username, us.email, us.url from tweets as tw join users as us on tw.userId = us.id';
            const ORDER_DESC = 'order by tw.createdAt desc';
  
 
 

 

  • data > tweet.js
    : 코드 변경
 
      < data > tweet.js >
 
           

            // 모든 트윗을 리턴
            export async function getAll() {
                return db.execute(`${SELECT_JOIN} ${ORDER_DESC}`).then((result) => {
                    console.log(result);
                    return result;
                });
            }

            // 해당 아이디에 대한 트윗을 리턴
            export async function getAllByUsername(username){
                return db.execute(`${SELECT_JOIN} where username = ? ${ORDER_DESC}`, [username]).then((result) => {
                    console.log(result);
                    return result;
                });
            }

            // 글번호에 대한 트윗을 리턴
            export async function getById(id){
                return db.execute(`${SELECT_JOIN} where tw.id = ? ${ORDER_DESC}`, [id]).then((result) => {
                    console.log(result);
                    return result;
                });
            }

            // 트윗을 작성
            export async function create(text, userId){
                return db.execute('insert into tweets (text, userId) values (?, ?)', [text, userId]).then((result) => {
                    console.log(result);
                    return getById(result[0].insertId);
                });
            }

            // 트윗을 변경
            export async function update(id, text){
                return db.execute('update tweets set text = ? where id = ?', [text, id]).then((result) => {
                    console.log(result);
                    return getById(id);
                });
            }

            // 트윗을 삭제
            export async function remove(id){
                return db.execute('delete from tweets where id = ?', [id]);
            }
 
 

 

  • data > tweet.js  원래 코드

 

  • controllar > auth.js 변경
  
      < controllar > auth.js >

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

       </js >
  
 

* 원래 코드



 

  • Postman으로 확인하기

* 로그인해서 나온 토큰 넣기



* 트윗 생성하기




* 생성한 트윗 확인









* 트윗 변경하기




* 변경한 트윗 확인




* 트윗 삭제하기



 


 

  • git 에 commit하기
더보기

'MYSQL 적용'으로 커밋

 

 

 


 

❗ 전체코드

  • 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 { db } from '../db/database.js';


            //아이디 (username) 중복검사
            export async function findByUsername(username){
                return db.execute('select * from users where username = ?', [username]).then((result) => {
                    console.log(result);
                    return result[0][0];
                });
            }

            //id 중복검사
            export async function findById(id){
                return db.execute('select * from users where id = ?', [id]).then((result) => {
                    console.log(result);
                    return result[0][0];
                });
            }

            //회원가입
            export async function createUser(user){
                console.log(user);
                const {username, hashed, name, email, url} = user;
                return db.execute('insert into users (username, password, name, email, url) values (?, ?, ?, ?, ?)', [username, hashed, name, email, url]).then((result) => {
                    console.log(result);    // result[0].insertId
                    return result[0].insertId;
                });
            }

            // //로그인
            // export async function login(username){
            //     return users.find((users) => users.username === username);
            // }
 
 
 
  • tweets.js
 
 
 
            import { db } from '../db/database.js';

            const SELECT_JOIN = 'select tw.id, tw.text, tw.createdAt, tw.userId, us.username, us.name, us.email, us.url from tweets as tw join users as us on tw.userId = us.id';

            const ORDER_DESC = 'order by tw.createdAt desc';

            // 모든 트윗을 리턴
            export async function getAll() {
                return db.execute(`${SELECT_JOIN} ${ORDER_DESC}`).then((result) => {
                    console.log(result);
                    return result;
                });
            }

            // 해당 아이디에 대한 트윗을 리턴
            export async function getAllByUsername(username){
                return db.execute(`${SELECT_JOIN} where username = ? ${ORDER_DESC}`, [username]).then((result) => {
                    console.log(result);
                    return result;
                });
            }

            // 글번호에 대한 트윗을 리턴
            export async function getById(id){
                return db.execute(`${SELECT_JOIN} where tw.id = ? ${ORDER_DESC}`, [id]).then((result) => {
                    console.log(result);
                    return result;
                });
            }

            // 트윗을 작성
            export async function create(text, userId){
                return db.execute('insert into tweets (text, userId) values (?, ?)', [text, userId]).then((result) => {
                    console.log(result);
                    return getById(result[0].insertId);
                });
            }

            // 트윗을 변경
            export async function update(id, text){
                return db.execute('update tweets set text = ? where id = ?', [text, id]).then((result) => {
                    console.log(result);
                    return getById(id);
                });
            }

            // 트윗을 삭제
            export async function remove(id){
                return db.execute('delete from tweets where id = ?', [id]);
            }



 
 

 

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

            const pool = mysql.createPool({
                host: config.db.host,
                port: config.db.port,
                user: config.db.user,
                database: config.db.database,
                password: config.db.password
            });

            export const db = pool.promise();
 
 

 

 

  • 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 { db } 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.getConnection().then(connection => console.log(connection)); //추가

            app.listen(config.host.port);
 
 
 
  • .env
더보기
 
 
            # DB
            DB_HOST=127.0.0.1
            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' 카테고리의 다른 글

18. MongoDB  (0) 2024.05.09
17. Sequelize  (0) 2024.05.08
15. 환경변수, 웹소켓  (0) 2024.05.03
14. Postman 정리, 아이디 중복체크  (0) 2024.05.02
13. Authentication, bcrypt, JWT  (0) 2024.04.29