Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

꼬물꼬물 개발자

ORM Framework 본문

백엔드 개발

ORM Framework

한고운 2023. 12. 28. 17:03

1. Sequelize  설치

> npm i sequelize mysql2

> npm i -g sequelize-cli   (한번만)

> sequelize init

 

config

migrations

models

seeders

 

2. MySQL DB 스키마 생성

SCHEMAS 탭에서 우측마우스 클릭 Create schemas 선택

-Name 입력

-utf8mb4 / utf8mb4_unicode_ci 선택

 

-> CREATE SCHEMA `gowoon_chat` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ;

 

3. dotenv 설정 및 DB 연결

.env 파일 생성

> npm i dotenv


# 포트설정
PORT=3001  #개발환경 포트 : bin/www  process.env.PORT
WAS_PORT=3000  #실제서비스 포트
NODE_ENV=development  # models/index   process.env.NODE_ENV

# 시크릿키
JWT_SECRET=gowoon427520
COOKIE_SECRET=gowoon427520
MYSQL_AES_KEY=AFDKFKDWYIRDFDFDNCGMFKDHXTPEREF!MDLLJFDS$

# DB환경설정
# development
DB_USER = root
DB_PASS = 427520
DB_NAME =gowoon_chat
DB_HOST = 127.0.0.1
DB_PORT = 3306
# test
TEST_DB_USER = root
TEST_DB_PASS = 427520
TEST_DB_NAME = modu_chat
TEST_DB_HOST = 127.0.0.1
TEST_DB_PORT = 3306
# production
PRO_DB_USER = root
PRO_DB_PASS = 427520
PRO_DB_NAME = modu_chat
PRO_DB_HOST = 127.0.0.1
PRO_DB_PORT = 3306

#AWS S3 스토리지 연결정보
S3_BUCKET=hangowoon-bucket
S3_ACCESS_KEY_ID=AKIAYECRYAMHR5ZPV5ES
S3_ACCESS_SECRET_KEY=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

 

app.js에서 추가 설정

//dotenv 어플리케이션 환경설정관리 팩키지 참조 및 구성하기
require('dotenv').config();

 

 

1) config.json 파일 수정

"development": {
    "username": "root",
    "password": "******",
    "database": "gowoon_chat",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },

 

index.js에서 적용

//DB연결 환경설정정보 변경처리//관련정보 수정
//const config = require('../config/config.js')[env];
const config = require(path.join(__dirname,'..','config','config.json'))[env];

 

 

2) config.js 파일 생성

module.exports = {
    "development":{
        "username": process.env.DB_USER,
        "password": process.env.DB_PASS,
        "database": process.env.DB_NAME,
        "host": process.env.DB_HOST,
        "port": Number(process.env.DB_PORT),
        "dialect": "mysql",
        "timezone": "+09:00"
    },
    "test": {
        "username": process.env.TEST_DB_USER,
        "password": process.env.TEST_DB_PASS,
        "database": process.env.TEST_DB_NAME,
        "host": process.env.TEST_DB_HOST,
        "port": Number(process.env.TEST_DB_PORT),
        "dialect": "mysql"
    },
    "production": {
        "username": process.env.PRO_DB_USER,
        "password": process.env.PRO_DB_PASS,
        "database": process.env.PRO_DB_NAME,
        "host": process.env.PRO_DB_HOST,
        "port": Number(process.env.PRO_DB_PORT),
        "dialect": "mysql"
    }
}

 

index.js에서 적용

//DB연결 환경설정정보 변경처리//관련정보 수정
const config = require('../config/config.js')[env];
//const config = require(path.join(__dirname,'..','config','config.json'))[env];

 

4. Model 환경 설정

models /  index.js 내용 작성

const path = require('path');
const Sequelize = require('sequelize');

//개발모드 환경설정
const env = process.env.NODE_ENV || 'development';

//DB연결 환경설정정보 변경처리//관련정보 수정
const config = require(path.join(__dirname,'..','config','config.json'))[env];

//데이터 베이스 객체
const db= {};

//DB연결정보로 시퀄라이즈 ORM 객체 생성
const sequelize = new Sequelize(config.database,config.username,config.password,config);

//DB 처리 객체에 시퀄라이즈 정보 맵핑처리
//이후 DB객체를 통해 데이터 관리가능해짐
db.sequelize = sequelize; //DB연결정보를 포함한 DB제어 객체속성(CRUD)
db.Sequelize = Sequelize; //Sequelize팩키지에서 제공하는 각종 데이터 타입 및 관련 객체정보를 제공함


//회원모델 모듈파일 참조하고 db속성정의하기
//db.Member = require('./member.js')(sequelize,Sequelize);

//db객체 외부로 노출하기
module.exports = db;

 

app.js 추가 설정

//// ORM 기반 DB 연결 정보 참조하기 / DB객체 안에 Sequelize 불러옴
var sequelize = require('./models/index').sequelize;
 

var app = express();


//// mysql과 자동연결처리 및 모델기반 물리 테이블 생성처리제공
sequelize.sync();

 

 

5. MVC 패턴 : Model

models / article.js 생성

module.exports = function(sequelize, DataTypes){

    return sequelize.define('article',
    {
        article_id: {
            type: DataTypes.INTEGER,
            autoIncrement: true,
            primaryKey: true,
            allowNull: false,
            comment: '게시글고유번호',
        },
        board_type_code: {
            type: DataTypes.INTEGER,
            allowNull: false,
            comment: '게시판고유번호 1:공지사항게시판,2:일반사용자 게시판',
        },
        title: {
          type: DataTypes.STRING(200),
          allowNull: false,
          comment: '글제목',
        },
        article_type_code: {
            type: DataTypes.INTEGER,
            allowNull: false,
            comment: '게시글유형코드 0:일반게시글 1:고정게시글',
        },
        contents: {
            type: DataTypes.TEXT,
            allowNull: true,
            comment: '글내용',
        },
        view_count: {
            type: DataTypes.INTEGER,
            allowNull: false,
            comment: '조회수',
        },
        ip_address: {
            type: DataTypes.STRING(50),
            allowNull: false,
            comment: '작성자IP주소',
        },
        is_display_code: {
            type: DataTypes.TINYINT,
            allowNull: false,
            comment: '게시여부 0:게시안함 1:게시함',
        },
        reg_date: {
            type: DataTypes.DATE,
            allowNull: false,
            comment: '등록일시',
        },
        reg_member_id: {
            type: DataTypes.INTEGER,
            allowNull: false,
            comment: '등록자고유번호',
        },
        edit_date: {
            type: DataTypes.DATE,
            allowNull: true,
            comment: '수정일시',
        },
        edit_member_id: {
            type: DataTypes.INTEGER,
            allowNull: true,
            comment: '수정자고유번호',
        }

    },
    {
        sequelize,
        tableName: 'article', // 기본 테이블명 옵션이 복수형이 아닌 여기 지정한 테이블명으로 생성됨
        timestamps: false,
        comment: '게시글정보',
        indexes: [
            {
                name: 'PRIMARY',
                unique: true,
                using: 'BTREE',
                fields: [{ name: 'article_id' }], // 여러개의 컬럼이 프라이머리키인경우(복합키){}추가하여 설정가능
            },
        ],
       
    });

}

 

models / index.js 추가 설정

//회원모델 모듈파일 참조하고 db속성정의하기
db.Article = require('./article.js')(sequelize,Sequelize);

 

6. MVC 패턴 : Controller (Router)

 라우팅 구현

7. MVC 패턴 : View

뷰 구현

8. C/R/U/D ORM DB 프로그래밍 

1) ORM db 객체 선언

routes/ article.js  

// ORM DB객체 참조
var db = require('../models/index');

 

2) 게시글 생성하기

 let registedArticle = await db.Article.create(article);

 

routes/ article.js 

//신규 목록 페이지 호출
//http://localhost:3001/article/create
router.get('/create',async(req,res,next)=>{
    res.render('article/create');
});

//신규 목록 작성 완료 후 목폭 페이지 이동처리
//http://localhost:3001/article/create
router.post('/create',async(req,res,next)=>{

    // 작성 목록 추출
    // view 파일에서 추출 데이터 확인
    let title = req.body.title;
    let contents = req.body.contents;
    let articleTypeCode = req.body.articleTypeCode;
    let isDisplayCode = req.body.isDisplayCode;


    // DB 테이블에 저장할 json 단일데이터 구조 정의
    // 속성명은 데이터 모델(models/article.js)의 속성명과 동일
    let article ={
        board_type_code:2,
        title,
        article_type_code:articleTypeCode,
        contents,
        view_count:0,
        ip_address:"111,111,111,111",
        is_display_code:isDisplayCode,
        reg_date:Date.now(),
        reg_member_id:0,
        edit_date:Date.now(),
        edit_member_id:0
    }

    // 신규 게시글 정보가 등록
    // create()메소드는 등록된 db의 데이터를 반환
    let registedArticle = await db.Article.create(article);


    // 작성 환료 후 목록 페이지 이동
     res.redirect('/article/list');
});

 

3) 전체 게시글 목록 불러오기

let article = await db.Article.findAll();

 

routes/ article.js 

//게시글 목폭 페이지 호출
//http://localhost:3001/article/list
router.get('/list',async(req,res,next)=>{

    // article 테이블의 모든 게시글 목록을 조회해옴
    let article = await db.Article.findAll();

    // 조회결과 모든 게시글 데이터를 뷰에 전달
    res.render('article/list',{ articles });
});

 

4) 생성된 게시글 뷰에 연결하기

view/ article.ejs  

<tbody class="hoverTblBody">

                                            <% for(var i =0;i < articles.length;i++){ %>
                                                <tr>
                                                    <td><%=articles.length-i%></td>
                                                    <td><a href="/article/modify/<%=articles[i].article_id%>"><%=articles[i].title%></a></td>
                                                    <td>

                                                        <% if(articles[i].article_type_code == 0){%>
                                                            일반 게시글
                                                        <%} else {%>
                                                            고정 게시글
                                                        <%} %>

                                                    </td>
                                                    <td><%=articles[i].view_count%></td>
                                                    <td><%=articles[i].ip_address%></td>
                                                    <td>

                                                        <% if(articles[i].is_display_code == 1){%>
                                                            게시함
                                                        <%} else {%>
                                                            게시안함
                                                        <%} %>

                                                    </td>
                                                    <td><%=moment(articles[i].edit_date).format('YYYY-MM-DD HH:mm:ss')%></td>
                                                </tr>
                                           
                                            <% } %>

                                        </tbody>

 

 

***날짜 패키지 추가 설치***

> npm i moment

 

moment 패키지 참조하기

routes / article.js

// 날짜 변환 패키지 참조
var moment = require('moment');

 

moment  속성 전달하기

routes / article.js

//게시글 목폭 페이지 호출
//http://localhost:3001/article/list
router.get('/list',async(req,res,next)=>{

    // article 테이블의 모든 게시글 목록을 조회해옴
    let articles = await db.Article.findAll();

    // 조회결과 모든 게시글 데이터를 뷰에 전달
    res.render('article/list',{ articles,moment });
});

 

5) 단일게시글 수정하기

 

라우터 설정

단일게시글 불러오기

let article = await db.Article.findOne({
        where:{article_id : articleId }
    });

 

routes / article.js

//수정 목록 페이지 호출
//http://localhost:3001/article/modify/1
router.get('/modify/:aid',async(req,res,next)=>{

    // 게시글 고유번호 추출
    let articleId = req.params.aid;

    // 게시글 고유번호를 기준으로 단일 게시글 정보 조회
    let article = await db.Article.findOne({
        where:{article_id : articleId }
    });

    // db데이터 받아서 뷰에 전달
    res.render('article/modify',{ article, moment });
});

 

뷰 설정 

단일게시글 불러오기

view/ article/ modify.ejs

<form action="/article/modify/:aid" method="post" id="articleCreateForm">
        <div class="ibox-content m-b-sm border-bottom">

            <!-- 1번째 열 -->
            <div class="row">
                <div class="col-sm-12">
                    <div class="form-group">
                        <label class="control-label">게시글 제목</label>
                        <input type="text" name="title" id="title" class="form-control" value="<%=article.title%>">
                    </div>
                </div>
            </div>


            <!-- 2번째 열 -->
            <div class="row">
                <div class="col-sm-12">
                    <div class="form-group">
                        <label class="control-label">글내용</label>
                        <textarea class="form-control" name="contents" id="contents" rows="10" cols="5"><%=article.contents%></textarea>
                    </div>
                </div>
            </div>


            <!-- 3번째 열 -->
            <div class="row">
                <div class="col-sm-4">
                    <div class="form-group">
                        <label class="control-label">게시글유형</label>
                        <select name="articleTypeCode" id="articleTypeCode" class="form-control">
                            <option value="0" <% if(article.article_type_code == 0){%> selected<%} %> >일반 게시글</option>
                            <option value="1" <% if(article.article_type_code == 1){%> selected<%} %> >고정 게시글</option>
                        </select>
                    </div>
                </div>
                <div class="col-sm-4">
                    <div class="form-group">
                        <label class="control-label">게시여부</label>
                        <select name="isDisplayCode" id="isDisplayCode" class="form-control">
                            <option value="0" <% if(article.is_display_code == 0){%> selected<%} %> >게시안함</option>
                            <option value="1" <% if(article.is_display_code == 1){%> selected<%} %> >게시함</option>
                        </select>
                    </div>
                </div>
                <div class="col-sm-4">
                    <div class="form-group">
                        <label class="control-label">작성일</label>
                        <input type="text" class="form-control" disabled value="<%=moment(article.edit_date).format('YYYY-MM-DD HH:mm:ss')%>">
                    </div>
                </div>
            </div>


            <div class="text-center">
                <button type="submit" class="btn btn-primary">저장</button>
                <a href="/article/list" class="btn btn-info">목록</a>
                <a href="#" class="btn btn-danger">삭제</a>
            </div>

        </div>
    </form>

 

라우터 설정

단일게시글 수정하기

let updatedCnt = await db.Article.update(updateArticle,{
        where: {article_id:articleId}
    });

 

routes / article.js

// 수정 목록 작성 완료 후 목록 페이지 이동 처리
//http://localhost:3001/article/modify/1
router.post('/modify/:aid',async(req,res,next)=>{

    // 게시글 고유번호 추출
    let articleId = req.params.aid;

    // 수정할 데이터 변수 할당
    let title = req.body.title;
    let contents = req.body.contents;
    let articleTypeCode = req.body.articleTypeCode;
    let isDisplayCode = req.body.isDisplayCode;

    // 수정하고자 하는 단일 데이터 정의
    let updateArticle = {
        title,
        article_type_code:articleTypeCode,
        contents,
        ip_address:"222.222.222.222",
        is_display_code:isDisplayCode,
        edit_date:Date.now(),
        edit_member_id:0,
    }

    //단일 게시글 정보 수정처리 ORM
    let updatedCnt = await db.Article.update(updateArticle,{
        where: {article_id:articleId}
    });


    //수정 완료 후 목록 페이지 이동
    res.redirect('/article/list');
});

 

6) 단일게시글 삭제하기

 

삭제 버튼 뷰 설정

            <div class="text-center">
                <button type="submit" class="btn btn-primary">저장</button>
                <a href="/article/list" class="btn btn-info">목록</a>
                <a href="#" id="btnDelete" class="btn btn-danger">삭제</a>
                <input type="hidden" id="articleId" value="<%=article.article_id%>"/>
            </div>

 

삭제버튼 스크립트 설정

<script>

    $("#btnDelete").click(function(){
        if(confirm("해당 게시글을 삭제하시겠습니까?")){
            // 확인 팝업내 확인 버튼을 누르면 하기 코드가 실행
            // 취소를 투르면 하기 콛를 건너뜀
            location.href="/article/delete?aid="+$("#articleId").val();
        }
    });
</script>

 

삭제 라우터 설정

// 목록 삭제 후 목록 페이지 이동 처리
router.get('/delete',async(req,res,next)=>{

    // 삭제 고유번호 추출
    let articleId = req.query.aid;

    // DB 삭제 처리
    let deletedCnt = await db.Article.destroy({
        where:{article_id:articleId}
    });

    // 삭제 완료 후 목록 페이지로 이동
    res.redirect('/article/list');
});

 

'백엔드 개발' 카테고리의 다른 글

JWT 토큰 기반 사용자 인증 프로세스  (0) 2024.01.16
주요 C/R/U/D ORM DB프로그래밍  (0) 2023.12.29
EJS 주요 문법 정리  (1) 2023.12.22
라우팅 구현 - 회원가입, 로그인  (0) 2023.12.17
라우팅 프로세스  (1) 2023.12.17