Data Scientist 옌

매일 발전하는 IT문제해결사

국비지원교육 (22.01-22.07)/강의노트

22-06-28(화) 104일차 [Node.js, Team Project] Node.js MySQL insert

옌炎 2022. 6. 28. 22:04
728x90

수업내용


1교시 (09:30-10:20)

  • memo.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://code.jquery.com/jquery-3.2.1.min.js"></script>

<!-- moment 사용 : 날짜 cdn -->
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/locale/ko.js"></script>
-->
<script src="moment.min.js"></script>
<script>

    // 문서 로딩 완료 시
    $(function() {
        var curDate = moment().format('YYYY-MM-DD HH:mm');
        $('#createDate').attr('value', curDate);
    });

    // 파일선택 값이 바뀌면 
    $("#photoInput").change(function() {
        readURL(this);
    });

    // 파일선택한 정보를 이용해 이미지 프리뷰
    function readURL(input) {
        if (input.files && input.files[0]) {
            var reader = new FileReader();

            reader.onload = function (e) {
                $('#photoOutput').attr('src', e.target.result);
            }
            reader.readAsDataURL(input.files[0]);
        }
    }
     
</script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h3>나의 메모</h3>
<br>
<form method="post" enctype="multipart/form-data" action="/process/save">
<table>
    <tr>
        <td><label>작성자</label></td>
        <td><input type="text" name="author" /></td>
    </tr>
    <tr>
        <td><label>작성일시</label></td>
        <td><input type="text" name="createDate" id="createDate"/></td>
    </tr>
    <tr>
        <td><label>내용</label></td>
        <td><textarea name="contents" style="width:12em;height:10em;"></textarea></td>
    </tr>
    <tr>
        <td><label>사진</label></td>
        <td><input type="file" name="photo" id="photoInput" /><br><img src="" id="photoOutput" width="200px" /></td>
    </tr>
</table>
<br>
<input type="submit" value="저장" name=""/>
<input type="button" value="닫기" />
</form> 
</body>
</html>

2교시 (10:30-11:20)

  • app.js
/**
 * 미션 6
 * 
 * 미션 4에 데이터베이스 기능 붙이기
 *
 * MySQL 사용 : memo_table.sql 파일로 테이블 생성 가능
 *
 * Express 사용
 *
 * 1. 웹서버 실행 : 명령프롬프트에서 node app.js 실행
 * 2. 웹페이지 열기 : 웹브라우저에서 http://localhost:3000/public/memo.html 열기
 * 
 * 
 * npm init -y
 * npm i express --save
 * npm i http --save
 * npm i path --save
 * npm i body-parser --save
 * npm i serve-static --save
 * npm i multer --save
 * npm i cors --save
 * npm i mime --save
 * npm i mysql --save
 * 
 *
 * 1. 작성화면과 응답화면으로 구성
 *      작성화면 : 작성자, 작성날짜, 내용
 *                  사진을 선택해서 표시할 수 있도록 구성
 *                  사진 선택 버튼을 클릭하면 PC나 모바일 단말기에서 
 *                  사진을 선택한 후 보여준다
 *      저장, 닫기 버튼 
 * 2. 저장 버튼을 클릭하면 웹 서버로 메모 내용을 보내고 사진도 함께 보낸다.
 *      웹 서버에서는 메모 내용을 확인하고 사진도 업로드한 후 정상적으로 
 *      저장되었다는 응답 메시지를 클라이언트로 보냄
 * 3. 클라이언트에서 응답 메시지를 받으면 응답 화면에 메시지를 보여줌
 *      응답 메시지 아래쪽에 서버에 업로드한 사진을 보여준다.
 */


// Express 기본 모듈 불러오기
// 
var express = require('express');

// http 
var http = require('http');

// POST 방식을  GET 방식으로 받을 수 있게 해준다.
var path = require('path');

// Express의 미들웨어 불러오기
var bodyParser = require('body-parser');
var static = require('serve-static');

// 파일 처리
var fs = require('fs');

// 파일 업로드용 미들웨어
var multer = require('multer');

//클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원
var cors = require('cors');

// mime 모듈
// MIME : 파일 형식
var mime = require('mime');


//===== MySQL 데이터베이스를 사용할 수 있도록 하는 mysql 모듈 불러오기 =====//
var mysql = require('mysql');

//===== MySQL 데이터베이스 연결 설정 =====//
var pool      =    mysql.createPool({
    connectionLimit : 10, 
    host     : 'localhost',
    user     : 'root',
    password : '1234',
    database : 'test',
    debug    :  false
});


// 익스프레스 객체 생성
var app = express();

// 포트 설정
app.set('port', process.env.PORT || 3000);

// body-parser 설정
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
 
// public 폴더를 static으로 오픈
app.use('/public', static(path.join(__dirname, 'public')));
app.use('/uploads', static(path.join(__dirname, 'uploads')));

//클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원
app.use(cors());


//multer 미들웨어 사용 : 미들웨어 사용 순서 중요  body-parser -> multer -> router
// 파일 제한 : 10개, 1G
var storage = multer.diskStorage({
    destination: function (req, file, callback) {
        callback(null, 'uploads')
    },
    filename: function (req, file, callback) {
        var extension = path.extname(file.originalname);
        var basename = path.basename(file.originalname, extension);
        callback(null, basename + Date.now() + extension);
    }
});

var upload = multer({ 
    storage: storage,
    limits: {
        files: 10,
        fileSize: 1024 * 1024 * 1024
    }
});


// 라우터 사용하여 라우팅 함수 등록
var router = express.Router();

// 메모 저장을 위한 라우팅 함수
router.route('/process/save').post(upload.array('photo', 1), function(req, res) {
    console.log('/process/save 호출됨.');
    
    try {
        var paramAuthor = req.body.author;
        var paramContents = req.body.contents;
        var paramCreateDate = req.body.createDate;
        
        console.log('작성자 : ' + paramAuthor);
        console.log('내용 : ' + paramContents);
        console.log('일시 : ' + paramCreateDate);
 
        var files = req.files;
    
        console.dir('#===== 업로드된 첫번째 파일 정보 =====#')
        console.dir(req.files[0]);
        console.dir('#=====#')
        
        // 현재의 파일 정보를 저장할 변수 선언
        var originalname = '',
            filename = '',
            mimetype = '',
            size = 0;
        
        if (Array.isArray(files)) {   // 배열에 들어가 있는 경우 (설정에서 1개의 파일도 배열에 넣게 했음)
            console.log("배열에 들어있는 파일 갯수 : %d", files.length);
            
            for (var index = 0; index < files.length; index++) {
                originalname = files[index].originalname;
                filename = files[index].filename;
                mimetype = files[index].mimetype;
                size = files[index].size;
            }

            console.log('현재 파일 정보 : ' + originalname + ', ' + filename + ', ' + mimetype + ', ' + size);

        } else {
            console.log('업로드된 파일이 배열에 들어가 있지 않습니다.');
        }
        
        
        
        // insertMemo 함수 호출하여 메모 추가
        insertMemo(paramAuthor, paramContents, paramCreateDate, filename, function(err, addedMemo) {
            // 에러 발생 시 - 클라이언트로 에러 전송
            if (err) {
                console.error('메모 저장 중 에러 발생 : ' + err.stack);

                res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
                res.write('<h2>메모 저장 중 에러 발생</h2>');
                res.write('<p>' + err.stack + '</p>');
                res.end();

                return;
            }

            // 결과 객체 있으면 성공 응답 전송
            if (addedMemo) {
                console.dir(addedMemo);

                console.log('inserted ' + addedMemo.affectedRows + ' rows');

                var insertId = addedMemo.insertId;
                console.log('추가한 레코드의 아이디 : ' + insertId);

                res.writeHead(200, {'Content-Type':'text/html;charset=utf8'});
                res.write('<div><p>메모가 저장되었습니다.</p></div>');
                res.write('<img src="/uploads/' + filename + '" width="200px">');
                res.write('<div><input type="button" value="다시 작성" onclick="javascript:history.back()"></div>');
                res.end();
            } else {
                res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
                res.write('<h2>메모 저장 실패</h2>');
                res.end();
            }
        });
          
        
    } catch(err) {
        console.dir(err.stack);
        
        res.writeHead(400, {'Content-Type':'text/html;charset=utf8'});
        res.write('<div><p>메모 저장 시 에러 발생</p></div>');
        res.end();
    }   
        
});


app.use('/', router);



// 메모 추가 함수
var insertMemo = function(author, contents, createDate, filename, callback) {
    console.log('insertMemo 호출됨 : ' + author + ', ' + contents + ', ' + createDate + ', ' + filename);
    
    // 커넥션 풀에서 연결 객체를 가져옴
    pool.getConnection(function(err, conn) {
        if (err) {
            if (conn) {
                conn.release();  // 반드시 해제해야 함
            }
            
            callback(err, null);
            return;
        }   
        console.log('데이터베이스 연결 스레드 아이디 : ' + conn.threadId);

        // 데이터를 객체로 만듦
        var data = {author:author, contents:contents, createDate:createDate, filename:filename};
        
        // SQL 문을 실행함
        var exec = conn.query('insert into memo set ?', data, function(err, result) {
            conn.release();  // 반드시 해제해야 함
            console.log('실행 대상 SQL : ' + exec.sql);
            
            if (err) {
                console.log('SQL 실행 시 에러 발생함.');
                console.dir(err);
                
                callback(err, null);
                
                return;
            }
            
            callback(null, result);
            
        });
        
        conn.on('error', function(err) {      
              console.log('데이터베이스 연결 시 에러 발생함.');
              console.dir(err);
              
              callback(err, null);
        });
    });
    
}



// 웹서버 시작
var server = http.createServer(app).listen(app.get('port'), function(){
  console.log('웹 서버 시작됨 -> %s, %s', server.address().address, server.address().port);
});

3교시 (11:30-12:20)

  • 위의 app.js 계속 설명 및 한글 깨지는 것 인코딩 변경 방법 찾기
  • 프로젝트 진행

4교시 (12:30-13:20)

  • 프로젝트 진행

5교시 (14:30-15:20)

  • 프로젝트 진행

6교시 (15:30-16:20)

  • 프로젝트 진행

7교시 (16:30-17:20)

  • 프로젝트 진행

8교시 (17:30-18:30)

  • 프로젝트 진행

Notes


728x90